Patch: use SCM_CREDS authentication over PF_LOCAL sockets - Mailing list pgsql-patches
From | wollman@LCS.MIT.EDU |
---|---|
Subject | Patch: use SCM_CREDS authentication over PF_LOCAL sockets |
Date | |
Msg-id | 200108121917.f7CJHgN55360@mintaka.lcs.mit.edu Whole thread Raw |
Responses |
Re: Patch: use SCM_CREDS authentication over PF_LOCAL sockets
Re: Patch: use SCM_CREDS authentication over PF_LOCAL sockets |
List | pgsql-patches |
The following set of patches (relative to 7.1.2 release) implement SCM_CREDS authentication for local connections. On systems which support it, this mechanism should be used instead of `trust' for local connections. -GAWollman ------------------------------------------------------------------------ --- src/backend/libpq/auth.c Wed Mar 21 22:59:30 2001 +++ src/backend/libpq/auth.c Sun Aug 12 14:46:35 2001 @@ -26,6 +26,11 @@ #include <ctype.h> #include <sys/types.h> /* needed by in.h on Ultrix */ +#include <sys/socket.h> /* for SCM_CREDS */ +#ifdef SCM_CREDS +#include <sys/uio.h> /* for struct iovec */ +#include <errno.h> +#endif #include <netinet/in.h> #include <arpa/inet.h> @@ -42,6 +47,7 @@ static int handle_done_auth(void *arg, PacketLen len, void *pkt); static int handle_krb4_auth(void *arg, PacketLen len, void *pkt); static int handle_krb5_auth(void *arg, PacketLen len, void *pkt); +static int handle_local_auth(void *arg, PacketLen len, void *pkt); static int handle_password_auth(void *arg, PacketLen len, void *pkt); static int readPasswordPacket(void *arg, PacketLen len, void *pkt); static int pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt); @@ -322,6 +328,98 @@ #endif /* KRB5 */ +#ifdef SCM_CREDS +static int +pg_local_recvauth(Port *port) +{ + struct msghdr msg; + struct { + struct cmsghdr hdr; + struct cmsgcred cred; + } cmsg; + struct iovec iov; + char buf; + char namebuf[SM_USER + 1]; + struct passwd *pw; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (char *)&cmsg; + msg.msg_controllen = sizeof cmsg; + msg.msg_flags = 0; + + /* + * 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(port->sock, &msg, 0) < 0) { + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "pg_local_recvauth: error receiving credentials: %s\n", + strerror(errno)); +errout: + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + + return STATUS_ERROR; + } + + /* + * Make sure we got the right kind of message. + */ + if (cmsg.hdr.cmsg_len != sizeof cmsg + || cmsg.hdr.cmsg_level != SOL_SOCKET + || cmsg.hdr.cmsg_type != SCM_CREDS) { + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "pg_local_recvauth: protocol error receiving credentials\n"); + goto errout; + } + + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "pg_local_recvauth: pid %lu, uid %lu\n", + (unsigned long)cmsg.cred.cmcred_pid, + (unsigned long)cmsg.cred.cmcred_uid); + pqdebug("%s", PQerrormsg); + + strncpy(namebuf, port->user, SM_USER); + namebuf[SM_USER] = '\0'; + + pw = getpwnam(namebuf); + if (pw == NULL) { + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "pg_local_recvauth: unknown local user %s\n", + namebuf); + goto errout; + } + + if (pw->pw_uid != cmsg.cred.cmcred_uid) { + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "pg_local_recvauth: %s's uid %lu != real uid %lu\n", + namebuf, (unsigned long)pw->pw_uid, + (unsigned long)cmsg.cred.cmcred_uid); + goto errout; + } + return STATUS_OK; +} + +#else +static int +pg_local_recvauth(Port *port) +{ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "pg_local_recvauth: credential passing not implemented on this server.\n"); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + + return STATUS_ERROR; +} +#endif /* SCM_CREDS */ + /* * Handle a v0 password packet. */ @@ -439,6 +537,9 @@ case uaCrypt: authmethod = "Password"; break; + case uaLocalCred: + authmethod = "Local credential"; + break; } sprintf(buffer, "%s authentication failed for user '%s'", @@ -545,6 +646,10 @@ areq = AUTH_REQ_CRYPT; auth_handler = handle_password_auth; break; + case uaLocalCred: + areq = AUTH_REQ_LOCALCRED; + auth_handler = handle_local_auth; + break; } /* Tell the frontend what we want next. */ @@ -668,6 +773,24 @@ /* + * Called when we have told the front end that it should use local + * credential authentication. + */ + +static int +handle_local_auth(void *arg, PacketLen len, void *pkt) +{ + Port *port = (Port *) arg; + + if (pg_local_recvauth(port) != STATUS_OK) + auth_failed(port); + else + sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth); + + return STATUS_OK; +} + +/* * Called when we have received the password packet. */ @@ -777,6 +900,10 @@ case uaTrust: status = STATUS_OK; + break; + + case uaLocalCred: /* can't happen */ + status = STATUS_ERROR; break; case uaIdent: --- src/backend/libpq/hba.c Fri Feb 9 21:31:26 2001 +++ src/backend/libpq/hba.c Sun Aug 12 14:10:28 2001 @@ -125,6 +125,8 @@ *userauth_p = uaReject; else if (strcmp(buf, "crypt") == 0) *userauth_p = uaCrypt; + else if (strcmp(buf, "local") == 0) + *userauth_p = uaLocalCred; else { *error_p = true; @@ -279,6 +281,14 @@ */ read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p); + + /* + * Disallow authentication methods which require a PF_LOCAL + * socket. + */ + if (!*error_p && + (port->auth_method == uaLocalCred)) + *error_p = true; if (*error_p) goto syntax; --- src/backend/libpq/pg_hba.conf.sample Tue Nov 21 15:44:32 2000 +++ src/backend/libpq/pg_hba.conf.sample Sun Aug 12 14:17:41 2001 @@ -96,6 +96,12 @@ # trust: No authentication is done. Trust that the user has the # authority to use whatever username he specifies. # +# local: Use the credential-passing feature of local-domain sockets +# (available only on certain operating systems) to +# authenticate the user. Allow the user access if his +# real UID matches the UID in the system password file +# for the requested username. +# # password: Authentication is done by matching a password supplied # in clear by the host. If AUTH_ARGUMENT is specified then # the password is compared with the user's entry in that @@ -123,7 +129,7 @@ # # reject: Reject the connection. # -# Local (UNIX socket) connections support only AUTHTYPEs "trust", +# Local (UNIX socket) connections support only AUTHTYPEs "trust", "local", # "password", "crypt", and "reject". @@ -137,9 +143,18 @@ # # host all 127.0.0.1 255.255.255.255 trust # -# The same, over Unix-socket connections: +# Allow any user to connect to any database over a local socket, +# provided that the user's real UID is the same as the requested +# database username's UID: +# +# local all local +# +# On operating systems where credential passing over local sockets +# is not available, allow any user to connect to any database over +# a local socket under any username: # # local all trust +# # # Allow any user from any host with IP address 192.168.93.x to # connect to database "template1" as the same username that ident on that --- src/include/libpq/hba.h Wed Mar 21 23:00:47 2001 +++ src/include/libpq/hba.h Sun Aug 12 13:33:30 2001 @@ -35,7 +35,8 @@ uaTrust, uaIdent, uaPassword, - uaCrypt + uaCrypt, + uaLocalCred } UserAuth; typedef struct Port hbaPort; --- src/include/libpq/pqcomm.h Wed Mar 21 23:00:48 2001 +++ src/include/libpq/pqcomm.h Sun Aug 12 13:35:16 2001 @@ -90,7 +90,7 @@ /* The earliest and latest frontend/backend protocol version supported. */ #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(0,0) -#define PG_PROTOCOL_LATEST PG_PROTOCOL(2,0) +#define PG_PROTOCOL_LATEST PG_PROTOCOL(2,1) /* * All packets sent to the postmaster start with the length. This is omitted @@ -132,6 +132,7 @@ #define AUTH_REQ_KRB5 2 /* Kerberos V5 */ #define AUTH_REQ_PASSWORD 3 /* Password */ #define AUTH_REQ_CRYPT 4 /* Encrypted password */ +#define AUTH_REQ_LOCALCRED 5 /* PF_LOCAL credentials */ typedef uint32 AuthRequest; --- src/interfaces/libpq/fe-auth.c Wed Mar 21 23:01:25 2001 +++ src/interfaces/libpq/fe-auth.c Sun Aug 12 14:50:44 2001 @@ -43,6 +43,11 @@ #ifndef MAXHOSTNAMELEN #include <netdb.h> /* for MAXHOSTNAMELEN on some */ #endif +#include <sys/socket.h> /* for SCM_CREDS */ +#ifdef SCM_CREDS +#include <sys/uio.h> +#include <sys/errno.h> +#endif #include <pwd.h> #endif @@ -430,6 +435,52 @@ #endif /* KRB5 */ +#ifdef SCM_CREDS +static int +pg_local_sendauth(char *PQerrormsg, PGconn *conn) +{ + char buf; + struct iovec iov; + struct { + struct cmsghdr hdr; + struct cmsgcred cred; + } cmsg; + struct msghdr msg; + + /* + * 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; + + cmsg.hdr.cmsg_len = sizeof cmsg; + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_CREDS; + /* + * cmsg.cred will get filled in with the correct information + * by the kernel when this message is sent. + */ + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof cmsg; + msg.msg_flags = 0; + + if (sendmsg(conn->sock, &msg, 0) == -1) { + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "pg_local_sendauth: sendmsg: %s", strerror(errno)); + return STATUS_ERROR; + } + return STATUS_OK; +} +#endif + static int pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) { @@ -507,6 +558,17 @@ } break; + + case AUTH_REQ_LOCALCRED: +#ifdef SCM_CREDS + if (pg_local_sendauth(PQerrormsg, conn) != STATUS_OK) + return STATUS_ERROR; + break; +#else + (void) sprintf(PQerrormsg, + "fe_sendauth: local authentication not supported\n"); + return STATUS_ERROR; +#endif default: (void) sprintf(PQerrormsg,
pgsql-patches by date: