Implement getpeereid() as a src/port compatibility function.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jun 2011 17:05:01 +0000 (13:05 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jun 2011 17:05:01 +0000 (13:05 -0400)
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

configure
configure.in
src/backend/libpq/auth.c
src/include/port.h
src/interfaces/libpq/fe-connect.c
src/port/getpeereid.c [new file with mode: 0644]

index 5c6022903de79a468985813bbf3331d443cf24f6..a8c59231183584bdd5b2b85f570057f8a3ec3b84 100755 (executable)
--- 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
index ed2d17d21988b421877dd40f5517521c0cc3e458..6a7278aefe7416c118e4597d4b6f3bd891840368 100644 (file)
@@ -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
 
index dc7ad2cadf49ff7bb83d423602253b7b9f4ee29d..f4099ac23458787d6af8aa2ff82da8130fc7ddcb 100644 (file)
 
 #include <sys/param.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 <arpa/inet.h>
 #include <unistd.h>
@@ -1756,85 +1750,25 @@ 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")));
-               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")));
+               /* 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;
        }
 
-       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);
 
        if (pass == NULL)
index 6ea681f16ace64ad0d035bea97f9c839f84149e0..d7295e3132798f9d506ff653677c6f816f1e4bc9 100644 (file)
@@ -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
index 5a6502fff4dab16df82ec8767313f8fa351ed58a..9aa6ca01eb2fb5c325e50963e495789635754556 100644 (file)
 #include <ctype.h>
 #include <time.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-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)));
-                                               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);
+                                               /* 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;
                                        }
-                                       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 (file)
index 0000000..3b826f0
--- /dev/null
@@ -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 <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
+}