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 /* 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,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 #include #include + #include /* for SCM_CREDS */ + #ifdef SCM_CREDS + #include /* for struct iovec */ + #include + #include + #endif #include #include #include *************** *** 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 #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 *************** *** 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