diff -ur postgresql-7.1/configure.in postgresql-7.1release/configure.in --- postgresql-7.1/configure.in Fri Apr 13 22:22:46 2001 +++ postgresql-7.1release/configure.in Tue May 1 15:03:24 2001 @@ -762,6 +762,15 @@ dnl Check whether declares fdatasync(). AC_EGREP_HEADER(fdatasync, unistd.h, AC_DEFINE(HAVE_FDATASYNC_DECL)) +dnl Check whether declares SO_PEERCRED, which is needed for +dnl passing authorisation credentials across a Unix socket +AC_EGREP_CPP(SO_PEERCRED, [#include +main() { +#ifdef SO_PEERCRED +printf("SO_PEERCRED\n"); +#endif +}], AC_DEFINE(HAVE_SCM_CREDENTIALS)) + AC_CACHE_CHECK([for PS_STRINGS], [pgac_cv_var_PS_STRINGS], [AC_TRY_LINK( [#include diff -ur postgresql-7.1/doc/src/sgml/client-auth.sgml postgresql-7.1release/doc/src/sgml/client-auth.sgml --- postgresql-7.1/doc/src/sgml/client-auth.sgml Fri Mar 16 21:50:37 2001 +++ postgresql-7.1release/doc/src/sgml/client-auth.sgml Wed May 2 11:57:11 2001 @@ -243,6 +243,27 @@ + + + peer + + + The Unix socket is asked for the identity + of the connecting user. Postgres + then verifies whether the so identified operating system user + is allowed to connect as the database user that is requested. + This is only available for Unix sockets on operating systems + that support the transmission of credentials across the socket; + on systems that so not support it, use of this option is an error. + In just the same way as for ident, the authentication + option following + the peer keyword specifies the name of an + ident map that specifies which operating + system users equate with which database users. See below for + details. + + + @@ -292,6 +313,11 @@ # The same, over Unix-socket connections: local all trust + +# Allow any user to connect as himself only, over a Unix socket +connection (on a system that supports this facility for sockets): + +local all peer sameuser # 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 diff -ur postgresql-7.1/src/backend/libpq/auth.c postgresql-7.1release/src/backend/libpq/auth.c --- postgresql-7.1/src/backend/libpq/auth.c Sat Mar 24 00:54:39 2001 +++ postgresql-7.1release/src/backend/libpq/auth.c Tue May 1 16:42:21 2001 @@ -439,6 +439,11 @@ case uaCrypt: authmethod = "Password"; break; +#ifdef SCM_CREDENTIALS + case uaPeer: + authmethod = "Peer"; + break; +#endif SCM_CREDENTIALS } sprintf(buffer, "%s authentication failed for user '%s'", @@ -545,6 +550,16 @@ areq = AUTH_REQ_CRYPT; auth_handler = handle_password_auth; break; +#ifdef HAVE_SCM_CREDENTIALS + case uaPeer: + if (authpeer(port->sock, port->user, + port->auth_arg) == STATUS_OK) + { + areq = AUTH_REQ_OK; + auth_handler = handle_done_auth; + } + break; +#endif HAVE_SCM_CREDENTIALS } /* Tell the frontend what we want next. */ @@ -783,6 +798,13 @@ status = authident(&port->raddr.in, &port->laddr.in, port->user, port->auth_arg); break; + +#ifdef HAVE_SCM_CREDENTIALS + case uaPeer: + status = authpeer(port->sock, port->user, + port->auth_arg); + break; +#endif HAVE_SCM_CREDENTIALS case uaPassword: if (old != uaPassword) diff -ur postgresql-7.1/src/backend/libpq/hba.c postgresql-7.1release/src/backend/libpq/hba.c --- postgresql-7.1/src/backend/libpq/hba.c Fri Feb 23 18:12:02 2001 +++ postgresql-7.1release/src/backend/libpq/hba.c Wed May 2 10:52:13 2001 @@ -115,6 +115,10 @@ *userauth_p = uaTrust; else if (strcmp(buf, "ident") == 0) *userauth_p = uaIdent; +#ifdef HAVE_SCM_CREDENTIALS + else if (strcmp(buf, "peer") == 0) + *userauth_p = uaPeer; +#endif else if (strcmp(buf, "password") == 0) *userauth_p = uaPassword; else if (strcmp(buf, "krb4") == 0) @@ -763,8 +767,8 @@ bool *checks_out_p) { /*-------------------------------------------------------------------------- - See if the user with ident username "ident_username" is allowed to act - as Postgres user "pguser" according to usermap "usermap_name". Look + See if the user with ident/peer username "ident_username" is allowed to + act as Postgres user "pguser" according to usermap "usermap_name". Look it up in the usermap file. Special case: For usermap "sameuser", don't look in the usermap @@ -866,6 +870,74 @@ return checks_out ? STATUS_OK : STATUS_ERROR; } + + +#ifdef HAVE_SCM_CREDENTIALS +#include +#include + +int +authpeer(int sock, + const char *postgres_username, + const char *auth_arg) +{ +/*--------------------------------------------------------------------------- + Find out from the Unix socket who is connected at the front-end. Then look + in the usermap file under the usermap *auth_arg and see if that user is + equivalent to Postgres user *user. + + Return STATUS_OK if yes. +---------------------------------------------------------------------------*/ + bool checks_out; + bool peer_failed; + + char peer_username[L_cuserid + 1]; + /* The username returned by the socket */ + + int passcred = -1; + struct ucred peercred; + socklen_t so_len = sizeof(passcred); + struct passwd *pass; + + if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred, + so_len) != 0) { + /* We could not set the socket to pass credentials */ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "authpeer() could not set the UNIX socket to pass credentials.\n" + "%s\n", strerror(errno)); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return STATUS_ERROR; + } + + so_len = sizeof(peercred); + peer_failed = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len); + if (peer_failed != 0 || so_len != sizeof(peercred)) { + /* We didn't get a valid credentials struct. */ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "authpeer() could not get valid credentials from the UNIX socket.\n" + "%s\n", strerror(errno)); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return STATUS_ERROR; + } + + if (!(pass = getpwuid(peercred.uid))) { + /* Error - no username with the given uid */ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "authpeer() There is no entry in /etc/passwd with the socket's uid.\n"); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return STATUS_ERROR; + } + strncpy(peer_username, pass->pw_name, L_cuserid); + + verify_against_usermap(postgres_username, peer_username, auth_arg, + &checks_out); + + return checks_out ? STATUS_OK : STATUS_ERROR; +} +#endif HAVE_SCM_CREDENTIALS #ifdef CYR_RECODE diff -ur postgresql-7.1/src/include/config.h.in postgresql-7.1release/src/include/config.h.in --- postgresql-7.1/src/include/config.h.in Sat Mar 24 00:54:58 2001 +++ postgresql-7.1release/src/include/config.h.in Tue May 1 13:31:55 2001 @@ -659,6 +659,9 @@ /* Define if you have on_exit() */ #undef HAVE_ON_EXIT + +/* Define if UNIX sockets support SCM_CREDENTIALS */ +#undef HAVE_SCM_CREDENTIALS /* *------------------------------------------------------------------------ diff -ur postgresql-7.1/src/include/libpq/hba.h postgresql-7.1release/src/include/libpq/hba.h --- postgresql-7.1/src/include/libpq/hba.h Sat Mar 24 00:54:58 2001 +++ postgresql-7.1release/src/include/libpq/hba.h Tue May 1 16:41:24 2001 @@ -33,6 +33,9 @@ uaKrb4, uaKrb5, uaTrust, +#ifdef HAVE_SCM_CREDENTIALS + uaPeer, +#endif HAVE_SCM_CREDENTIALS uaIdent, uaPassword, uaCrypt @@ -43,5 +46,8 @@ int hba_getauthmethod(hbaPort *port); int authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr, const char *postgres_username, const char *auth_arg); +#ifdef HAVE_SCM_CREDENTIALS +int authpeer(int sock, const char *postgres_username, const char *auth_arg); +#endif HAVE_SCM_CREDENTIALS #endif diff -ur postgresql-7.1/src/backend/libpq/pg_hba.conf.sample postgresql-7.1release/src/backend/libpq/pg_hba.conf.sample --- postgresql-7.1/src/backend/libpq/pg_hba.conf.sample Tue Nov 21 20:44:32 2000 +++ postgresql-7.1release/src/backend/libpq/pg_hba.conf.sample Wed May 2 12:33:39 2001 @@ -117,15 +117,21 @@ # implied map (not sought in pg_ident.conf) that maps every # ident username to the identical PostgreSQL username. # +# peer: Authentication is done as for ident, but by obtaining user +# identification from the Unix socket credentials. (This +# service is only supported by a few operating systems. If +# it is not usable in a particular implementation, use of +# this method will cause an error.) Username mapping is +# exactly the same as for ident. +# # krb4: Kerberos V4 authentication is used. # # krb5: Kerberos V5 authentication is used. # # reject: Reject the connection. # -# Local (UNIX socket) connections support only AUTHTYPEs "trust", -# "password", "crypt", and "reject". - +# Local (UNIX socket) connections support only AUTHTYPEs "trust", "password", +# "crypt", "reject" and (where supported by the operating system) "peer". # Examples # -------- @@ -140,6 +146,11 @@ # The same, over Unix-socket connections: # # local all trust +# +# Over a Unix socket, allow any user on the local system to connect to any +# database using the PostgreSQL username that is the same as his login id: +# +# local all peer sameuser # # 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