]> granicus.if.org Git - postgresql/commitdiff
Add server authentication over Unix-domain sockets
authorPeter Eisentraut <peter_e@gmx.net>
Sun, 18 Jul 2010 11:37:26 +0000 (11:37 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Sun, 18 Jul 2010 11:37:26 +0000 (11:37 +0000)
This adds a libpq connection parameter requirepeer that specifies the user
name that the server process is expected to run under.

reviewed by KaiGai Kohei

doc/src/sgml/libpq.sgml
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/libpq-int.h

index 595cb0bb55bd1042c195d9ee3d86ae55ddf00fce..ad56b84828bb1fa0fe33b2e505f2a93b16a6e69e 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.314 2010/07/14 17:09:45 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.315 2010/07/18 11:37:25 petere Exp $ -->
 
 <chapter id="libpq">
  <title><application>libpq</application> - C Library</title>
          </listitem>
         </varlistentry>
 
+        <varlistentry id="libpq-connect-requirepeer" xreflabel="requirepeer">
+         <term><literal>requirepeer</literal></term>
+         <listitem>
+          <para>
+           For Unix-domain socket connections, if this parameter is
+           set, the client checks at the beginning of the connection
+           that the server process runs under the specified user name,
+           otherwise the connection is aborted with an error.  This
+           parameter can be used to achieve the kind of server
+           authentication that SSL certificates achieve on TCP/IP
+           connections.  (Note that if the Unix-domain socket is
+           in <filename>/tmp</filename> or another publically writable
+           location, any user could start a server there.  Use this
+           parameter to ensure that you are connected to a server run
+           by a trusted user,
+           e.g., <literal>requirepeer=postgres</literal>.)  This
+           option is only supported on some platforms, currently
+           Linux, FreeBSD, NetBSD, OpenBSD, and Solaris.
+          </para>
+         </listitem>
+        </varlistentry>
+
         <varlistentry id="libpq-connect-krbsrvname" xreflabel="krbsrvname">
          <term><literal>krbsrvname</literal></term>
          <listitem>
@@ -6139,6 +6161,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
      </para>
     </listitem>
 
+    <listitem>
+     <para>
+      <indexterm>
+       <primary><envar>PGREQUIREPEER</envar></primary>
+      </indexterm>
+      <envar>PGREQUIREPEER</envar> behaves the same as the <xref
+      linkend="libpq-connect-requirepeer"> connection parameter.
+     </para>
+    </listitem>
+
     <listitem>
      <para>
       <indexterm>
index 4c59ca6834f7995e8d8170571c186eb4f14d1a28..2b99f03cc41f9fcff1a8de3ae8ee6a038f95ac97 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.398 2010/07/08 16:19:50 mha Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.399 2010/07/18 11:37:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -229,6 +229,9 @@ static const PQconninfoOption PQconninfoOptions[] = {
        {"sslcrl", "PGSSLCRL", NULL, NULL,
        "SSL-Revocation-List", "", 64},
 
+       {"requirepeer", "PGREQUIREPEER", NULL, NULL,
+       "Require-Peer", "", 10},
+
 #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        /* Kerberos and GSSAPI authentication support specifying the service name */
        {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
@@ -595,6 +598,8 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
                conn->sslmode = strdup("require");
        }
 #endif
+       tmp = conninfo_getval(connOptions, "requirepeer");
+       conn->requirepeer = tmp ? strdup(tmp) : NULL;
 #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        tmp = conninfo_getval(connOptions, "krbsrvname");
        conn->krbsrvname = tmp ? strdup(tmp) : NULL;
@@ -1746,6 +1751,86 @@ keep_going:                                              /* We will come back to here until there is
                                char       *startpacket;
                                int                     packetlen;
 
+#ifdef HAVE_UNIX_SOCKETS
+                               if (conn->requirepeer)
+                               {
+                                       char            pwdbuf[BUFSIZ];
+                                       struct passwd pass_buf;
+                                       struct passwd *pass;
+                                       uid_t           uid;
+
+# if defined(HAVE_GETPEEREID)
+                                       gid_t           gid;
+
+                                       errno = 0;
+                                       if (getpeereid(sock, &uid, &gid) != 0)
+                                       {
+                                               appendPQExpBuffer(&conn->errorMessage,
+                                                                                 libpq_gettext("could not get peer credentials: %s\n"),
+                                                                                 pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                               goto error_return;
+                                       }
+# elif defined(SO_PEERCRED)
+                                       struct ucred peercred;
+                                       ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
+
+                                       errno = 0;
+                                       if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
+                                               so_len != sizeof(peercred))
+                                       {
+                                               appendPQExpBuffer(&conn->errorMessage,
+                                                                                 libpq_gettext("could not get peer credentials: %s\n"),
+                                                                                 pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                               goto error_return;
+                                       }
+                                       uid = peercred.uid;
+# elif defined(HAVE_GETPEERUCRED)
+                                       ucred_t    *ucred;
+
+                                       ucred = NULL;                           /* must be initialized to NULL */
+                                       if (getpeerucred(sock, &ucred) == -1)
+                                       {
+                                               appendPQExpBuffer(&conn->errorMessage,
+                                                                                 libpq_gettext("could not get peer credentials: %s\n"),
+                                                                                 pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                               goto error_return;
+                                       }
+
+                                       if ((uid = ucred_geteuid(ucred)) == -1)
+                                       {
+                                               appendPQExpBuffer(&conn->errorMessage,
+                                                                                 libpq_gettext("could not get effective UID from peer credentials: %s\n"),
+                                                                                 pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                               ucred_free(ucred);
+                                               goto error_return;
+                                       }
+                                       ucred_free(ucred);
+# else
+                                       appendPQExpBuffer(&conn->errorMessage,
+                                                                         libpq_gettext("requirepeer parameter is not supported on this platform\n"));
+                                       goto error_return;
+# endif
+
+                                       pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
+
+                                       if (pass == NULL)
+                                       {
+                                               appendPQExpBuffer(&conn->errorMessage,
+                                                                                 libpq_gettext("local user with ID %d does not exist\n"),
+                                                                                                               (int) peercred.uid);
+                                               goto error_return;
+                                       }
+
+                                       if (strcmp(pass->pw_name, conn->requirepeer) != 0)
+                                       {
+                                               appendPQExpBuffer(&conn->errorMessage,
+                                                                                 libpq_gettext("requirepeer failed (actual: %s != required: %s)\n"),
+                                                                                                               pass->pw_name, conn->requirepeer);
+                                               goto error_return;
+                                       }
+                               }
+#endif /* HAVE_UNIX_SOCKETS */
+
 #ifdef USE_SSL
 
                                /*
@@ -2553,6 +2638,8 @@ freePGconn(PGconn *conn)
                free(conn->sslrootcert);
        if (conn->sslcrl)
                free(conn->sslcrl);
+       if (conn->requirepeer)
+               free(conn->requirepeer);
 #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        if (conn->krbsrvname)
                free(conn->krbsrvname);
index 571c3fbbf42739365f090335c93c5102a22ad2c4..f64917995ab04c6c8220730c8fde785cf00319eb 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.153 2010/07/14 17:09:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.154 2010/07/18 11:37:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -310,6 +310,7 @@ struct pg_conn
        char       *sslcert;            /* client certificate filename */
        char       *sslrootcert;        /* root certificate filename */
        char       *sslcrl;                     /* certificate revocation list filename */
+       char       *requirepeer;        /* required peer credentials for local sockets */
 
 #if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
        char       *krbsrvname;         /* Kerberos service name */