diff --git a/configure b/configure index 5c6022903d..a8c5923118 100755 --- a/configure +++ b/configure @@ -18852,8 +18852,7 @@ fi - -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 +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 do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $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'` -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 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 diff --git a/configure.in b/configure.in index ed2d17d219..6a7278aefe 100644 --- a/configure.in +++ b/configure.in @@ -1191,7 +1191,7 @@ PGAC_VAR_INT_TIMEZONE AC_FUNC_ACCEPT_ARGTYPES 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) case $host_os in @@ -1310,7 +1310,7 @@ fi pgac_save_LIBS="$LIBS" 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 diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index dc7ad2cadf..f4099ac234 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -17,12 +17,6 @@ #include #include -#ifdef HAVE_UCRED_H -#include -#endif -#ifdef HAVE_SYS_UCRED_H -#include -#endif #include #include #include @@ -1756,84 +1750,24 @@ static int auth_peer(hbaPort *port) { char ident_user[IDENT_USERNAME_MAX + 1]; - uid_t uid = 0; - struct passwd *pass; - -#if defined(HAVE_GETPEEREID) - /* Most BSDen, including OS X: use getpeereid() */ + uid_t uid; gid_t gid; + struct passwd *pass; errno = 0; if (getpeereid(port->sock, &uid, &gid) != 0) { - /* We didn't get a valid credentials struct. */ - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not get peer credentials: %m"))); + /* Provide special error message if getpeereid is a stub */ + if (errno == ENOSYS) + ereport(LOG, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("peer authentication is not supported on this platform"))); + else + ereport(LOG, + (errcode_for_socket_access(), + errmsg("could not get peer credentials: %m"))); return STATUS_ERROR; } -#elif defined(SO_PEERCRED) - /* Linux: use getsockopt(SO_PEERCRED) */ - struct ucred peercred; - 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; - } - - 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); diff --git a/src/include/port.h b/src/include/port.h index 6ea681f16a..d7295e3132 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -395,6 +395,10 @@ extern void srand48(long seed); extern int getopt(int nargc, char *const * nargv, const char *ostr); #endif +#ifndef HAVE_GETPEEREID +extern int getpeereid(int sock, uid_t *uid, gid_t *gid); +#endif + #ifndef HAVE_ISINF extern int isinf(double x); #endif diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 5a6502fff4..9aa6ca01eb 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -21,12 +21,6 @@ #include #include #include -#ifdef HAVE_UCRED_H -#include -#endif -#ifdef HAVE_SYS_UCRED_H -#include -#endif #include "libpq-fe.h" #include "libpq-int.h" @@ -1859,6 +1853,7 @@ keep_going: /* We will come back to here until there is char *startpacket; int packetlen; +#ifdef HAVE_UNIX_SOCKETS /* * Implement requirepeer check, if requested and it's a * Unix-domain socket. @@ -1866,82 +1861,25 @@ keep_going: /* We will come back to here until there is if (conn->requirepeer && conn->requirepeer[0] && IS_AF_UNIX(conn->raddr.addr.ss_family)) { -#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(LOCAL_PEERCRED) || defined(HAVE_GETPEERUCRED) char pwdbuf[BUFSIZ]; struct passwd pass_buf; struct passwd *pass; uid_t uid; - -#if defined(HAVE_GETPEEREID) - /* Most BSDen, including OS X: use getpeereid() */ gid_t gid; errno = 0; if (getpeereid(conn->sock, &uid, &gid) != 0) { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get peer credentials: %s\n"), - pqStrerror(errno, sebuf, sizeof(sebuf))); + /* Provide special error message if getpeereid is a stub */ + if (errno == ENOSYS) + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("requirepeer parameter is not supported on this platform\n")); + else + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not get peer credentials: %s\n"), + pqStrerror(errno, sebuf, sizeof(sebuf))); goto error_return; } -#elif defined(SO_PEERCRED) - /* Linux: use getsockopt(SO_PEERCRED) */ - struct ucred peercred; - 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; - } - ucred_free(ucred); -#else -#error missing implementation method for requirepeer -#endif pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass); @@ -1960,12 +1898,8 @@ keep_going: /* We will come back to here until there is conn->requirepeer, pass->pw_name); 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 diff --git a/src/port/getpeereid.c b/src/port/getpeereid.c new file mode 100644 index 0000000000..3b826f01e8 --- /dev/null +++ b/src/port/getpeereid.c @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------- + * + * 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 +#include +#include +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_UCRED_H +#include +#endif +#ifdef HAVE_SYS_UCRED_H +#include +#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 +}