[apologies if this appears twice; I thought I had sent it but it hasn't
appeared anywhere]
The attached patch implements a method of connection authentication for
Unix sockets that support SCM_CREDENTIALS. This includes Linux kernels
2.2 and 2.4 at least; I don't know what other implementations support
it.
Since it is not universally supported, I have included a configure test.
autoconf needs to be run after installing the patch.
This patch provides a new authentication method "peer" for use with
"local" connections; otherwise it works exactly like the "ident" method.
Please consider including this in PostgreSQL.
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 <unistd.h> declares fdatasync().
AC_EGREP_HEADER(fdatasync, unistd.h, AC_DEFINE(HAVE_FDATASYNC_DECL))
+dnl Check whether <sys/socket.h> declares SO_PEERCRED, which is needed for
+dnl passing authorisation credentials across a Unix socket
+AC_EGREP_CPP(SO_PEERCRED, [#include <sys/socket.h>
+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 <machine/vmparam.h>
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 @@
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>peer</term>
+ <listitem>
+ <para>
+ The Unix socket is asked for the identity
+ of the connecting user. <productname>Postgres</productname>
+ 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 <replaceable>authentication
+ option</replaceable> following
+ the <literal>peer</> keyword specifies the name of an
+ <firstterm>ident map</firstterm> that specifies which operating
+ system users equate with which database users. See below for
+ details.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
@@ -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 <stdio.h>
+#include <string.h>
+
+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
Oliver Elphick [EMAIL PROTECTED]
Isle of Wight http://www.lfix.co.uk/oliver
PGP: 1024R/32B8FAA1: 97 EA 1D 47 72 3F 28 47 6B 7E 39 CC 56 E4 C1 47
GPG: 1024D/3E1D0C1C: CA12 09E0 E8D5 8870 5839 932A 614D 4C34 3E1D 0C1C
========================================
"Rejoice with them that do rejoice, and weep with them
that weep." Romans 12:15
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]