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/19 16:37:30 *************** *** 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,521 ---- break; case uaIdent: + #if !defined(SO_PEERCRED) && defined(SCM_CREDS) + /* + * If we are doing ident on unix-domain sockets, + * use SCM_CREDS only if it is defined and SO_PEERCRED isn't. + */ + #ifdef fc_uid + /* 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 **** --- 699,702 ---- 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/19 16:37:30 *************** *** 18,26 **** #include #include - #include #include ! #include #include #include #include --- 18,30 ---- #include #include #include ! #include ! #include /* for SCM_CREDS */ ! #ifdef SCM_CREDS ! #include /* for struct iovec */ ! #include ! #endif #include #include #include *************** *** 876,914 **** { /* We didn't get a valid credentials struct. */ snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "Could not get valid credentials from the UNIX socket: %s\n", strerror(errno)); fputs(PQerrormsg, stderr); pqdebug("%s", PQerrormsg); return false; } - /* Convert UID to user login name */ pass = getpwuid(peercred.uid); 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); pqdebug("%s", PQerrormsg); 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 */ } /* --- 880,982 ---- { /* We didn't get a valid credentials struct. */ snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "ident_unix: error receiving credentials: %s\n", strerror(errno)); fputs(PQerrormsg, stderr); pqdebug("%s", PQerrormsg); return false; } pass = getpwuid(peercred.uid); if (pass == NULL) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "ident_unix: unknown local user with uid %d\n", fputs(PQerrormsg, stderr); pqdebug("%s", PQerrormsg); return false; } ! StrNCpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX+1); return true; + + #elif defined(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; + #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/19 16:37:33 *************** *** 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/19 16:37:34 *************** *** 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/19 16:37:35 *************** *** 30,35 **** --- 30,36 ---- #include "postgres_fe.h" + /* XXX is there a reason these appear before the system defines? */ #include "libpq-fe.h" #include "libpq-int.h" #include "fe-auth.h" *************** *** 40,45 **** --- 41,53 ---- #else #include #include + #include + #include + #include /* for SCM_CREDS */ + #ifdef SCM_CREDS + #include /* for struct iovec */ + #include + #endif #include /* for MAXHOSTNAMELEN on most */ #ifndef MAXHOSTNAMELEN #include /* for MAXHOSTNAMELEN on some */ *************** *** 428,433 **** --- 436,488 ---- #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); --- 528,540 ---- 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 **** --- 607,624 ---- 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/19 16:37:36 *************** *** 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/19 16:37:36 *************** *** 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