Commit 3980f7fc authored by Tom Lane's avatar Tom Lane

Implement getpeereid() as a src/port compatibility function.

This unifies a bunch of ugly #ifdef's in one place.  Per discussion,
we only need this where HAVE_UNIX_SOCKETS, so no need to cover Windows.

Marko Kreen, some adjustment by Tom Lane
parent 0c99d41e
...@@ -18852,8 +18852,7 @@ fi ...@@ -18852,8 +18852,7 @@ fi
for ac_func in cbrt dlopen fcvt fdatasync getifaddrs getpeerucred getrlimit memmove poll pstat readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l
for ac_func in cbrt dlopen fcvt fdatasync getifaddrs getpeereid getpeerucred getrlimit memmove poll pstat readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l
do do
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
...@@ -20424,7 +20423,8 @@ LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` ...@@ -20424,7 +20423,8 @@ LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
for ac_func in crypt erand48 getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
for ac_func in crypt erand48 getopt getpeereid getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
do do
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
......
...@@ -1191,7 +1191,7 @@ PGAC_VAR_INT_TIMEZONE ...@@ -1191,7 +1191,7 @@ PGAC_VAR_INT_TIMEZONE
AC_FUNC_ACCEPT_ARGTYPES AC_FUNC_ACCEPT_ARGTYPES
PGAC_FUNC_GETTIMEOFDAY_1ARG PGAC_FUNC_GETTIMEOFDAY_1ARG
AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getifaddrs getpeereid getpeerucred getrlimit memmove poll pstat readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l]) AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getifaddrs getpeerucred getrlimit memmove poll pstat readlink scandir setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs wcstombs_l])
AC_REPLACE_FUNCS(fseeko) AC_REPLACE_FUNCS(fseeko)
case $host_os in case $host_os in
...@@ -1310,7 +1310,7 @@ fi ...@@ -1310,7 +1310,7 @@ fi
pgac_save_LIBS="$LIBS" pgac_save_LIBS="$LIBS"
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
AC_REPLACE_FUNCS([crypt erand48 getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul]) AC_REPLACE_FUNCS([crypt erand48 getopt getpeereid getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul])
case $host_os in case $host_os in
......
...@@ -17,12 +17,6 @@ ...@@ -17,12 +17,6 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/socket.h> #include <sys/socket.h>
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#ifdef HAVE_SYS_UCRED_H
#include <sys/ucred.h>
#endif
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <unistd.h> #include <unistd.h>
...@@ -1756,85 +1750,25 @@ static int ...@@ -1756,85 +1750,25 @@ static int
auth_peer(hbaPort *port) auth_peer(hbaPort *port)
{ {
char ident_user[IDENT_USERNAME_MAX + 1]; char ident_user[IDENT_USERNAME_MAX + 1];
uid_t uid = 0; uid_t uid;
struct passwd *pass;
#if defined(HAVE_GETPEEREID)
/* Most BSDen, including OS X: use getpeereid() */
gid_t gid; gid_t gid;
struct passwd *pass;
errno = 0; errno = 0;
if (getpeereid(port->sock, &uid, &gid) != 0) if (getpeereid(port->sock, &uid, &gid) != 0)
{ {
/* We didn't get a valid credentials struct. */ /* Provide special error message if getpeereid is a stub */
ereport(LOG, if (errno == ENOSYS)
(errcode_for_socket_access(), ereport(LOG,
errmsg("could not get peer credentials: %m"))); (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
return STATUS_ERROR; errmsg("peer authentication is not supported on this platform")));
} else
#elif defined(SO_PEERCRED) ereport(LOG,
/* Linux: use getsockopt(SO_PEERCRED) */ (errcode_for_socket_access(),
struct ucred peercred; errmsg("could not get peer credentials: %m")));
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
errno = 0;
if (getsockopt(port->sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
so_len != sizeof(peercred))
{
/* We didn't get a valid credentials struct. */
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
return STATUS_ERROR;
}
uid = peercred.uid;
#elif defined(LOCAL_PEERCRED)
/* Debian with FreeBSD kernel: use getsockopt(LOCAL_PEERCRED) */
struct xucred peercred;
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
errno = 0;
if (getsockopt(port->sock, 0, LOCAL_PEERCRED, &peercred, &so_len) != 0 ||
so_len != sizeof(peercred) ||
peercred.cr_version != XUCRED_VERSION)
{
/* We didn't get a valid credentials struct. */
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
return STATUS_ERROR;
}
uid = peercred.cr_uid;
#elif defined(HAVE_GETPEERUCRED)
/* Solaris: use getpeerucred() */
ucred_t *ucred;
ucred = NULL; /* must be initialized to NULL */
if (getpeerucred(port->sock, &ucred) == -1)
{
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
return STATUS_ERROR;
}
if ((uid = ucred_geteuid(ucred)) == -1)
{
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get effective UID from peer credentials: %m")));
return STATUS_ERROR; return STATUS_ERROR;
} }
ucred_free(ucred);
#else
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Peer authentication is not supported on local connections on this platform")));
return STATUS_ERROR;
#endif
pass = getpwuid(uid); pass = getpwuid(uid);
if (pass == NULL) if (pass == NULL)
......
...@@ -395,6 +395,10 @@ extern void srand48(long seed); ...@@ -395,6 +395,10 @@ extern void srand48(long seed);
extern int getopt(int nargc, char *const * nargv, const char *ostr); extern int getopt(int nargc, char *const * nargv, const char *ostr);
#endif #endif
#ifndef HAVE_GETPEEREID
extern int getpeereid(int sock, uid_t *uid, gid_t *gid);
#endif
#ifndef HAVE_ISINF #ifndef HAVE_ISINF
extern int isinf(double x); extern int isinf(double x);
#endif #endif
......
...@@ -21,12 +21,6 @@ ...@@ -21,12 +21,6 @@
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#ifdef HAVE_SYS_UCRED_H
#include <sys/ucred.h>
#endif
#include "libpq-fe.h" #include "libpq-fe.h"
#include "libpq-int.h" #include "libpq-int.h"
...@@ -1859,6 +1853,7 @@ keep_going: /* We will come back to here until there is ...@@ -1859,6 +1853,7 @@ keep_going: /* We will come back to here until there is
char *startpacket; char *startpacket;
int packetlen; int packetlen;
#ifdef HAVE_UNIX_SOCKETS
/* /*
* Implement requirepeer check, if requested and it's a * Implement requirepeer check, if requested and it's a
* Unix-domain socket. * Unix-domain socket.
...@@ -1866,82 +1861,25 @@ keep_going: /* We will come back to here until there is ...@@ -1866,82 +1861,25 @@ keep_going: /* We will come back to here until there is
if (conn->requirepeer && conn->requirepeer[0] && if (conn->requirepeer && conn->requirepeer[0] &&
IS_AF_UNIX(conn->raddr.addr.ss_family)) IS_AF_UNIX(conn->raddr.addr.ss_family))
{ {
#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(LOCAL_PEERCRED) || defined(HAVE_GETPEERUCRED)
char pwdbuf[BUFSIZ]; char pwdbuf[BUFSIZ];
struct passwd pass_buf; struct passwd pass_buf;
struct passwd *pass; struct passwd *pass;
uid_t uid; uid_t uid;
#if defined(HAVE_GETPEEREID)
/* Most BSDen, including OS X: use getpeereid() */
gid_t gid; gid_t gid;
errno = 0; errno = 0;
if (getpeereid(conn->sock, &uid, &gid) != 0) if (getpeereid(conn->sock, &uid, &gid) != 0)
{ {
appendPQExpBuffer(&conn->errorMessage, /* Provide special error message if getpeereid is a stub */
libpq_gettext("could not get peer credentials: %s\n"), if (errno == ENOSYS)
pqStrerror(errno, sebuf, sizeof(sebuf))); appendPQExpBuffer(&conn->errorMessage,
goto error_return; libpq_gettext("requirepeer parameter is not supported on this platform\n"));
} else
#elif defined(SO_PEERCRED) appendPQExpBuffer(&conn->errorMessage,
/* Linux: use getsockopt(SO_PEERCRED) */ libpq_gettext("could not get peer credentials: %s\n"),
struct ucred peercred; pqStrerror(errno, sebuf, sizeof(sebuf)));
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
errno = 0;
if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED,
&peercred, &so_len) != 0 ||
so_len != sizeof(peercred))
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
goto error_return;
}
uid = peercred.uid;
#elif defined(LOCAL_PEERCRED)
/* Debian with FreeBSD kernel: use LOCAL_PEERCRED */
struct xucred peercred;
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
errno = 0;
if (getsockopt(conn->sock, 0, LOCAL_PEERCRED,
&peercred, &so_len) != 0 ||
so_len != sizeof(peercred) ||
peercred.cr_version != XUCRED_VERSION)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
goto error_return;
}
uid = peercred.cr_uid;
#elif defined(HAVE_GETPEERUCRED)
/* Solaris: use getpeerucred() */
ucred_t *ucred;
ucred = NULL; /* must be initialized to NULL */
if (getpeerucred(conn->sock, &ucred) == -1)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
goto error_return;
}
if ((uid = ucred_geteuid(ucred)) == -1)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get effective UID from peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
ucred_free(ucred);
goto error_return; goto error_return;
} }
ucred_free(ucred);
#else
#error missing implementation method for requirepeer
#endif
pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass); pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
...@@ -1960,12 +1898,8 @@ keep_going: /* We will come back to here until there is ...@@ -1960,12 +1898,8 @@ keep_going: /* We will come back to here until there is
conn->requirepeer, pass->pw_name); conn->requirepeer, pass->pw_name);
goto error_return; goto error_return;
} }
#else /* can't support requirepeer */
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("requirepeer parameter is not supported on this platform\n"));
goto error_return;
#endif
} }
#endif /* HAVE_UNIX_SOCKETS */
#ifdef USE_SSL #ifdef USE_SSL
......
/*-------------------------------------------------------------------------
*
* getpeereid.c
* get peer userid for UNIX-domain socket connection
*
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* src/port/getpeereid.c
*
*-------------------------------------------------------------------------
*/
#include "c.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <unistd.h>
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#ifdef HAVE_SYS_UCRED_H
#include <sys/ucred.h>
#endif
/*
* BSD-style getpeereid() for platforms that lack it.
*/
int
getpeereid(int sock, uid_t *uid, gid_t *gid)
{
#if defined(SO_PEERCRED)
/* Linux: use getsockopt(SO_PEERCRED) */
struct ucred peercred;
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
so_len != sizeof(peercred))
return -1;
*uid = peercred.uid;
*gid = peercred.gid;
return 0;
#elif defined(LOCAL_PEERCRED)
/* Debian with FreeBSD kernel: use getsockopt(LOCAL_PEERCRED) */
struct xucred peercred;
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
if (getsockopt(sock, 0, LOCAL_PEERCRED, &peercred, &so_len) != 0 ||
so_len != sizeof(peercred) ||
peercred.cr_version != XUCRED_VERSION)
return -1;
*uid = peercred.cr_uid;
*gid = peercred.cr_gid;
return 0;
#elif defined(HAVE_GETPEERUCRED)
/* Solaris: use getpeerucred() */
ucred_t *ucred;
ucred = NULL; /* must be initialized to NULL */
if (getpeerucred(sock, &ucred) == -1)
return -1;
*uid = ucred_geteuid(ucred);
*gid = ucred_getegid(ucred);
ucred_free(ucred);
if (*uid == (pid_t)(-1) || *gid == (gid_t)(-1))
return -1;
return 0;
#else
/* No implementation available on this platform */
errno = ENOSYS;
return -1;
#endif
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment