[apologies if this appears twice; I thought I had sent it but it hasn't
appeared anywhere]
The attached patch implements a method of connection authentication for
Unix sockets that support SCM_CREDENTIALS.  This includes Linux kernels
2.2 and 2.4 at least; I don't know what other implementations support
it.

Since it is not universally supported, I have included a configure test. 
autoconf needs to be run after installing the patch.

This patch provides a new authentication method "peer" for use with
"local" connections; otherwise it works exactly like the "ident" method.

Please consider including this in PostgreSQL.

diff -ur postgresql-7.1/configure.in postgresql-7.1release/configure.in
--- postgresql-7.1/configure.in Fri Apr 13 22:22:46 2001
+++ postgresql-7.1release/configure.in  Tue May  1 15:03:24 2001
@@ -762,6 +762,15 @@
 dnl Check whether <unistd.h> declares fdatasync().
 AC_EGREP_HEADER(fdatasync, unistd.h, AC_DEFINE(HAVE_FDATASYNC_DECL))
 
+dnl Check whether <sys/socket.h> declares SO_PEERCRED, which is needed for
+dnl passing authorisation credentials across a Unix socket
+AC_EGREP_CPP(SO_PEERCRED, [#include <sys/socket.h>
+main() {
+#ifdef SO_PEERCRED
+printf("SO_PEERCRED\n");
+#endif
+}], AC_DEFINE(HAVE_SCM_CREDENTIALS))
+
 AC_CACHE_CHECK([for PS_STRINGS], [pgac_cv_var_PS_STRINGS],
 [AC_TRY_LINK(
 [#include <machine/vmparam.h>
diff -ur postgresql-7.1/doc/src/sgml/client-auth.sgml 
postgresql-7.1release/doc/src/sgml/client-auth.sgml
--- postgresql-7.1/doc/src/sgml/client-auth.sgml        Fri Mar 16 21:50:37 2001
+++ postgresql-7.1release/doc/src/sgml/client-auth.sgml Wed May  2 11:57:11 2001
@@ -243,6 +243,27 @@
          </para>
         </listitem>
        </varlistentry>
+
+       <varlistentry>
+        <term>peer</term>
+        <listitem>
+         <para>
+          The Unix socket is asked for the identity
+          of the connecting user. <productname>Postgres</productname>
+          then verifies whether the so identified operating system user
+          is allowed to connect as the database user that is requested.
+          This is only available for Unix sockets on operating systems
+          that support the transmission of credentials across the socket;
+          on systems that so not support it, use of this option is an error.
+          In just the same way as for ident, the <replaceable>authentication
+          option</replaceable> following
+          the <literal>peer</> keyword specifies the name of an
+          <firstterm>ident map</firstterm> that specifies which operating
+          system users equate with which database users. See below for
+          details.
+         </para>
+        </listitem>
+       </varlistentry>
       </variablelist>
 
       </para>
@@ -292,6 +313,11 @@
 # The same, over Unix-socket connections:
 
 local        all                                          trust
+
+# Allow any user to connect as himself only, over a Unix socket
+connection (on a system that supports this facility for sockets):
+
+local        all                                          peer      sameuser
 
 # Allow any user from any host with IP address 192.168.93.x to
 # connect to database "template1" as the same username that ident on that
diff -ur postgresql-7.1/src/backend/libpq/auth.c 
postgresql-7.1release/src/backend/libpq/auth.c
--- postgresql-7.1/src/backend/libpq/auth.c     Sat Mar 24 00:54:39 2001
+++ postgresql-7.1release/src/backend/libpq/auth.c      Tue May  1 16:42:21 2001
@@ -439,6 +439,11 @@
                case uaCrypt:
                        authmethod = "Password";
                        break;
+#ifdef SCM_CREDENTIALS
+               case uaPeer:
+                       authmethod = "Peer";
+                       break;
+#endif SCM_CREDENTIALS
        }
 
        sprintf(buffer, "%s authentication failed for user '%s'",
@@ -545,6 +550,16 @@
                                areq = AUTH_REQ_CRYPT;
                                auth_handler = handle_password_auth;
                                break;
+#ifdef HAVE_SCM_CREDENTIALS
+                       case uaPeer:
+                         if (authpeer(port->sock, port->user,
+                                      port->auth_arg) == STATUS_OK)
+                           {
+                             areq = AUTH_REQ_OK;
+                             auth_handler = handle_done_auth;
+                           }
+                               break;
+#endif HAVE_SCM_CREDENTIALS
                }
 
                /* Tell the frontend what we want next. */
@@ -783,6 +798,13 @@
                        status = authident(&port->raddr.in, &port->laddr.in,
                                                           port->user, port->auth_arg);
                        break;
+
+#ifdef HAVE_SCM_CREDENTIALS
+               case uaPeer:
+                       status = authpeer(port->sock, port->user,
+                                         port->auth_arg);
+                       break;
+#endif HAVE_SCM_CREDENTIALS
 
                case uaPassword:
                        if (old != uaPassword)
diff -ur postgresql-7.1/src/backend/libpq/hba.c 
postgresql-7.1release/src/backend/libpq/hba.c
--- postgresql-7.1/src/backend/libpq/hba.c      Fri Feb 23 18:12:02 2001
+++ postgresql-7.1release/src/backend/libpq/hba.c       Wed May  2 10:52:13 2001
@@ -115,6 +115,10 @@
                *userauth_p = uaTrust;
        else if (strcmp(buf, "ident") == 0)
                *userauth_p = uaIdent;
+#ifdef HAVE_SCM_CREDENTIALS
+       else if (strcmp(buf, "peer") == 0)
+               *userauth_p = uaPeer;
+#endif
        else if (strcmp(buf, "password") == 0)
                *userauth_p = uaPassword;
        else if (strcmp(buf, "krb4") == 0)
@@ -763,8 +767,8 @@
                                           bool *checks_out_p)
 {
 /*--------------------------------------------------------------------------
-  See if the user with ident username "ident_username" is allowed to act
-  as Postgres user "pguser" according to usermap "usermap_name".   Look
+  See if the user with ident/peer username "ident_username" is allowed to
+  act as Postgres user "pguser" according to usermap "usermap_name".   Look
   it up in the usermap file.
 
   Special case: For usermap "sameuser", don't look in the usermap
@@ -866,6 +870,74 @@
 
        return checks_out ? STATUS_OK : STATUS_ERROR;
 }
+
+
+#ifdef HAVE_SCM_CREDENTIALS
+#include <stdio.h>
+#include <string.h>
+
+int
+authpeer(int sock,
+        const char *postgres_username,
+        const char *auth_arg)
+{
+/*---------------------------------------------------------------------------
+  Find out from the Unix socket who is connected at the front-end.  Then look
+  in the usermap file under the usermap *auth_arg and see if that user is
+  equivalent to Postgres user *user.
+
+  Return STATUS_OK if yes.
+---------------------------------------------------------------------------*/
+       bool            checks_out;
+       bool peer_failed;
+
+       char            peer_username[L_cuserid + 1];
+       /* The username returned by the socket */
+
+        int passcred = -1;
+       struct ucred peercred;
+       socklen_t so_len = sizeof(passcred);
+       struct passwd *pass;
+
+       if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred,
+                      so_len) != 0) {
+         /* We could not set the socket to pass credentials */
+         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                  "authpeer() could not set the UNIX socket to pass credentials.\n"
+                  "%s\n", strerror(errno));
+         fputs(PQerrormsg, stderr);
+         pqdebug("%s", PQerrormsg);
+         return STATUS_ERROR;
+       }
+
+       so_len = sizeof(peercred);
+       peer_failed = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len);
+       if (peer_failed != 0 || so_len != sizeof(peercred)) {
+       /* We didn't get a valid credentials struct. */
+         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                  "authpeer() could not get valid credentials from the UNIX socket.\n"
+                  "%s\n", strerror(errno));
+         fputs(PQerrormsg, stderr);
+         pqdebug("%s", PQerrormsg);
+         return STATUS_ERROR;
+       }
+
+       if (!(pass = getpwuid(peercred.uid))) {
+         /* Error - no username with the given uid */
+         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                  "authpeer() There is no entry in /etc/passwd with the socket's 
+uid.\n");
+         fputs(PQerrormsg, stderr);
+         pqdebug("%s", PQerrormsg);
+         return STATUS_ERROR;
+       }
+       strncpy(peer_username, pass->pw_name, L_cuserid);
+
+       verify_against_usermap(postgres_username, peer_username, auth_arg,
+                                                  &checks_out);
+
+       return checks_out ? STATUS_OK : STATUS_ERROR;
+}
+#endif HAVE_SCM_CREDENTIALS
 
 
 #ifdef CYR_RECODE
diff -ur postgresql-7.1/src/include/config.h.in 
postgresql-7.1release/src/include/config.h.in
--- postgresql-7.1/src/include/config.h.in      Sat Mar 24 00:54:58 2001
+++ postgresql-7.1release/src/include/config.h.in       Tue May  1 13:31:55 2001
@@ -659,6 +659,9 @@
 
 /* Define if you have on_exit() */
 #undef HAVE_ON_EXIT
+
+/* Define if UNIX sockets support SCM_CREDENTIALS */
+#undef HAVE_SCM_CREDENTIALS
 
 /*
  *------------------------------------------------------------------------
diff -ur postgresql-7.1/src/include/libpq/hba.h 
postgresql-7.1release/src/include/libpq/hba.h
--- postgresql-7.1/src/include/libpq/hba.h      Sat Mar 24 00:54:58 2001
+++ postgresql-7.1release/src/include/libpq/hba.h       Tue May  1 16:41:24 2001
@@ -33,6 +33,9 @@
        uaKrb4,
        uaKrb5,
        uaTrust,
+#ifdef HAVE_SCM_CREDENTIALS
+       uaPeer,
+#endif HAVE_SCM_CREDENTIALS
        uaIdent,
        uaPassword,
        uaCrypt
@@ -43,5 +46,8 @@
 int                    hba_getauthmethod(hbaPort *port);
 int authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
                  const char *postgres_username, const char *auth_arg);
+#ifdef HAVE_SCM_CREDENTIALS
+int authpeer(int sock, const char *postgres_username, const char *auth_arg);
+#endif HAVE_SCM_CREDENTIALS
 
 #endif
diff -ur postgresql-7.1/src/backend/libpq/pg_hba.conf.sample 
postgresql-7.1release/src/backend/libpq/pg_hba.conf.sample
--- postgresql-7.1/src/backend/libpq/pg_hba.conf.sample Tue Nov 21 20:44:32 2000
+++ postgresql-7.1release/src/backend/libpq/pg_hba.conf.sample  Wed May  2 12:33:39 
+2001
@@ -117,15 +117,21 @@
 #              implied map (not sought in pg_ident.conf) that maps every
 #              ident username to the identical PostgreSQL username.
 #
+#   peer:       Authentication is done as for ident, but by obtaining user
+#              identification from the Unix socket credentials.  (This
+#              service is only supported by a few operating systems.  If
+#              it is not usable in a particular implementation, use of
+#              this method will cause an error.)  Username mapping is
+#              exactly the same as for ident.
+#
 #   krb4:      Kerberos V4 authentication is used.
 #
 #   krb5:      Kerberos V5 authentication is used.
 #
 #   reject:    Reject the connection.
 #
-# Local (UNIX socket) connections support only AUTHTYPEs "trust",
-# "password", "crypt", and "reject".
-
+# Local (UNIX socket) connections support only AUTHTYPEs "trust", "password",
+# "crypt", "reject" and (where supported by the operating system) "peer".
 
 # Examples
 # --------
@@ -140,6 +146,11 @@
 # The same, over Unix-socket connections:
 #
 # local      all                                          trust
+#
+# Over a Unix socket, allow any user on the local system to connect to any
+# database using the PostgreSQL username that is the same as his login id:
+#
+# local      all                                          peer      sameuser
 #
 # Allow any user from any host with IP address 192.168.93.x to
 # connect to database "template1" as the same username that ident on that
Oliver Elphick                                [EMAIL PROTECTED]
Isle of Wight                              http://www.lfix.co.uk/oliver
PGP: 1024R/32B8FAA1: 97 EA 1D 47 72 3F 28 47  6B 7E 39 CC 56 E4 C1 47
GPG: 1024D/3E1D0C1C: CA12 09E0 E8D5 8870 5839  932A 614D 4C34 3E1D 0C1C
                 ========================================
     "Rejoice with them that do rejoice, and weep with them 
      that weep."            Romans 12:15 

---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]

Reply via email to