Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Replace use of credential control messages with getsockopt(LOCAL_PEERCRED).
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 31 May 2011 20:10:46 +0000 (16:10 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 31 May 2011 20:10:46 +0000 (16:10 -0400)
It turns out the reason we hadn't found out about the portability issues
with our credential-control-message code is that almost no modern platforms
use that code at all; the ones that used to need it now offer getpeereid(),
which we choose first.  The last holdout was NetBSD, and they added
getpeereid() as of 5.0.  So far as I can tell, the only live platform on
which that code was being exercised was Debian/kFreeBSD, ie, FreeBSD kernel
with Linux userland --- since glibc doesn't provide getpeereid(), we fell
back to the control message code.  However, the FreeBSD kernel provides a
LOCAL_PEERCRED socket parameter that's functionally equivalent to Linux's
SO_PEERCRED.  That is both much simpler to use than control messages, and
superior because it doesn't require receiving a message from the other end
at just the right time.

Therefore, add code to use LOCAL_PEERCRED when necessary, and rip out all
the credential-control-message code in the backend.  (libpq still has such
code so that it can still talk to pre-9.1 servers ... but eventually we can
get rid of it there too.)  Clean up related autoconf probes, too.

This means that libpq's requirepeer parameter now works on exactly the same
platforms where the backend supports peer authentication, so adjust the
documentation accordingly.

configure
configure.in
doc/src/sgml/client-auth.sgml
doc/src/sgml/libpq.sgml
doc/src/sgml/protocol.sgml
src/backend/libpq/auth.c
src/include/pg_config.h.in
src/include/pg_config.h.win32
src/interfaces/libpq/fe-auth.c
src/interfaces/libpq/fe-connect.c

index e73315721b09362da9cce73840e1e2abe4c15a24..5c6022903de79a468985813bbf3331d443cf24f6 100755 (executable)
--- a/configure
+++ b/configure
@@ -9990,7 +9990,8 @@ done
 
 
 
-for ac_header in crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h poll.h pwd.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h
+
+for ac_header in crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h poll.h pwd.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/ucred.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h
 do
 as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
@@ -17037,10 +17038,10 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <sys/param.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#ifdef HAVE_SYS_UCRED_H
 #include <sys/ucred.h>
+#endif
 
 int
 main ()
@@ -17075,10 +17076,10 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <sys/param.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#ifdef HAVE_SYS_UCRED_H
 #include <sys/ucred.h>
+#endif
 
 int
 main ()
@@ -17134,226 +17135,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-fi
-{ $as_echo "$as_me:$LINENO: checking for struct fcred" >&5
-$as_echo_n "checking for struct fcred... " >&6; }
-if test "${ac_cv_type_struct_fcred+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_type_struct_fcred=no
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ucred.h>
-
-int
-main ()
-{
-if (sizeof (struct fcred))
-       return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-    test -z "$ac_c_werror_flag" ||
-    test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ucred.h>
-
-int
-main ()
-{
-if (sizeof ((struct fcred)))
-     return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-    test -z "$ac_c_werror_flag" ||
-    test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-   ac_cv_type_struct_fcred=yes
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_struct_fcred" >&5
-$as_echo "$ac_cv_type_struct_fcred" >&6; }
-if test "x$ac_cv_type_struct_fcred" = x""yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_FCRED 1
-_ACEOF
-
-
-fi
-{ $as_echo "$as_me:$LINENO: checking for struct sockcred" >&5
-$as_echo_n "checking for struct sockcred... " >&6; }
-if test "${ac_cv_type_struct_sockcred+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_type_struct_sockcred=no
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ucred.h>
-
-int
-main ()
-{
-if (sizeof (struct sockcred))
-       return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-    test -z "$ac_c_werror_flag" ||
-    test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ucred.h>
-
-int
-main ()
-{
-if (sizeof ((struct sockcred)))
-     return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-    test -z "$ac_c_werror_flag" ||
-    test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-   ac_cv_type_struct_sockcred=yes
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockcred" >&5
-$as_echo "$ac_cv_type_struct_sockcred" >&6; }
-if test "x$ac_cv_type_struct_sockcred" = x""yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_SOCKCRED 1
-_ACEOF
-
-
 fi
 
 
index a752618bf58b0e544571d5061fef72fa65ad5659..ed2d17d21988b421877dd40f5517521c0cc3e458 100644 (file)
@@ -984,7 +984,7 @@ AC_SUBST(OSSP_UUID_LIBS)
 ##
 
 dnl sys/socket.h is required by AC_FUNC_ACCEPT_ARGTYPES
-AC_CHECK_HEADERS([crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h poll.h pwd.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h])
+AC_CHECK_HEADERS([crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h poll.h pwd.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/ucred.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h])
 
 # On BSD, cpp test for net/if.h will fail unless sys/socket.h
 # is included first.
@@ -1125,11 +1125,11 @@ AC_TYPE_LONG_LONG_INT
 
 PGAC_TYPE_LOCALE_T
 
-AC_CHECK_TYPES([struct cmsgcred, struct fcred, struct sockcred], [], [],
-[#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ucred.h>])
+AC_CHECK_TYPES([struct cmsgcred], [], [],
+[#include <sys/socket.h>
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif])
 
 AC_CHECK_TYPES([struct option], [], [],
 [#ifdef HAVE_GETOPT_H
index cb577e6112a63981b604c90f8b8857779684fe0d..77c541b6cb0ea21e48b732a5041dbae6b5a6ae31 100644 (file)
@@ -48,7 +48,8 @@
   runs. If all the users of a particular server also have accounts on
   the server's machine, it makes sense to assign database user names
   that match their operating system user names. However, a server that
-  accepts remote connections might have many database users who have no local operating system
+  accepts remote connections might have many database users who have no local
+  operating system
   account, and in such cases there need be no connection between
   database user names and OS user names.
  </para>
@@ -472,8 +473,8 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
         <term><literal>peer</></term>
         <listitem>
          <para>
-          Obtain the operating system user name from the operating system
-          and check if it matches the requested database user name.
+          Obtain the client's operating system user name from the operating
+          system and check if it matches the requested database user name.
           This is only available for local connections.
           See <xref linkend="auth-peer"> for details.
          </para>
@@ -1304,7 +1305,7 @@ omicron         bryanh                  guest1
     The peer authentication method works by obtaining the client's
     operating system user name from the kernel and using it as the
     allowed database user name (with optional user name mapping). This
-    is only supported on local connections.
+    method is only supported on local connections.
    </para>
 
    <para>
@@ -1323,14 +1324,13 @@ omicron         bryanh                  guest1
    </para>
 
    <para>
-    Peer authentication is only available on  systems supporting
-    <symbol>SO_PEERCRED</symbol> requests for
-    Unix-domain sockets (currently <systemitem
-    class="osname">Linux</>, <systemitem class="osname">FreeBSD</>,
-    <systemitem class="osname">NetBSD</>, <systemitem class="osname">OpenBSD</>,
-    <systemitem class="osname">BSD/OS</>, and <systemitem class="osname">Solaris</systemitem>).
-    <productname>PostgreSQL</> uses <symbol>SO_PEERCRED</symbol> to find out
-    the operating system name of the connected client process.
+    Peer authentication is only available on operating systems providing
+    the <function>getpeereid()</> function, the <symbol>SO_PEERCRED</symbol>
+    socket parameter, or similar mechanisms.  Currently that includes
+    <systemitem class="osname">Linux</>,
+    most flavors of <systemitem class="osname">BSD</> including
+    <systemitem class="osname">Mac OS X</>,
+    and <systemitem class="osname">Solaris</systemitem>.
    </para>
 
   </sect2>
index 8e19a6e525136d3265cd36fd739cfed460d60e4e..b359000ab302e00217f0da4beef6e7597a234b4f 100644 (file)
@@ -549,20 +549,21 @@ PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand
          <term><literal>requirepeer</literal></term>
          <listitem>
           <para>
-           For Unix-domain socket connections, if this parameter is
-           set, the client checks at the beginning of the connection
-           that the server process runs under the specified user name,
-           otherwise the connection is aborted with an error.  This
-           parameter can be used to achieve the kind of server
-           authentication that SSL certificates achieve on TCP/IP
-           connections.  (Note that if the Unix-domain socket is
-           in <filename>/tmp</filename> or another publicly writable
-           location, any user could start a server there.  Use this
-           parameter to ensure that you are connected to a server run
-           by a trusted user,
-           e.g., <literal>requirepeer=postgres</literal>.)  This
-           option is only supported on some platforms, currently
-           Linux, FreeBSD, NetBSD, OpenBSD, and Solaris.
+           This parameter specifies the operating-system user name of the
+           server, for example <literal>requirepeer=postgres</literal>.
+           When making a Unix-domain socket connection, if this
+           parameter is set, the client checks at the beginning of the
+           connection that the server process is running under the specified
+           user name; if it is not, the connection is aborted with an error.
+           This parameter can be used to provide server authentication similar
+           to that available with SSL certificates on TCP/IP connections.
+           (Note that if the Unix-domain socket is in
+           <filename>/tmp</filename> or another publicly writable location,
+           any user could start a server listening there.  Use this parameter
+           to ensure that you are connected to a server run by a trusted user.)
+           This option is only supported on platforms for which the
+           <literal>peer</> authentication method is implemented; see
+           <xref linkend="auth-peer">.
           </para>
          </listitem>
         </varlistentry>
index 6be5a149aec18df800caae952d615e1bcfd81627..d3de330916dd55ebc64225ef7a5cb8afc02b6dc3 100644 (file)
         the credential message.)  If the credential is acceptable,
         the server responds with an
         AuthenticationOk, otherwise it responds with an ErrorResponse.
+        (This message type is only issued by pre-9.1 servers.  It may
+        eventually be removed from the protocol specification.)
        </para>
       </listitem>
      </varlistentry>
index e6ab659f4b182030641907e7e4b0e083f218eb1a..dc7ad2cadf49ff7bb83d423602253b7b9f4ee29d 100644 (file)
 
 #include <sys/param.h>
 #include <sys/socket.h>
-#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
-#include <sys/uio.h>
-#include <sys/ucred.h>
-#endif
 #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>
-#include <stddef.h>
 
 #include "libpq/auth.h"
 #include "libpq/crypt.h"
@@ -515,36 +513,8 @@ ClientAuthentication(Port *port)
 
        case uaPeer:
 #ifdef HAVE_UNIX_SOCKETS
-
-           /*
-            * If we are doing peer on unix-domain sockets, use SCM_CREDS only
-            * if it is defined and SO_PEERCRED isn't.
-            */
-#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
-   (defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
-    (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS)))
-           if (port->raddr.addr.ss_family == AF_UNIX)
-           {
-#if defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
-
-               /*
-                * Receive credentials on next message receipt, BSD/OS,
-                * NetBSD. We need to set this before the client sends the
-                * next packet.
-                */
-               int         on = 1;
-
-               if (setsockopt(port->sock, 0, LOCAL_CREDS, &on, sizeof(on)) < 0)
-                   ereport(FATAL,
-                           (errcode_for_socket_access(),
-                      errmsg("could not enable credential reception: %m")));
-#endif
-
-               sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
-           }
-#endif
            status = auth_peer(port);
-#else                          /* HAVE_UNIX_SOCKETS */
+#else
            Assert(false);
 #endif
            break;
@@ -1774,11 +1744,11 @@ ident_inet_done:
 }
 
 /*
- * Ask kernel about the credentials of the connecting process and
- * determine the symbolic name of the corresponding user.
+ * Ask kernel about the credentials of the connecting process,
+ * determine the symbolic name of the corresponding user, and check
+ * if valid per the usermap.
  *
- * Returns either true and the username put into "ident_user",
- * or false if we were unable to determine the username.
+ * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
  */
 #ifdef HAVE_UNIX_SOCKETS
 
@@ -1786,12 +1756,12 @@ static int
 auth_peer(hbaPort *port)
 {
    char        ident_user[IDENT_USERNAME_MAX + 1];
+   uid_t       uid = 0;
+   struct passwd *pass;
 
 #if defined(HAVE_GETPEEREID)
-   /* OpenBSD (also Mac OS X) style: use getpeereid() */
-   uid_t       uid;
+   /* Most BSDen, including OS X: use getpeereid() */
    gid_t       gid;
-   struct passwd *pass;
 
    errno = 0;
    if (getpeereid(port->sock, &uid, &gid) != 0)
@@ -1802,23 +1772,10 @@ auth_peer(hbaPort *port)
                 errmsg("could not get peer credentials: %m")));
        return STATUS_ERROR;
    }
-
-   pass = getpwuid(uid);
-
-   if (pass == NULL)
-   {
-       ereport(LOG,
-               (errmsg("local user with ID %d does not exist",
-                       (int) uid)));
-       return STATUS_ERROR;
-   }
-
-   strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
 #elif defined(SO_PEERCRED)
-   /* Linux style: use getsockopt(SO_PEERCRED) */
+   /* Linux: use getsockopt(SO_PEERCRED) */
    struct ucred peercred;
    ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
-   struct passwd *pass;
 
    errno = 0;
    if (getsockopt(port->sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
@@ -1830,22 +1787,26 @@ auth_peer(hbaPort *port)
                 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);
 
-   pass = getpwuid(peercred.uid);
-
-   if (pass == NULL)
+   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,
-               (errmsg("local user with ID %d does not exist",
-                       (int) peercred.uid)));
+               (errcode_for_socket_access(),
+                errmsg("could not get peer credentials: %m")));
        return STATUS_ERROR;
    }
-
-   strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
+   uid = peercred.cr_uid;
 #elif defined(HAVE_GETPEERUCRED)
-   /* Solaris > 10: use getpeerucred() */
-   uid_t       uid;
-   struct passwd *pass;
+   /* Solaris: use getpeerucred() */
    ucred_t    *ucred;
 
    ucred = NULL;               /* must be initialized to NULL */
@@ -1866,8 +1827,16 @@ auth_peer(hbaPort *port)
    }
 
    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)
    {
        ereport(LOG,
@@ -1877,90 +1846,6 @@ auth_peer(hbaPort *port)
    }
 
    strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
-#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
-   /* Assorted BSDen: use a credentials control message */
-#if defined(HAVE_STRUCT_CMSGCRED)
-   typedef struct cmsgcred Cred;
-
-#define cruid cmcred_uid
-#elif defined(HAVE_STRUCT_FCRED)
-   typedef struct fcred Cred;
-
-#define cruid fc_uid
-#elif defined(HAVE_STRUCT_SOCKCRED)
-   typedef struct sockcred Cred;
-
-#define cruid sc_uid
-#endif
-
-   struct msghdr msg;
-   struct cmsghdr *cmsg;
-   union
-   {
-       struct cmsghdr  hdr;
-       unsigned char   buf[CMSG_SPACE(sizeof(Cred))];
-   } cmsgbuf;
-   struct iovec iov;
-   char        buf;
-   Cred       *cred;
-   struct passwd *pw;
-
-   /*
-    * The one character that is received here is not meaningful; its purpose
-    * is only to make sure that recvmsg() blocks long enough for the other
-    * side to send its credentials.
-    */
-   iov.iov_base = &buf;
-   iov.iov_len = 1;
-
-   memset(&msg, 0, sizeof(msg));
-   msg.msg_iov = &iov;
-   msg.msg_iovlen = 1;
-   msg.msg_control = &cmsgbuf.buf;
-   msg.msg_controllen = sizeof(cmsgbuf.buf);
-   memset(&cmsgbuf, 0, sizeof(cmsgbuf));
-
-   if (recvmsg(port->sock, &msg, 0) < 0)
-   {
-       ereport(LOG,
-               (errcode_for_socket_access(),
-                errmsg("could not get peer credentials: %m")));
-       return STATUS_ERROR;
-   }
-
-   cmsg = CMSG_FIRSTHDR(&msg);
-   if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC) ||
-       cmsg == NULL ||
-       cmsg->cmsg_len < CMSG_LEN(sizeof(Cred)) ||
-       cmsg->cmsg_level != SOL_SOCKET ||
-       cmsg->cmsg_type != SCM_CREDS)
-   {
-       ereport(LOG,
-               (errcode(ERRCODE_PROTOCOL_VIOLATION),
-                errmsg("could not get peer credentials: incorrect control message")));
-       return STATUS_ERROR;
-   }
-
-   cred = (Cred *) CMSG_DATA(cmsg);
-
-   pw = getpwuid(cred->cruid);
-
-   if (pw == NULL)
-   {
-       ereport(LOG,
-               (errmsg("local user with ID %d does not exist",
-                       (int) cred->cruid)));
-       return STATUS_ERROR;
-   }
-
-   strlcpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX + 1);
-#else
-   ereport(LOG,
-           (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-            errmsg("Ident authentication is not supported on local connections on this platform")));
-
-   return STATUS_ERROR;
-#endif
 
    return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
 }
index 04560c74bf5f8a0adef3fd802fb770ddd0de912d..5d38f25d263a0b1a9175fa36620e822ece6cd85d 100644 (file)
 /* Define to 1 if the system has the type `struct cmsgcred'. */
 #undef HAVE_STRUCT_CMSGCRED
 
-/* Define to 1 if the system has the type `struct fcred'. */
-#undef HAVE_STRUCT_FCRED
-
 /* Define to 1 if the system has the type `struct option'. */
 #undef HAVE_STRUCT_OPTION
 
 /* Define to 1 if the system has the type `struct sockaddr_un'. */
 #undef HAVE_STRUCT_SOCKADDR_UN
 
-/* Define to 1 if the system has the type `struct sockcred'. */
-#undef HAVE_STRUCT_SOCKCRED
-
 /* Define to 1 if `tm_zone' is member of `struct tm'. */
 #undef HAVE_STRUCT_TM_TM_ZONE
 
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+#undef HAVE_SYS_UCRED_H
+
 /* Define to 1 if you have the <sys/un.h> header file. */
 #undef HAVE_SYS_UN_H
 
index 1ecc05604daea0c0e500084657bb06571f23e555..54bbb5ae72fd9691d036adbc51f88d863bbd3ef5 100644 (file)
 /* Define to 1 if the system has the type `struct cmsgcred'. */
 /* #undef HAVE_STRUCT_CMSGCRED */
 
-/* Define to 1 if the system has the type `struct fcred'. */
-/* #undef HAVE_STRUCT_FCRED */
-
 /* Define to 1 if the system has the type `struct option'. */
 //#define HAVE_STRUCT_OPTION 1
 
 /* Define to 1 if the system has the type `struct sockaddr_un'. */
 /* #undef HAVE_STRUCT_SOCKADDR_UN */
 
-/* Define to 1 if the system has the type `struct sockcred'. */
-/* #undef HAVE_STRUCT_SOCKCRED */
-
 /* Define to 1 if `tm_zone' is member of `struct tm'. */
 /* #undef HAVE_STRUCT_TM_TM_ZONE */
 
 /* Define to 1 if you have the <sys/types.h> header file. */
 #define HAVE_SYS_TYPES_H 1
 
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+/* #undef HAVE_SYS_UCRED_H */
+
 /* Define to 1 if you have the <sys/un.h> header file. */
 /* #undef HAVE_SYS_UN_H */
 
index 094926b4e61f52a665397cbaae11b592ad01abea..9a0317ba4af13ef9ca237c74ef0c11e3bb01f9c1 100644 (file)
 #else
 #include <unistd.h>
 #include <fcntl.h>
-#include <sys/types.h>
 #include <sys/param.h>         /* for MAXHOSTNAMELEN on most */
 #include <sys/socket.h>
-#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
-#include <sys/uio.h>
+#ifdef HAVE_SYS_UCRED_H
 #include <sys/ucred.h>
 #endif
 #ifndef  MAXHOSTNAMELEN
@@ -679,27 +677,25 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate)
 /*
  * Respond to AUTH_REQ_SCM_CREDS challenge.
  *
- * Note: current backends will not use this challenge if HAVE_GETPEEREID
- * or SO_PEERCRED is defined, but pre-7.4 backends might, so compile the
- * code anyway.
+ * Note: this is dead code as of Postgres 9.1, because current backends will
+ * never send this challenge.  But we must keep it as long as libpq needs to
+ * interoperate with pre-9.1 servers.  It is believed to be needed only on
+ * Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the
+ * getpeereid() function isn't provided by libc).
  */
 static int
 pg_local_sendauth(PGconn *conn)
 {
-#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
-   (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
+#ifdef HAVE_STRUCT_CMSGCRED
    char        buf;
    struct iovec iov;
    struct msghdr msg;
-
-#ifdef HAVE_STRUCT_CMSGCRED
    struct cmsghdr *cmsg;
    union
    {
        struct cmsghdr  hdr;
        unsigned char   buf[CMSG_SPACE(sizeof(struct cmsgcred))];
    } cmsgbuf;
-#endif
 
    /*
     * The backend doesn't care what we send here, but it wants exactly one
@@ -713,8 +709,7 @@ pg_local_sendauth(PGconn *conn)
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
 
-#ifdef HAVE_STRUCT_CMSGCRED
-   /* FreeBSD needs us to set up a message that will be filled in by kernel */
+   /* We must set up a message that will be filled in by kernel */
    memset(&cmsgbuf, 0, sizeof(cmsgbuf));
    msg.msg_control = &cmsgbuf.buf;
    msg.msg_controllen = sizeof(cmsgbuf.buf);
@@ -722,7 +717,6 @@ pg_local_sendauth(PGconn *conn)
    cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_CREDS;
-#endif
 
    if (sendmsg(conn->sock, &msg, 0) == -1)
    {
index f89ceb96642af7efe67097544b1e11dcaeb16089..5a6502fff4dab16df82ec8767313f8fa351ed58a 100644 (file)
@@ -24,6 +24,9 @@
 #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"
@@ -1856,15 +1859,21 @@ keep_going:                     /* We will come back to here until there is
                char       *startpacket;
                int         packetlen;
 
-               if (conn->requirepeer && conn->requirepeer[0])
+               /*
+                * Implement requirepeer check, if requested and it's a
+                * Unix-domain socket.
+                */
+               if (conn->requirepeer && conn->requirepeer[0] &&
+                   IS_AF_UNIX(conn->raddr.addr.ss_family))
                {
-#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(HAVE_GETPEERUCRED)
+#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;
@@ -1876,6 +1885,7 @@ keep_going:                       /* We will come back to here until there is
                        goto error_return;
                    }
 #elif defined(SO_PEERCRED)
+                   /* Linux: use getsockopt(SO_PEERCRED) */
                    struct ucred peercred;
                    ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
 
@@ -1890,7 +1900,25 @@ keep_going:                      /* We will come back to here until there is
                        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 */