Re: Patch: use SCM_CREDS authentication over PF_LOCAL sockets - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Patch: use SCM_CREDS authentication over PF_LOCAL sockets
Date
Msg-id 200108180408.f7I488D25604@candle.pha.pa.us
Whole thread Raw
In response to Patch: use SCM_CREDS authentication over PF_LOCAL sockets  (wollman@LCS.MIT.EDU)
Responses Re: Patch: use SCM_CREDS authentication over PF_LOCAL sockets
List pgsql-patches
> There are some funky alignment macros that you probably need to use on
> BSD/OS.  Also, as written this will break on NetBSD and OpenBSD for
> reasons I have already noted (the structure is named something
> different there), and those systems will also require the alignment
> macros.  (Basically, putting the two structures in another larger
> structure is a shortcut in my implementation which only works because
> the compiler puts the right amount of padding in; on those other
> systems, more padding is required.)

OK, here is an even better version.  It handles the lack of alignment in
the the structure passing.  This works on BSD/OS and should work on
FreeBSD too.

I will apply it in a day or so unless someone finds a problem.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
Index: src/backend/libpq/auth.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/auth.c,v
retrieving revision 1.62
diff -c -r1.62 auth.c
*** src/backend/libpq/auth.c    2001/08/17 15:44:17    1.62
--- src/backend/libpq/auth.c    2001/08/18 04:04:51
***************
*** 15,24 ****

  #include "postgres.h"

! #include <sys/types.h>            /* needed by in.h on Ultrix */
  #include <netinet/in.h>
  #include <arpa/inet.h>
-
  #include "libpq/auth.h"
  #include "libpq/crypt.h"
  #include "libpq/hba.h"
--- 15,29 ----

  #include "postgres.h"

! #include <sys/types.h>
! #include <sys/socket.h>            /* for SCM_CREDS */
! #ifdef SCM_CREDS
! #include <sys/uio.h>            /* for struct iovec */
! #include <sys/ucred.h>
! #include <errno.h>
! #endif
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include "libpq/auth.h"
  #include "libpq/crypt.h"
  #include "libpq/hba.h"
***************
*** 28,39 ****
  #include "miscadmin.h"

  static void sendAuthRequest(Port *port, AuthRequest areq);
-
  static int    checkPassword(Port *port, char *user, char *password);
  static int    old_be_recvauth(Port *port);
  static int    map_old_to_new(Port *port, UserAuth old, int status);
  static void auth_failed(Port *port);
-
  static int    recv_and_check_password_packet(Port *port);
  static int    recv_and_check_passwordv0(Port *port);

--- 33,42 ----
***************
*** 493,498 ****
--- 496,519 ----
              break;

          case uaIdent:
+ #ifdef SCM_CREDS
+ #ifdef fc_uid
+             /* If we are doing ident on unix-domain sockets,
+                we are going to use SCM_CREDS, if defined. BSD/OS */
+             /* Receive credentials on next message receipt, BSD/OS */
+             {
+                 int on = 1;
+                 if (setsockopt(port->sock, 0, LOCAL_CREDS, &on, sizeof(on)) < 0)
+                 {
+                     elog(FATAL,
+                          "pg_local_sendauth: can't do setsockopt: %s\n", strerror(errno));
+                     return;
+                 }
+             }
+ #endif
+             if (port->raddr.sa.sa_family ==    AF_UNIX)
+                 sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
+ #endif
              status = authident(port);
              break;

***************
*** 676,678 ****
--- 697,700 ----

      return status;
  }
+
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/hba.c,v
retrieving revision 1.64
diff -c -r1.64 hba.c
*** src/backend/libpq/hba.c    2001/08/16 16:24:15    1.64
--- src/backend/libpq/hba.c    2001/08/18 04:04:52
***************
*** 19,24 ****
--- 19,30 ----
  #include <errno.h>
  #include <pwd.h>
  #include <sys/types.h>
+ #include <sys/socket.h>            /* for SCM_CREDS */
+ #ifdef SCM_CREDS
+ #include <sys/uio.h>            /* for struct iovec */
+ #include <sys/ucred.h>
+ #include <errno.h>
+ #endif
  #include <fcntl.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
***************
*** 864,870 ****
  static bool
  ident_unix(int sock, char *ident_user)
  {
! #ifdef SO_PEERCRED
      /* Linux style: use getsockopt(SO_PEERCRED) */
      struct ucred    peercred;
      ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
--- 870,942 ----
  static bool
  ident_unix(int sock, char *ident_user)
  {
! #ifdef SCM_CREDS
!     struct msghdr msg;
!
! /* Credentials structure */
! #ifndef fc_uid
!     typedef struct cmsgcred Cred;
! #define cruid cmcred_uid
! #else
!     typedef struct fcred Cred;
! #define cruid fc_uid
! #endif
!     Cred *cred;
!
!     /* Compute size without padding */
!     char cmsgmem[sizeof(struct cmsghdr) + sizeof(Cred)];
!     /* Point to start of first structure */
!     struct cmsghdr *cmsg = (struct cmsghdr *)cmsgmem;
!
!     struct iovec iov;
!     char buf;
!     struct passwd *pw;
!
!     memset(&msg, 0, sizeof(msg));
!     msg.msg_iov = &iov;
!     msg.msg_iovlen = 1;
!     msg.msg_control = (char *)cmsg;
!     msg.msg_controllen = sizeof(cmsgmem);
!     memset(cmsg, 0, sizeof(cmsgmem));
!
!     /*
!      * The one character which is received here is not meaningful;
!      * its purposes 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;
!
!     if (recvmsg(sock, &msg, 0) < 0 ||
!         cmsg->cmsg_len < sizeof(cmsgmem) ||
!         cmsg->cmsg_type != SCM_CREDS)
!     {
!         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                  "ident_unix: error receiving credentials: %s\n",
!                  strerror(errno));
!         fputs(PQerrormsg, stderr);
!         pqdebug("%s", PQerrormsg);
!         return false;
!     }
!
!     cred = (Cred *)CMSG_DATA(cmsg);
!
!     pw = getpwuid(cred->fc_uid);
!     if (pw == NULL)
!     {
!         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!              "ident_unix: unknown local user with uid %d\n",
!              cred->fc_uid);
!         fputs(PQerrormsg, stderr);
!         pqdebug("%s", PQerrormsg);
!         return false;
!     }
!
!     StrNCpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX+1);
!
!     return true;
!
! #elif SO_PEERCRED
      /* Linux style: use getsockopt(SO_PEERCRED) */
      struct ucred    peercred;
      ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
***************
*** 888,894 ****

      if (pass == NULL)
      {
-         /* Error - no username with the given uid */
          snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                   "There is no entry in /etc/passwd with the socket's uid\n");
          fputs(PQerrormsg, stderr);
--- 960,965 ----
***************
*** 896,914 ****
          return false;
      }

!     StrNCpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX);

      return true;

! #else /* not SO_PEERCRED */
!
      snprintf(PQerrormsg, PQERRORMSG_LENGTH,
               "IDENT auth is not supported on local connections on this platform\n");
      fputs(PQerrormsg, stderr);
      pqdebug("%s", PQerrormsg);
      return false;

! #endif /* SO_PEERCRED */
  }

  /*
--- 967,985 ----
          return false;
      }

!     StrNCpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX+1);

      return true;

! #else
      snprintf(PQerrormsg, PQERRORMSG_LENGTH,
               "IDENT auth is not supported on local connections on this platform\n");
      fputs(PQerrormsg, stderr);
      pqdebug("%s", PQerrormsg);
+
      return false;

! #endif
  }

  /*
Index: src/backend/libpq/pg_hba.conf.sample
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/pg_hba.conf.sample,v
retrieving revision 1.25
diff -c -r1.25 pg_hba.conf.sample
*** src/backend/libpq/pg_hba.conf.sample    2001/08/16 16:24:16    1.25
--- src/backend/libpq/pg_hba.conf.sample    2001/08/18 04:04:54
***************
*** 127,138 ****
  #   ident:    For TCP/IP connections, authentication is done by contacting
  #        the ident server on the client host.  (CAUTION: this is only
  #        as secure as the client machine!)  On machines that support
! #        SO_PEERCRED socket requests, this method also works for
! #        local Unix-domain connections.  AUTH_ARGUMENT is required:
! #        it determines how to map remote user names to Postgres user
! #        names.  The AUTH_ARGUMENT is a map name found in the
! #        $PGDATA/pg_ident.conf file. The connection is accepted if
! #        that file contains an entry for this map name with the
  #        ident-supplied username and the requested Postgres username.
  #        The special map name "sameuser" indicates an implied map
  #        (not in pg_ident.conf) that maps each ident username to the
--- 127,138 ----
  #   ident:    For TCP/IP connections, authentication is done by contacting
  #        the ident server on the client host.  (CAUTION: this is only
  #        as secure as the client machine!)  On machines that support
! #        SO_PEERCRED or SCM_CREDS socket requests, this method also
! #        works for local Unix-domain connections.  AUTH_ARGUMENT is
! #        required: it determines how to map remote user names to
! #        Postgres user names.  The AUTH_ARGUMENT is a map name found
! #        in the $PGDATA/pg_ident.conf file. The connection is accepted
! #        if that file contains an entry for this map name with the
  #        ident-supplied username and the requested Postgres username.
  #        The special map name "sameuser" indicates an implied map
  #        (not in pg_ident.conf) that maps each ident username to the
Index: src/include/libpq/pqcomm.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/libpq/pqcomm.h,v
retrieving revision 1.57
diff -c -r1.57 pqcomm.h
*** src/include/libpq/pqcomm.h    2001/08/16 04:27:18    1.57
--- src/include/libpq/pqcomm.h    2001/08/18 04:04:55
***************
*** 133,138 ****
--- 133,139 ----
  #define AUTH_REQ_PASSWORD    3    /* Password */
  #define AUTH_REQ_CRYPT        4    /* crypt password */
  #define AUTH_REQ_MD5        5    /* md5 password */
+ #define AUTH_REQ_SCM_CREDS    6    /* transfer SCM credentials */

  typedef uint32 AuthRequest;

Index: src/interfaces/libpq/fe-auth.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v
retrieving revision 1.55
diff -c -r1.55 fe-auth.c
*** src/interfaces/libpq/fe-auth.c    2001/08/17 15:40:07    1.55
--- src/interfaces/libpq/fe-auth.c    2001/08/18 04:04:56
***************
*** 40,50 ****
--- 40,57 ----
  #else
  #include <unistd.h>
  #include <fcntl.h>
+ #ifdef SCM_CREDS
+ #include <sys/uio.h>            /* for struct iovec */
+ #include <sys/ucred.h>
+ #include <errno.h>
+ #endif
  #include <sys/param.h>            /* for MAXHOSTNAMELEN on most */
  #ifndef  MAXHOSTNAMELEN
  #include <netdb.h>                /* for MAXHOSTNAMELEN on some */
  #endif
  #include <pwd.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>            /* for SCM_CREDS */
  #endif

  #ifdef HAVE_CRYPT_H
***************
*** 428,433 ****
--- 435,487 ----

  #endif     /* KRB5 */

+ #ifdef SCM_CREDS
+ static int
+ pg_local_sendauth(char *PQerrormsg, PGconn *conn)
+ {
+     char buf;
+     struct iovec iov;
+     struct msghdr msg;
+ #ifndef fc_uid
+     /* Prevent padding */
+     char cmsgmem[sizeof(struct cmsghdr) + sizeof(struct cmsgcred)];
+     /* Point to start of first structure */
+     struct cmsghdr *cmsg = (struct cmsghdr *)cmsgmem;
+ #endif
+
+     /*
+      * The backend doesn't care what we send here, but it wants
+      * exactly one character to force recvmsg() to block and wait
+      * for us.
+      */
+     buf = '\0';
+     iov.iov_base = &buf;
+     iov.iov_len = 1;
+
+     memset(&msg, 0, sizeof(msg));
+     msg.msg_iov = &iov;
+     msg.msg_iovlen = 1;
+
+ #ifndef fc_uid
+     /* Create control header, FreeBSD */
+     msg.msg_control = cmsg;
+     msg.msg_controllen = sizeof(cmsgmem);
+     memset(cmsg, 0, sizeof(cmsgmem));
+     cmsg.hdr.cmsg_len = sizeof(cmsgmem);
+     cmsg.hdr.cmsg_level = SOL_SOCKET;
+     cmsg.hdr.cmsg_type = SCM_CREDS;
+ #endif
+
+     if (sendmsg(conn->sock, &msg, 0) == -1)
+     {
+         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+              "pg_local_sendauth: sendmsg: %s\n", strerror(errno));
+         return STATUS_ERROR;
+     }
+     return STATUS_OK;
+ }
+ #endif
+
  static int
  pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
  {
***************
*** 473,484 ****
              crypt_pwd = crypt(password, salt);
              break;
          }
!         default:
              /* discard const so we can assign it */
              crypt_pwd = (char *)password;
              break;
      }
-
      ret = pqPacketSend(conn, crypt_pwd, strlen(crypt_pwd) + 1);
      if (areq == AUTH_REQ_MD5)
          free(crypt_pwd);
--- 527,539 ----
              crypt_pwd = crypt(password, salt);
              break;
          }
!         case AUTH_REQ_PASSWORD:
              /* discard const so we can assign it */
              crypt_pwd = (char *)password;
              break;
+         default:
+             return STATUS_ERROR;
      }
      ret = pqPacketSend(conn, crypt_pwd, strlen(crypt_pwd) + 1);
      if (areq == AUTH_REQ_MD5)
          free(crypt_pwd);
***************
*** 551,556 ****
--- 606,623 ----
                  return STATUS_ERROR;
              }
              break;
+
+         case AUTH_REQ_SCM_CREDS:
+ #ifdef SCM_CREDS
+             if (pg_local_sendauth(PQerrormsg, conn) != STATUS_OK)
+                 return STATUS_ERROR;
+ #else
+             snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                      libpq_gettext("SCM_CRED authentication method not supported\n"));
+             return STATUS_ERROR;
+ #endif
+             break;
+
          default:
              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                       libpq_gettext("authentication method %u not supported\n"), areq);
Index: src/interfaces/odbc/connection.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/odbc/connection.c,v
retrieving revision 1.34
diff -c -r1.34 connection.c
*** src/interfaces/odbc/connection.c    2001/08/17 02:59:20    1.34
--- src/interfaces/odbc/connection.c    2001/08/18 04:04:57
***************
*** 724,729 ****
--- 724,734 ----
                              self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
                              return 0;

+                         case AUTH_REQ_SCM_CREDS:
+                             self->errormsg = "Unix socket credential authentication not supported";
+                             self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
+                             return 0;
+
                          default:
                              self->errormsg = "Unknown authentication type";
                              self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
Index: src/interfaces/odbc/connection.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/odbc/connection.h,v
retrieving revision 1.25
diff -c -r1.25 connection.h
*** src/interfaces/odbc/connection.h    2001/08/15 18:42:16    1.25
--- src/interfaces/odbc/connection.h    2001/08/18 04:05:00
***************
*** 94,99 ****
--- 94,100 ----
  #define AUTH_REQ_PASSWORD                            3
  #define AUTH_REQ_CRYPT                                4
  #define AUTH_REQ_MD5                                5
+ #define AUTH_REQ_SCM_CREDS                            6

  /*    Startup Packet sizes */
  #define SM_DATABASE                                    64

pgsql-patches by date:

Previous
From: "Serguei Mokhov"
Date:
Subject: Re: encoding names
Next
From: Tatsuo Ishii
Date:
Subject: Re: encoding names