Unix sockets connection authentication - patch

Started by Oliver Elphickover 24 years ago5 messages
#1Oliver Elphick
olly@lfix.co.uk
1 attachment(s)

[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.

Attachments:

p.difftext/plain; charset=us-ascii; name=p.diffDownload
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
#2Peter Eisentraut
peter_e@gmx.net
In reply to: Oliver Elphick (#1)
Re: Unix sockets connection authentication - patch

Oliver Elphick writes:

Since it is not universally supported, I have included a configure test.
autoconf needs to be run after installing the patch.

You don't need Autoconf tests for cpp symbols. You can just write #ifdef
WEIRD_SYMBOL in the code.

Btw., never ever use AC_EGREP_*.

--
Peter Eisentraut peter_e@gmx.net http://funkturm.homeip.net/~peter

#3Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Oliver Elphick (#1)
Re: Unix sockets connection authentication - patch

[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.

Are SCM_CREDENTIALS supported by some standard?

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#4Oliver Elphick
olly@lfix.co.uk
In reply to: Bruce Momjian (#3)
Re: Unix sockets connection authentication - patch

Bruce Momjian wrote:

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.

Are SCM_CREDENTIALS supported by some standard?

I don't know if there is a standard. I've done a search on Google - it
seems to have been invented by Sun and implemented in newer BSD as well
as Linux.

--
Oliver Elphick Oliver.Elphick@lfix.co.uk
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

#5Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Oliver Elphick (#1)
Re: Unix sockets connection authentication - patch

Not sure what to do with this. Our authentication options are already
pretty complicated, and I hate to add a new one that no one is really
sure about its portability or usefulness.

[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.

Content-Description: p.diff

[ Attachment, skipping... ]

Oliver Elphick Oliver.Elphick@lfix.co.uk
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 majordomo@postgresql.org

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026