Add parameter krb_realm used by GSSAPI, SSPI and Kerberos
authorMagnus Hagander <magnus@hagander.net>
Fri, 9 Nov 2007 17:31:07 +0000 (17:31 +0000)
committerMagnus Hagander <magnus@hagander.net>
Fri, 9 Nov 2007 17:31:07 +0000 (17:31 +0000)
to validate the realm of the connecting user. By default
it's empty meaning no verification, which is the way
Kerberos authentication has traditionally worked in
PostgreSQL.

doc/src/sgml/client-auth.sgml
doc/src/sgml/config.sgml
src/backend/libpq/auth.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/libpq/auth.h

index b4a851588eac7be5c04dd27440234d3bc7a07aef..9e3ab2440d9897efa8429d6af3d9f59daff4857c 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.101 2007/09/14 03:53:54 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.102 2007/11/09 17:31:07 mha Exp $ -->
 
 <chapter id="client-authentication">
  <title>Client Authentication</title>
@@ -773,10 +773,10 @@ local   db1,db2,@demodbs  all                         md5
    <para>
     Client principals must have their <productname>PostgreSQL</> database user
     name as their first component, for example
-    <literal>pgusername/otherstuff@realm</>. At present the realm of
-    the client is not checked by <productname>PostgreSQL</>; so if you
-    have cross-realm authentication enabled, then any principal in any
-    realm that can communicate with yours will be accepted.
+    <literal>pgusername@realm</>. By default, the realm of the client is
+   not checked by <productname>PostgreSQL</>. If you have cross-realm
+   authentication enabled and need to verify the realm, use the
+   <xref linkend="guc-krb-realm"> parameter.
    </para>
 
    <para>
index f070290f4835acb5443a46ad1d39acb1af560def..d8d8c4deb140aebe001e3e853be454489a2802de 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.153 2007/11/05 17:35:38 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.154 2007/11/09 17:31:07 mha Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -601,6 +601,21 @@ SET ENABLE_SEQSCAN TO OFF;
       </listitem>
      </varlistentry>
 
+    <varlistentry id="guc-krb-realm" xreflabel="krb_realm">
+     <term><varname>krb_realm</varname> (<type>string</type>)</term>
+     <indexterm>
+      <primary><varname>krb_realm</> configuration parameter</primary>
+     </indexterm>
+     <listitem>
+      <para>
+       Sets the realm to match Kerberos, GSSAPI and SSPI usernames against.
+       See <xref linkend="kerberos-auth">, <xref linkend="gssapi-auth"> or
+       <xref linkend="sspi-auth"> for details. This parameter can only be
+       set at server start.
+       </para>
+     </listitem>
+    </varlistentry>
+
      <varlistentry id="guc-krb-server-keyfile" xreflabel="krb_server_keyfile">
       <term><varname>krb_server_keyfile</varname> (<type>string</type>)</term>
       <indexterm>
index 403a9664b46bc105370d6316ceeb4292bea499a7..bba3ebf5b451bf098a5fdc46ff4736fd380d14c5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.156 2007/09/14 15:58:02 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.157 2007/11/09 17:31:07 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,6 +42,7 @@ char     *pg_krb_server_keyfile;
 char      *pg_krb_srvnam;
 bool       pg_krb_caseins_users;
 char      *pg_krb_server_hostname = NULL;
+char      *pg_krb_realm = NULL;
 
 #ifdef USE_PAM
 #ifdef HAVE_PAM_PAM_APPL_H
@@ -102,30 +103,6 @@ static int CheckLDAPAuth(Port *port);
 #include <com_err.h>
 #endif
 
-/*
- * pg_an_to_ln -- return the local name corresponding to an authentication
- *               name
- *
- * XXX Assumes that the first aname component is the user name.  This is NOT
- *    necessarily so, since an aname can actually be something out of your
- *    worst X.400 nightmare, like
- *       ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
- *    Note that the MIT an_to_ln code does the same thing if you don't
- *    provide an aname mapping database...it may be a better idea to use
- *    krb5_an_to_ln, except that it punts if multiple components are found,
- *    and we can't afford to punt.
- */
-static char *
-pg_an_to_ln(char *aname)
-{
-   char       *p;
-
-   if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
-       *p = '\0';
-   return aname;
-}
-
-
 /*
  * Various krb5 state which is not connection specfic, and a flag to
  * indicate whether we have initialised it yet.
@@ -216,6 +193,7 @@ pg_krb5_recvauth(Port *port)
    krb5_auth_context auth_context = NULL;
    krb5_ticket *ticket;
    char       *kusername;
+   char       *cp;
 
    if (get_role_line(port->user_name) == NULL)
        return STATUS_ERROR;
@@ -240,8 +218,6 @@ pg_krb5_recvauth(Port *port)
     * The "client" structure comes out of the ticket and is therefore
     * authenticated.  Use it to check the username obtained from the
     * postmaster startup packet.
-    *
-    * I have no idea why this is considered necessary.
     */
 #if defined(HAVE_KRB5_TICKET_ENC_PART2)
    retval = krb5_unparse_name(pg_krb5_context,
@@ -263,7 +239,42 @@ pg_krb5_recvauth(Port *port)
        return STATUS_ERROR;
    }
 
-   kusername = pg_an_to_ln(kusername);
+   cp = strchr(kusername, '@');
+   if (cp)
+   {
+       *cp = '\0';
+       cp++;
+
+       if (pg_krb_realm != NULL && strlen(pg_krb_realm))
+       {
+           /* Match realm against configured */
+           if (pg_krb_caseins_users)
+               ret = pg_strcasecmp(pg_krb_realm, cp);
+           else
+               ret = strcmp(pg_krb_realm, cp);
+
+           if (ret)
+           {
+               elog(DEBUG2,
+                    "krb5 realm (%s) and configured realm (%s) don't match",
+                    cp, pg_krb_realm);
+
+               krb5_free_ticket(pg_krb5_context, ticket);
+               krb5_auth_con_free(pg_krb5_context, auth_context);
+               return STATUS_ERROR;
+           }
+       }
+   }
+   else if (pg_krb_realm && strlen(pg_krb_realm))
+   {
+       elog(DEBUG2,
+            "krb5 did not return realm but realm matching was requested");
+
+       krb5_free_ticket(pg_krb5_context, ticket);
+       krb5_auth_con_free(pg_krb5_context, auth_context);
+       return STATUS_ERROR;
+   }
+
    if (pg_krb_caseins_users)
        ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER);
    else
@@ -509,14 +520,42 @@ pg_GSS_recvauth(Port *port)
                     maj_stat, min_stat);
 
    /*
-    * Compare the part of the username that comes before the @
-    * sign only (ignore realm). The GSSAPI libraries won't have 
-    * authenticated the user if he's from an invalid realm.
+    * Split the username at the realm separator
     */
    if (strchr(gbuf.value, '@'))
    {
        char *cp = strchr(gbuf.value, '@');
        *cp = '\0';
+       cp++;
+
+       if (pg_krb_realm != NULL && strlen(pg_krb_realm))
+       {
+           /*
+            * Match the realm part of the name first
+            */
+           if (pg_krb_caseins_users)
+               ret = pg_strcasecmp(pg_krb_realm, cp);
+           else
+               ret = strcmp(pg_krb_realm, cp);
+
+           if (ret)
+           {
+               /* GSS realm does not match */
+               elog(DEBUG2,
+                    "GSSAPI realm (%s) and configured realm (%s) don't match",
+                    cp, pg_krb_realm);
+               gss_release_buffer(&lmin_s, &gbuf);
+               return STATUS_ERROR;
+           }
+       }
+   }
+   else if (pg_krb_realm && strlen(pg_krb_realm))
+   {
+       elog(DEBUG2,
+            "GSSAPI did not return realm but realm matching was requested");
+
+       gss_release_buffer(&lmin_s, &gbuf);
+       return STATUS_ERROR;
    }
 
    if (pg_krb_caseins_users)
@@ -792,6 +831,21 @@ pg_SSPI_recvauth(Port *port)
 
    free(tokenuser);
 
+   /* 
+    * Compare realm/domain if requested. In SSPI, always compare case insensitive.
+    */
+   if (pg_krb_realm && strlen(pg_krb_realm))
+   {
+       if (pg_strcasecmp(pg_krb_realm, domainname))
+       {
+           elog(DEBUG2,
+                "SSPI domain (%s) and configured domain (%s) don't match",
+                domainname, pg_krb_realm);
+           
+           return STATUS_ERROR;
+       }
+   }
+
    /*
     * We have the username (without domain/realm) in accountname, compare 
     * to the supplied value. In SSPI, always compare case insensitive.
index 64eeaabef3d1d16bba5457e3b981b87d373b0e64..49a4cc722e02337109178d85331c4e23b3b624b9 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.423 2007/09/26 22:36:30 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.424 2007/11/09 17:31:07 mha Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -2043,6 +2043,16 @@ static struct config_string ConfigureNamesString[] =
        "$libdir", NULL, NULL
    },
 
+   {
+       {"krb_realm", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+           gettext_noop("Sets realm to match Kerberos and GSSAPI users against."),
+           NULL,
+           GUC_SUPERUSER_ONLY
+       },
+       &pg_krb_realm,
+       NULL, NULL, NULL
+   },
+
    {
        {"krb_server_keyfile", PGC_POSTMASTER, CONN_AUTH_SECURITY,
            gettext_noop("Sets the location of the Kerberos server key file."),
index 48023bc4ddf8bda474748b4e17db6a1744b90555..3a94829ced151ddb4dad1d97c03fc696eb4c2908 100644 (file)
@@ -85,6 +85,7 @@
 #krb_server_hostname = ''      # empty string matches any keytab entry
                    # (change requires restart, kerberos only)
 #krb_caseins_users = off       # (change requires restart)
+#krb_realm = ''                # (change requires restart)
 
 # - TCP Keepalives -
 # see 'man 7 tcp' for details
index 65c9d512d8494b42818a0d6ffebdd8059e9a4617..da0871d9ffee896bb0c050dacfcb24d7793175da 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/libpq/auth.h,v 1.33 2007/01/05 22:19:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/auth.h,v 1.34 2007/11/09 17:31:07 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@ extern char *pg_krb_server_keyfile;
 extern char *pg_krb_srvnam;
 extern bool pg_krb_caseins_users;
 extern char *pg_krb_server_hostname;
+extern char *pg_krb_realm;
 
 extern void ClientAuthentication(Port *port);