diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/libpq/auth.c | 34 | ||||
-rw-r--r-- | src/backend/libpq/hba.c | 90 | ||||
-rw-r--r-- | src/backend/libpq/pg_hba.conf.sample | 12 | ||||
-rw-r--r-- | src/include/libpq/pqcomm.h | 3 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-auth.c | 74 | ||||
-rw-r--r-- | src/interfaces/odbc/connection.c | 5 | ||||
-rw-r--r-- | src/interfaces/odbc/connection.h | 1 |
7 files changed, 193 insertions, 26 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 42078e29834..682eede37b9 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -8,17 +8,22 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.62 2001/08/17 15:44:17 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.63 2001/08/21 00:33:27 momjian Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include <sys/types.h> /* needed by in.h on Ultrix */ +#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,12 +33,10 @@ #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); @@ -493,6 +496,26 @@ ClientAuthentication(Port *port) 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,3 +699,4 @@ map_old_to_new(Port *port, UserAuth old, int status) return status; } + diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index cfafa712e12..26a56e567cd 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.64 2001/08/16 16:24:15 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.65 2001/08/21 00:33:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -18,9 +18,13 @@ #include <errno.h> #include <pwd.h> -#include <sys/types.h> #include <fcntl.h> -#include <sys/socket.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> +#endif #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> @@ -876,39 +880,103 @@ ident_unix(int sock, char *ident_user) { /* We didn't get a valid credentials struct. */ snprintf(PQerrormsg, PQERRORMSG_LENGTH, - "Could not get valid credentials from the UNIX socket: %s\n", + "ident_unix: error receiving credentials: %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"); + "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); + StrNCpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX+1); return true; -#else /* not SO_PEERCRED */ +#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"); + "'ident' auth is not supported on local connections on this platform\n"); fputs(PQerrormsg, stderr); pqdebug("%s", PQerrormsg); + return false; -#endif /* SO_PEERCRED */ +#endif } /* diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index d7498717b59..9605dfb3e8c 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -127,12 +127,12 @@ # 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 +# 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 diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 57a7e79696a..48e304d9753 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pqcomm.h,v 1.57 2001/08/16 04:27:18 momjian Exp $ + * $Id: pqcomm.h,v 1.58 2001/08/21 00:33:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -133,6 +133,7 @@ typedef struct StartupPacket #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; diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index e26a9c271ba..72c37bd1203 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -10,7 +10,7 @@ * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes). * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.55 2001/08/17 15:40:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.56 2001/08/21 00:33:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -30,6 +30,7 @@ #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,6 +41,13 @@ #else #include <unistd.h> #include <fcntl.h> +#include <errno.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> +#endif #include <sys/param.h> /* for MAXHOSTNAMELEN on most */ #ifndef MAXHOSTNAMELEN #include <netdb.h> /* for MAXHOSTNAMELEN on some */ @@ -428,6 +436,53 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, #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,12 +528,13 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) crypt_pwd = crypt(password, salt); break; } - default: + 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,6 +607,18 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname, 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); diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c index 1e6167098e2..54e448892bb 100644 --- a/src/interfaces/odbc/connection.c +++ b/src/interfaces/odbc/connection.c @@ -726,6 +726,11 @@ CC_connect(ConnectionClass *self, char do_password) 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; diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h index 67fb38dcaab..11379e4f2ff 100644 --- a/src/interfaces/odbc/connection.h +++ b/src/interfaces/odbc/connection.h @@ -94,6 +94,7 @@ typedef enum #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 |