Index: src/backend/libpq/auth.c =================================================================== RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/auth.c,v retrieving revision 1.58 diff -c -r1.58 auth.c *** src/backend/libpq/auth.c 2001/08/16 04:27:18 1.58 --- src/backend/libpq/auth.c 2001/08/16 14:56:42 *************** *** 15,24 **** #include "postgres.h" ! #include /* needed by in.h on Ultrix */ #include #include - #include "libpq/auth.h" #include "libpq/crypt.h" #include "libpq/hba.h" --- 15,29 ---- #include "postgres.h" ! #include ! #include /* for SCM_CREDS */ ! #ifdef SCM_CREDS ! #include /* for struct iovec */ ! #include ! #include ! #endif #include #include #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,507 ---- break; case uaIdent: + #ifdef SCM_CREDS + /* If we are doing ident on unix-domain sockets, + we are going to use SCM_CREDS, if defined. */ + if (port->raddr.sa.sa_family == AF_UNIX) + sendAuthRequest(port, AUTH_REQ_SCM_CREDS); + #endif status = authident(port); break; Index: src/backend/libpq/hba.c =================================================================== RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/hba.c,v retrieving revision 1.63 diff -c -r1.63 hba.c *** src/backend/libpq/hba.c 2001/08/16 04:27:18 1.63 --- src/backend/libpq/hba.c 2001/08/16 14:56:42 *************** *** 19,24 **** --- 19,30 ---- #include #include #include + #include /* for SCM_CREDS */ + #ifdef SCM_CREDS + #include /* for struct iovec */ + #include + #include + #endif #include #include #include *************** *** 863,869 **** 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); --- 869,959 ---- static bool ident_unix(int sock, char *ident_user) { ! #ifdef SCM_CREDS ! struct msghdr msg; ! struct { ! struct cmsghdr hdr; ! #ifndef fc_uid ! struct cmsgcred cred; ! #define cruid cmcred_uid ! #else ! struct fcred cred; ! #define cruid fc_uid ! #endif ! } cmsg; ! struct iovec iov; ! char buf; ! char namebuf[SM_USER + 1]; ! struct passwd *pw; ! ! msg.msg_name = NULL; ! msg.msg_namelen = 0; ! msg.msg_iov = &iov; ! msg.msg_iovlen = 1; ! msg.msg_control = (char *)&cmsg; ! msg.msg_controllen = sizeof cmsg; ! msg.msg_flags = 0; ! ! /* ! * 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) { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "ident_unix: error receiving credentials: %s\n", ! strerror(errno)); ! errout: ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! ! return false; ! } ! ! /* ! * Make sure we got the right kind of message. ! */ ! if (cmsg.hdr.cmsg_len != sizeof cmsg ! || cmsg.hdr.cmsg_level != SOL_SOCKET ! || cmsg.hdr.cmsg_type != SCM_CREDS) { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "ident_unix: protocol error receiving credentials\n"); ! goto errout; ! } ! ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "ident_unix: pid %lu, uid %lu\n", ! #ifndef fc_uid ! (unsigned long)cmsg.cred.cmcred_pid, ! #else ! (unsigned long)0, /* unavailable */ ! #endif ! (unsigned long)cmsg.cred.cruid); ! pqdebug("%s", PQerrormsg); ! ! strncpy(namebuf, ident_user, SM_USER); ! namebuf[SM_USER] = '\0'; ! ! pw = getpwnam(namebuf); ! if (pw == NULL) { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "ident_unix: unknown local user %s\n", ! namebuf); ! goto errout; ! } ! ! if (pw->pw_uid != cmsg.cred.cruid) { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "ident_unix: %s's uid %lu != real uid %lu\n", ! namebuf, (unsigned long)pw->pw_uid, ! (unsigned long)cmsg.cred.cruid); ! goto errout; ! } ! return true; ! #elif SO_PEERCRED /* Linux style: use getsockopt(SO_PEERCRED) */ struct ucred peercred; ACCEPT_TYPE_ARG3 so_len = sizeof(peercred); *************** *** 899,905 **** return true; ! #else /* not SO_PEERCRED */ snprintf(PQerrormsg, PQERRORMSG_LENGTH, "IDENT auth is not supported on local connections on this platform\n"); --- 989,995 ---- return true; ! #else snprintf(PQerrormsg, PQERRORMSG_LENGTH, "IDENT auth is not supported on local connections on this platform\n"); *************** *** 907,913 **** pqdebug("%s", PQerrormsg); return false; ! #endif /* SO_PEERCRED */ } /* --- 997,1003 ---- 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.24 diff -c -r1.24 pg_hba.conf.sample *** src/backend/libpq/pg_hba.conf.sample 2001/08/15 18:42:15 1.24 --- src/backend/libpq/pg_hba.conf.sample 2001/08/16 14:56:47 *************** *** 125,136 **** # 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 --- 125,136 ---- # 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/16 14:56:48 *************** *** 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.50 diff -c -r1.50 fe-auth.c *** src/interfaces/libpq/fe-auth.c 2001/08/15 21:08:21 1.50 --- src/interfaces/libpq/fe-auth.c 2001/08/16 14:56:49 *************** *** 40,50 **** --- 40,57 ---- #else #include #include + #ifdef SCM_CREDS + #include /* for struct iovec */ + #include + #include + #endif #include /* for MAXHOSTNAMELEN on most */ #ifndef MAXHOSTNAMELEN #include /* for MAXHOSTNAMELEN on some */ #endif #include + #include + #include /* for SCM_CREDS */ #endif #ifdef HAVE_CRYPT_H *************** *** 432,437 **** --- 439,490 ---- #endif /* KRB5 */ + #ifdef SCM_CREDS + static int + pg_local_sendauth(char *PQerrormsg, PGconn *conn) + { + char buf; + struct iovec iov; + struct { + struct cmsghdr hdr; + /* We don't pass the credentials structure. Kernel fills it in. */ + } cmsg; + struct msghdr msg; + + /* + * 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; + + cmsg.hdr.cmsg_len = sizeof cmsg; + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_CREDS; + /* + * cmsg.cred will get filled in with the correct information + * by the kernel when this message is sent. + */ + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof cmsg; + msg.msg_flags = 0; + + 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) { *************** *** 442,447 **** --- 495,504 ---- switch (areq) { + case AUTH_REQ_PASSWORD: + /* discard const so we can assign it */ + crypt_pwd = (char *)password; + break; case AUTH_REQ_CRYPT: crypt_pwd = crypt(password, conn->salt); break; *************** *** 472,482 **** 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); --- 529,536 ---- break; } default: ! return STATUS_ERROR; } ret = pqPacketSend(conn, crypt_pwd, strlen(crypt_pwd) + 1); if (areq == AUTH_REQ_MD5) free(crypt_pwd); *************** *** 549,554 **** --- 603,620 ---- 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.33 diff -c -r1.33 connection.c *** src/interfaces/odbc/connection.c 2001/08/15 18:42:16 1.33 --- src/interfaces/odbc/connection.c 2001/08/16 14:56:50 *************** *** 722,727 **** --- 722,732 ---- 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/16 14:56:52 *************** *** 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