]> granicus.if.org Git - postgresql/commitdiff
Rename ident authentication over local connections to peer
authorMagnus Hagander <magnus@hagander.net>
Sat, 19 Mar 2011 17:44:35 +0000 (18:44 +0100)
committerMagnus Hagander <magnus@hagander.net>
Sat, 19 Mar 2011 17:44:35 +0000 (18:44 +0100)
This removes an overloading of two authentication options where
one is very secure (peer) and one is often insecure (ident). Peer
is also the name used in libpq from 9.1 to specify the same type
of authentication.

Also make initdb select peer for local connections when ident is
chosen, and ident for TCP connections when peer is chosen.

ident keyword in pg_hba.conf is still accepted and maps to peer
authentication.

doc/src/sgml/client-auth.sgml
doc/src/sgml/runtime.sgml
src/backend/libpq/auth.c
src/backend/libpq/hba.c
src/backend/libpq/pg_hba.conf.sample
src/bin/initdb/initdb.c
src/include/libpq/hba.h

index 4ca723fe1a6ac87d90f93dedbf5c77c4bf2ca5f7..afbd9feb37ce4d434321431a580dd6d7ddf4c5a2 100644 (file)
@@ -457,16 +457,29 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
         <term><literal>ident</></term>
         <listitem>
          <para>
-          Obtain the operating system user name of the client (for
-          TCP/IP connections by contacting the ident server on the
-          client, for local connections by getting it from the
-          operating system) and check if it matches the requested
-          database user name.
+          Obtain the operating system user name of the client
+          by contacting the ident server on the client
+          and check if it matches the requested database user name.
+          Ident authentication can only be used on TCP/IP
+          connections. When specified for local connections, peer
+          authentication will be used instead.
           See <xref linkend="auth-ident"> for details.
          </para>
         </listitem>
        </varlistentry>
 
+       <varlistentry>
+        <term><literal>peer</></term>
+        <listitem>
+         <para>
+          Obtain the operating system user name from the operating system
+          and check if it matches the requested database user name.
+          This is only available for local connections.
+          See <xref linkend="auth-peer"> for details.
+         </para>
+        </listitem>
+       </varlistentry>
+
        <varlistentry>
         <term><literal>ldap</></term>
         <listitem>
@@ -1200,7 +1213,7 @@ omicron         bryanh                  guest1
   </sect2>
 
   <sect2 id="auth-ident">
-   <title>Ident-based Authentication</title>
+   <title>Ident Authentication</title>
 
    <indexterm>
     <primary>ident</primary>
@@ -1208,13 +1221,19 @@ omicron         bryanh                  guest1
 
    <para>
     The ident authentication method works by obtaining the client's
-    operating system user name and using it as the allowed database user
-    name (with an optional user name mapping).
-    The determination of the client's
-    user name is the security-critical point, and it works differently
-    depending on the connection type, as described below.
+    operating system user name from an ident server and using it as
+    the allowed database user name (with an optional user name mapping).
+    This is only supported on TCP/IP connections.
    </para>
 
+   <note>
+    <para>
+     When ident is specified for a local (non-TCP/IP) connection,
+     peer authentication (see <xref linkend="auth-peer">) will be
+     used instead.
+    </para>
+   </note>
+
    <para>
     The following configuration options are supported for <productname>ident</productname>:
     <variablelist>
@@ -1230,9 +1249,6 @@ omicron         bryanh                  guest1
     </variablelist>
    </para>
 
-   <sect3>
-    <title>Ident Authentication Over TCP/IP</title>
-
    <para>
     The <quote>Identification Protocol</quote> is described in
     RFC 1413. Virtually every Unix-like
@@ -1275,36 +1291,48 @@ omicron         bryanh                  guest1
     since <productname>PostgreSQL</> does not have any way to decrypt the
     returned string to determine the actual user name.
    </para>
-   </sect3>
+  </sect2>
 
-   <sect3>
-    <title>Ident Authentication Over Local Sockets</title>
+  <sect2 id="auth-peer">
+   <title>Peer Authentication</title>
+
+   <indexterm>
+    <primary>peer</primary>
+   </indexterm>
 
    <para>
-    On systems supporting <symbol>SO_PEERCRED</symbol> requests for
+    The peer authentication method works by obtaining the client's
+    operating system user name from the kernel and using it as the
+    allowed database user name (with optional user name mapping). This
+    is only supported on local connections.
+   </para>
+
+   <para>
+    The following configuration options are supported for <productname>peer</productname>:
+    <variablelist>
+     <varlistentry>
+      <term><literal>map</literal></term>
+      <listitem>
+       <para>
+        Allows for mapping between system and database user names. See
+        <xref linkend="auth-username-maps"> for details.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+
+   <para>
+    Peer authentication is only available on  systems supporting
+    <symbol>SO_PEERCRED</symbol> requests for
     Unix-domain sockets (currently <systemitem
     class="osname">Linux</>, <systemitem class="osname">FreeBSD</>,
     <systemitem class="osname">NetBSD</>, <systemitem class="osname">OpenBSD</>,
-    <systemitem class="osname">BSD/OS</>, and <systemitem class="osname">Solaris</systemitem>), ident authentication can also
-    be applied to local connections.
+    <systemitem class="osname">BSD/OS</>, and <systemitem class="osname">Solaris</systemitem>).
     <productname>PostgreSQL</> uses <symbol>SO_PEERCRED</symbol> to find out
     the operating system name of the connected client process.
-    In this case, no security risk is added by
-    using ident authentication; indeed it is a preferable choice for
-    local connections on such systems.
    </para>
 
-    <para>
-     On systems without <symbol>SO_PEERCRED</> requests, ident
-     authentication is only available for TCP/IP connections. As a
-     work-around, it is possible to specify the <systemitem
-     class="systemname">localhost</> address <systemitem
-     class="systemname">127.0.0.1</> and make connections to this
-     address.  This method is trustworthy to the extent that you trust
-     the local ident server.
-    </para>
-    </sect3>
-
   </sect2>
 
   <sect2 id="auth-ldap">
index f77673791b9030204e664d21a93ac5724d8b616b..b5ad1011cbe6bed220fc2db42dd9402f0e89d09e 100644 (file)
@@ -148,7 +148,7 @@ postgres$ <userinput>initdb -D /usr/local/pgsql/data</userinput>
    mode is not used; or modify the generated <filename>pg_hba.conf</filename>
    file after running <command>initdb</command>, but
    <emphasis>before</> you start the server for the first time. (Other
-   reasonable approaches include using <literal>ident</literal> authentication
+   reasonable approaches include using <literal>peer</literal> authentication
    or file system permissions to restrict connections. See <xref
    linkend="client-authentication"> for more information.)
   </para>
index af43c2a7cbc4a030c58589b1b910fd1734b7be21..5f56020cc763ac82a5f36c00856bed58f522852b 100644 (file)
@@ -60,7 +60,10 @@ static int   recv_and_check_password_packet(Port *port);
 /* Standard TCP port number for Ident service. Assigned by IANA */
 #define IDENT_PORT 113
 
-static int     authident(hbaPort *port);
+static int     ident_inet(hbaPort *port);
+#ifdef HAVE_UNIX_SOCKETS
+static int     auth_peer(hbaPort *port);
+#endif
 
 
 /*----------------------------------------------------------------
@@ -269,6 +272,9 @@ auth_failed(Port *port, int status)
                case uaIdent:
                        errstr = gettext_noop("Ident authentication failed for user \"%s\"");
                        break;
+               case uaPeer:
+                       errstr = gettext_noop("Peer authentication failed for user \"%s\"");
+                       break;
                case uaPassword:
                case uaMD5:
                        errstr = gettext_noop("password authentication failed for user \"%s\"");
@@ -506,11 +512,12 @@ ClientAuthentication(Port *port)
 #endif
                        break;
 
-               case uaIdent:
+               case uaPeer:
+#ifdef HAVE_UNIX_SOCKETS
 
                        /*
-                        * If we are doing ident on unix-domain sockets, use SCM_CREDS
-                        * only if it is defined and SO_PEERCRED isn't.
+                        * If we are doing peer on unix-domain sockets, use SCM_CREDS only
+                        * if it is defined and SO_PEERCRED isn't.
                         */
 #if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
        (defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
@@ -535,7 +542,14 @@ ClientAuthentication(Port *port)
                                sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
                        }
 #endif
-                       status = authident(port);
+                       status = auth_peer(port);
+#else /* HAVE_UNIX_SOCKETS */
+                       Assert(false);
+#endif
+                       break;
+
+               case uaIdent:
+                       status = ident_inet(port);
                        break;
 
                case uaMD5:
@@ -1599,11 +1613,12 @@ interpret_ident_response(const char *ident_response,
  *
  *     But iff we're unable to get the information from ident, return false.
  */
-static bool
-ident_inet(const SockAddr remote_addr,
-                  const SockAddr local_addr,
-                  char *ident_user)
+static int
+ident_inet(hbaPort *port)
 {
+       const SockAddr remote_addr = port->raddr;
+       const SockAddr local_addr = port->laddr;
+       char            ident_user[IDENT_USERNAME_MAX + 1];
        pgsocket        sock_fd,                /* File descriptor for socket on which we talk
                                                                 * to Ident */
                                rc;                             /* Return code from a locally called function */
@@ -1646,7 +1661,7 @@ ident_inet(const SockAddr remote_addr,
        {
                if (ident_serv)
                        pg_freeaddrinfo_all(hints.ai_family, ident_serv);
-               return false;                   /* we don't expect this to happen */
+               return STATUS_ERROR;    /* we don't expect this to happen */
        }
 
        hints.ai_flags = AI_NUMERICHOST;
@@ -1662,7 +1677,7 @@ ident_inet(const SockAddr remote_addr,
        {
                if (la)
                        pg_freeaddrinfo_all(hints.ai_family, la);
-               return false;                   /* we don't expect this to happen */
+               return STATUS_ERROR;    /* we don't expect this to happen */
        }
 
        sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
@@ -1751,7 +1766,11 @@ ident_inet_done:
                closesocket(sock_fd);
        pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
        pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
-       return ident_return;
+
+       if (ident_return)
+               /* Success! Check the usermap */
+               return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
+       return STATUS_ERROR;
 }
 
 /*
@@ -1763,9 +1782,12 @@ ident_inet_done:
  */
 #ifdef HAVE_UNIX_SOCKETS
 
-static bool
-ident_unix(int sock, char *ident_user)
+static int
+auth_peer(hbaPort *port)
 {
+       int                     sock = port->sock;
+       char            ident_user[IDENT_USERNAME_MAX + 1];
+
 #if defined(HAVE_GETPEEREID)
        /* OpenBSD style:  */
        uid_t           uid;
@@ -1779,7 +1801,7 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errcode_for_socket_access(),
                                 errmsg("could not get peer credentials: %m")));
-               return false;
+               return STATUS_ERROR;
        }
 
        pass = getpwuid(uid);
@@ -1789,12 +1811,11 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errmsg("local user with ID %d does not exist",
                                                (int) uid)));
-               return false;
+               return STATUS_ERROR;
        }
 
        strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
 
-       return true;
 #elif defined(SO_PEERCRED)
        /* Linux style: use getsockopt(SO_PEERCRED) */
        struct ucred peercred;
@@ -1809,7 +1830,7 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errcode_for_socket_access(),
                                 errmsg("could not get peer credentials: %m")));
-               return false;
+               return STATUS_ERROR;
        }
 
        pass = getpwuid(peercred.uid);
@@ -1819,12 +1840,11 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errmsg("local user with ID %d does not exist",
                                                (int) peercred.uid)));
-               return false;
+               return STATUS_ERROR;
        }
 
        strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
 
-       return true;
 #elif defined(HAVE_GETPEERUCRED)
        /* Solaris > 10 */
        uid_t           uid;
@@ -1837,7 +1857,7 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errcode_for_socket_access(),
                                 errmsg("could not get peer credentials: %m")));
-               return false;
+               return STATUS_ERROR;
        }
 
        if ((uid = ucred_geteuid(ucred)) == -1)
@@ -1845,7 +1865,7 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errcode_for_socket_access(),
                   errmsg("could not get effective UID from peer credentials: %m")));
-               return false;
+               return STATUS_ERROR;
        }
 
        ucred_free(ucred);
@@ -1856,12 +1876,11 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errmsg("local user with ID %d does not exist",
                                                (int) uid)));
-               return false;
+               return STATUS_ERROR;
        }
 
        strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
 
-       return true;
 #elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
        struct msghdr msg;
 
@@ -1913,7 +1932,7 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errcode_for_socket_access(),
                                 errmsg("could not get peer credentials: %m")));
-               return false;
+               return STATUS_ERROR;
        }
 
        cred = (Cred *) CMSG_DATA(cmsg);
@@ -1925,59 +1944,22 @@ ident_unix(int sock, char *ident_user)
                ereport(LOG,
                                (errmsg("local user with ID %d does not exist",
                                                (int) cred->cruid)));
-               return false;
+               return STATUS_ERROR;
        }
 
        strlcpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX + 1);
 
-       return true;
 #else
        ereport(LOG,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("Ident authentication is not supported on local connections on this platform")));
 
-       return false;
-#endif
-}
-#endif   /* HAVE_UNIX_SOCKETS */
-
-
-/*
- *     Determine the username of the initiator of the connection described
- *     by "port".      Then look in the usermap file under the usermap
- *     port->hba->usermap and see if that user is equivalent to Postgres user
- *     port->user.
- *
- *     Return STATUS_OK if yes, STATUS_ERROR if no match (or couldn't get info).
- */
-static int
-authident(hbaPort *port)
-{
-       char            ident_user[IDENT_USERNAME_MAX + 1];
-
-       switch (port->raddr.addr.ss_family)
-       {
-               case AF_INET:
-#ifdef HAVE_IPV6
-               case AF_INET6:
+       return STATUS_ERROR;
 #endif
-                       if (!ident_inet(port->raddr, port->laddr, ident_user))
-                               return STATUS_ERROR;
-                       break;
-
-#ifdef HAVE_UNIX_SOCKETS
-               case AF_UNIX:
-                       if (!ident_unix(port->sock, ident_user))
-                               return STATUS_ERROR;
-                       break;
-#endif
-
-               default:
-                       return STATUS_ERROR;
-       }
 
        return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
 }
+#endif   /* HAVE_UNIX_SOCKETS */
 
 
 /*----------------------------------------------------------------
index 1b3a71431c9acc2a3adb68a4b2d9646b9298b017..2def6cea894852b01e786b308d5db343552fab6b 100644 (file)
@@ -1060,6 +1060,8 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
                parsedline->auth_method = uaTrust;
        else if (strcmp(token, "ident") == 0)
                parsedline->auth_method = uaIdent;
+       else if (strcmp(token, "peer") == 0)
+               parsedline->auth_method = uaPeer;
        else if (strcmp(token, "password") == 0)
                parsedline->auth_method = uaPassword;
        else if (strcmp(token, "krb5") == 0)
@@ -1137,6 +1139,14 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
                return false;
        }
 
+       /*
+        * XXX: When using ident on local connections, change it to peer, for
+        * backwards compatibility.
+        */
+       if (parsedline->conntype == ctLocal &&
+               parsedline->auth_method == uaIdent)
+               parsedline->auth_method = uaPeer;
+
        /* Invalid authentication combinations */
        if (parsedline->conntype == ctLocal &&
                parsedline->auth_method == uaKrb5)
@@ -1160,6 +1170,17 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
                return false;
        }
 
+       if (parsedline->conntype != ctLocal &&
+               parsedline->auth_method == uaPeer)
+       {
+               ereport(LOG,
+                               (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                       errmsg("peer authentication is only supported on local sockets"),
+                                errcontext("line %d of configuration file \"%s\"",
+                                                       line_num, HbaFileName)));
+               return false;
+       }
+
        /*
         * SSPI authentication can never be enabled on ctLocal connections,
         * because it's only supported on Windows, where ctLocal isn't supported.
@@ -1203,11 +1224,12 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
                        if (strcmp(token, "map") == 0)
                        {
                                if (parsedline->auth_method != uaIdent &&
+                                       parsedline->auth_method != uaPeer &&
                                        parsedline->auth_method != uaKrb5 &&
                                        parsedline->auth_method != uaGSS &&
                                        parsedline->auth_method != uaSSPI &&
                                        parsedline->auth_method != uaCert)
-                                       INVALID_AUTH_OPTION("map", gettext_noop("ident, krb5, gssapi, sspi and cert"));
+                                       INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, krb5, gssapi, sspi and cert"));
                                parsedline->usermap = pstrdup(c);
                        }
                        else if (strcmp(token, "clientcert") == 0)
index 87f84991bca9459fc6a9342de6079941289499d4..0a90b68c1006e386e46987998866225a2870e45a 100644 (file)
@@ -41,7 +41,7 @@
 # directly connected to.
 #
 # METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
-# "krb5", "ident", "pam", "ldap", "radius" or "cert".  Note that
+# "krb5", "ident", "peer", "pam", "ldap", "radius" or "cert".  Note that
 # "password" sends passwords in clear text; "md5" is preferred since
 # it sends encrypted passwords.
 #
@@ -75,7 +75,7 @@
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
 
 @remove-line-for-nolocal@# "local" is for Unix domain socket connections only
-@remove-line-for-nolocal@local   all             all                                     @authmethod@
+@remove-line-for-nolocal@local   all             all                                     @authmethodlocal@
 # IPv4 local connections:
 host    all             all             127.0.0.1/32            @authmethod@
 # IPv6 local connections:
index 7a4b698b99fe327d2fe815d965686f8b8d29987c..d509b1311d147b36cda8ded834d5baaa9d6b1ae6 100644 (file)
@@ -82,6 +82,7 @@ static char *username = "";
 static bool pwprompt = false;
 static char *pwfilename = NULL;
 static char *authmethod = "";
+static char *authmethodlocal = "";
 static bool debug = false;
 static bool noclean = false;
 static bool show_setting = false;
@@ -1076,6 +1077,9 @@ setup_config(void)
        conflines = replace_token(conflines,
                                                          "@authmethod@",
                                                          authmethod);
+       conflines = replace_token(conflines,
+                                                         "@authmethodlocal@",
+                                                         authmethodlocal);
 
        conflines = replace_token(conflines,
                                                          "@authcomment@",
@@ -2637,6 +2641,7 @@ main(int argc, char *argv[])
        }
 
        if (strcmp(authmethod, "md5") &&
+               strcmp(authmethod, "peer") &&
                strcmp(authmethod, "ident") &&
                strcmp(authmethod, "trust") &&
 #ifdef USE_PAM
@@ -2666,6 +2671,20 @@ main(int argc, char *argv[])
                exit(1);
        }
 
+       /*
+        * When ident is specified, use peer for local connections. Mirrored, when
+        * peer is specified, use ident for TCP connections.
+        */
+       if (strcmp(authmethod, "ident") == 0)
+               authmethodlocal = "peer";
+       else if (strcmp(authmethod, "peer") == 0)
+       {
+               authmethodlocal = "peer";
+               authmethod = "ident";
+       }
+       else
+               authmethodlocal = authmethod;
+
        if (strlen(pg_data) == 0)
        {
                pgdenv = getenv("PGDATA");
index aa60d8d4f1741e0d7ff97bbc8d0f9e74aed207a1..b92dc0d3a47dc8af4ede6027e68c797949c81f6e 100644 (file)
@@ -29,7 +29,8 @@ typedef enum UserAuth
        uaPAM,
        uaLDAP,
        uaCert,
-       uaRADIUS
+       uaRADIUS,
+       uaPeer
 } UserAuth;
 
 typedef enum IPCompareMethod