diff options
Diffstat (limited to 'src/backend')
-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 |
3 files changed, 114 insertions, 22 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 |