diff options
Diffstat (limited to 'src/backend/libpq/auth.c')
-rw-r--r-- | src/backend/libpq/auth.c | 183 |
1 files changed, 34 insertions, 149 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index e6ab659f4b1..dc7ad2cadf4 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -17,17 +17,15 @@ #include <sys/param.h> #include <sys/socket.h> -#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED) -#include <sys/uio.h> -#include <sys/ucred.h> -#endif #ifdef HAVE_UCRED_H #include <ucred.h> #endif +#ifdef HAVE_SYS_UCRED_H +#include <sys/ucred.h> +#endif #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> -#include <stddef.h> #include "libpq/auth.h" #include "libpq/crypt.h" @@ -515,36 +513,8 @@ ClientAuthentication(Port *port) case uaPeer: #ifdef HAVE_UNIX_SOCKETS - - /* - * If we are doing peer on unix-domain sockets, use SCM_CREDS only - * if it is defined and SO_PEERCRED isn't. - */ -#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \ - (defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \ - (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))) - if (port->raddr.addr.ss_family == AF_UNIX) - { -#if defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED) - - /* - * Receive credentials on next message receipt, BSD/OS, - * NetBSD. We need to set this before the client sends the - * next packet. - */ - int on = 1; - - if (setsockopt(port->sock, 0, LOCAL_CREDS, &on, sizeof(on)) < 0) - ereport(FATAL, - (errcode_for_socket_access(), - errmsg("could not enable credential reception: %m"))); -#endif - - sendAuthRequest(port, AUTH_REQ_SCM_CREDS); - } -#endif status = auth_peer(port); -#else /* HAVE_UNIX_SOCKETS */ +#else Assert(false); #endif break; @@ -1774,11 +1744,11 @@ ident_inet_done: } /* - * Ask kernel about the credentials of the connecting process and - * determine the symbolic name of the corresponding user. + * Ask kernel about the credentials of the connecting process, + * determine the symbolic name of the corresponding user, and check + * if valid per the usermap. * - * Returns either true and the username put into "ident_user", - * or false if we were unable to determine the username. + * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR. */ #ifdef HAVE_UNIX_SOCKETS @@ -1786,12 +1756,12 @@ static int auth_peer(hbaPort *port) { char ident_user[IDENT_USERNAME_MAX + 1]; + uid_t uid = 0; + struct passwd *pass; #if defined(HAVE_GETPEEREID) - /* OpenBSD (also Mac OS X) style: use getpeereid() */ - uid_t uid; + /* Most BSDen, including OS X: use getpeereid() */ gid_t gid; - struct passwd *pass; errno = 0; if (getpeereid(port->sock, &uid, &gid) != 0) @@ -1802,23 +1772,10 @@ auth_peer(hbaPort *port) errmsg("could not get peer credentials: %m"))); return STATUS_ERROR; } - - pass = getpwuid(uid); - - if (pass == NULL) - { - ereport(LOG, - (errmsg("local user with ID %d does not exist", - (int) uid))); - return STATUS_ERROR; - } - - strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1); #elif defined(SO_PEERCRED) - /* Linux style: use getsockopt(SO_PEERCRED) */ + /* Linux: use getsockopt(SO_PEERCRED) */ struct ucred peercred; ACCEPT_TYPE_ARG3 so_len = sizeof(peercred); - struct passwd *pass; errno = 0; if (getsockopt(port->sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 || @@ -1830,22 +1787,26 @@ auth_peer(hbaPort *port) errmsg("could not get peer credentials: %m"))); return STATUS_ERROR; } + uid = peercred.uid; +#elif defined(LOCAL_PEERCRED) + /* Debian with FreeBSD kernel: use getsockopt(LOCAL_PEERCRED) */ + struct xucred peercred; + ACCEPT_TYPE_ARG3 so_len = sizeof(peercred); - pass = getpwuid(peercred.uid); - - if (pass == NULL) + errno = 0; + if (getsockopt(port->sock, 0, LOCAL_PEERCRED, &peercred, &so_len) != 0 || + so_len != sizeof(peercred) || + peercred.cr_version != XUCRED_VERSION) { + /* We didn't get a valid credentials struct. */ ereport(LOG, - (errmsg("local user with ID %d does not exist", - (int) peercred.uid))); + (errcode_for_socket_access(), + errmsg("could not get peer credentials: %m"))); return STATUS_ERROR; } - - strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1); + uid = peercred.cr_uid; #elif defined(HAVE_GETPEERUCRED) - /* Solaris > 10: use getpeerucred() */ - uid_t uid; - struct passwd *pass; + /* Solaris: use getpeerucred() */ ucred_t *ucred; ucred = NULL; /* must be initialized to NULL */ @@ -1866,8 +1827,16 @@ auth_peer(hbaPort *port) } ucred_free(ucred); +#else + ereport(LOG, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Peer authentication is not supported on local connections on this platform"))); + + return STATUS_ERROR; +#endif pass = getpwuid(uid); + if (pass == NULL) { ereport(LOG, @@ -1877,90 +1846,6 @@ auth_peer(hbaPort *port) } strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1); -#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS)) - /* Assorted BSDen: use a credentials control message */ -#if defined(HAVE_STRUCT_CMSGCRED) - typedef struct cmsgcred Cred; - -#define cruid cmcred_uid -#elif defined(HAVE_STRUCT_FCRED) - typedef struct fcred Cred; - -#define cruid fc_uid -#elif defined(HAVE_STRUCT_SOCKCRED) - typedef struct sockcred Cred; - -#define cruid sc_uid -#endif - - struct msghdr msg; - struct cmsghdr *cmsg; - union - { - struct cmsghdr hdr; - unsigned char buf[CMSG_SPACE(sizeof(Cred))]; - } cmsgbuf; - struct iovec iov; - char buf; - Cred *cred; - struct passwd *pw; - - /* - * The one character that is received here is not meaningful; its purpose - * 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; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - memset(&cmsgbuf, 0, sizeof(cmsgbuf)); - - if (recvmsg(port->sock, &msg, 0) < 0) - { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not get peer credentials: %m"))); - return STATUS_ERROR; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC) || - cmsg == NULL || - cmsg->cmsg_len < CMSG_LEN(sizeof(Cred)) || - cmsg->cmsg_level != SOL_SOCKET || - cmsg->cmsg_type != SCM_CREDS) - { - ereport(LOG, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("could not get peer credentials: incorrect control message"))); - return STATUS_ERROR; - } - - cred = (Cred *) CMSG_DATA(cmsg); - - pw = getpwuid(cred->cruid); - - if (pw == NULL) - { - ereport(LOG, - (errmsg("local user with ID %d does not exist", - (int) cred->cruid))); - return STATUS_ERROR; - } - - strlcpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX + 1); -#else - ereport(LOG, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Ident authentication is not supported on local connections on this platform"))); - - return STATUS_ERROR; -#endif return check_usermap(port->hba->usermap, port->user_name, ident_user, false); } |