Allow kerberos name and username case sensitivity to be specified from
authorBruce Momjian <[email protected]>
Sat, 4 Jun 2005 20:42:43 +0000 (20:42 +0000)
committerBruce Momjian <[email protected]>
Sat, 4 Jun 2005 20:42:43 +0000 (20:42 +0000)
postgresql.conf.

---------------------------------------------------------------------------

Here's an updated version of the patch, with the following changes:

1) No longer uses "service name" as "application version". It's instead
hardcoded as "postgres". It could be argued that this part should be
backpatched to 8.0, but it doesn't make a big difference until you can
start changing it with GUC / connection parameters. This change only
affects kerberos 5, not 4.

2) Now downcases kerberos usernames when the client is running on win32.

3) Adds guc option for "krb_caseins_users" to make the server ignore
case mismatch which is required by some KDCs such as Active Directory.
Off by default, per discussion with Tom. This change only affects
kerberos 5, not 4.

4) Updated so it doesn't conflict with the rendevouz/bonjour patch
already in ;-)

Magnus Hagander

14 files changed:
configure
configure.in
doc/src/sgml/client-auth.sgml
doc/src/sgml/installation.sgml
doc/src/sgml/libpq.sgml
doc/src/sgml/runtime.sgml
src/backend/libpq/auth.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/libpq/auth.h
src/include/pg_config.h.in
src/interfaces/libpq/fe-auth.c
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/libpq-int.h

index 232015a862f8ce94f072fa6a9c0011f0e1ade2e4..3d33f8c796e5ea049c169a89a36650132170b198 100755 (executable)
--- a/configure
+++ b/configure
@@ -869,7 +869,7 @@ Optional Packages:
   --with-python           build Python modules (PL/Python)
   --with-krb4             build with Kerberos 4 support
   --with-krb5             build with Kerberos 5 support
-  --with-krb-srvnam=NAME  name of the service principal in Kerberos [postgres]
+  --with-krb-srvnam=NAME  name of the default service principal in Kerberos [postgres]
   --with-pam              build with PAM support
   --with-bonjour          build with Bonjour support
   --with-openssl          build with OpenSSL support
index ba449b4272f92a2951609a3f39b2b5aedd901903..a3ff340e7d73062dc63b2b14de939df51b3ab2e2 100644 (file)
@@ -447,11 +447,11 @@ AC_SUBST(krb_srvtab)
 # Kerberos configuration parameters
 #
 PGAC_ARG_REQ(with, krb-srvnam,
-             [  --with-krb-srvnam=NAME  name of the service principal in Kerberos [[postgres]]],
+             [  --with-krb-srvnam=NAME  name of the default service principal in Kerberos [[postgres]]],
              [],
              [with_krb_srvnam="postgres"])
 AC_DEFINE_UNQUOTED([PG_KRB_SRVNAM], ["$with_krb_srvnam"],
-                   [Define to the name of the PostgreSQL service principal in Kerberos. (--with-krb-srvnam=NAME)])
+                   [Define to the name of the default PostgreSQL service principal in Kerberos. (--with-krb-srvnam=NAME)])
 
 
 #
index d94e94d7fec0193b9a4eed784ae6a48c2c736394..bd2cd7f7f3a1c6097b65471b22f171855c231b95 100644 (file)
@@ -617,7 +617,7 @@ local   db1,db2,@demodbs  all                         md5
     quite complex (yet powerful). The 
     <ulink url="http://www.nrl.navy.mil/CCS/people/kenh/kerberos-faq.html">
     Kerberos <acronym>FAQ</></ulink> or 
-    <ulink url="ftp://athena-dist.mit.edu">MIT Project Athena</ulink>
+    <ulink url="http://web.mit.edu/kerberos/www/">MIT Kerberos page</ulink>
     can be a good starting point for exploration.
     Several sources for <productname>Kerberos</> distributions exist.
    </para>
@@ -626,23 +626,29 @@ local   db1,db2,@demodbs  all                         md5
     While <productname>PostgreSQL</> supports both Kerberos 4 and 
     Kerberos 5, only Kerberos 5 is recommended.  Kerberos 4 is
     considered insecure and no longer recommended for general
-    use.
-   </para>
-
-   <para>
-    In order to use <productname>Kerberos</>, support for it must be
-    enabled at build time.  See <xref linkend="installation"> for more
-    information.  Both Kerberos 4 and 5 are supported, but only one
-    version can be supported in any one build.
+    use. Only one version of Kerberos can be supported in any one
+               build, and support must be enabled at build time. See
+               <xref linkend="installation"> for more information.
    </para>
 
    <para>
     <productname>PostgreSQL</> operates like a normal Kerberos service.
     The name of the service principal is
-    <literal><replaceable>servicename</>/<replaceable>hostname</>@<replaceable>realm</></literal>, where
-    <replaceable>servicename</> is <literal>postgres</literal> (unless a
-    different service name was selected at configure time with
-    <literal>./configure --with-krb-srvnam=whatever</>).
+    <literal><replaceable>servicename</>/<replaceable>hostname</>@<replaceable>realm</></literal>.
+        </para>
+         <para>
+    <replaceable>servicename</> can be set on the server side using the
+    <xref linkend="guc-krb-srvname"> configuration parameter, and on the
+    client side using the krbsrvname connection parameter. (See also <xref linkend="libpq-connect">.). The installation default can be changed from the default
+               <literal>postgres</literal> at build time using 
+    <literal>./configure --with-krb-srvnam=whatever</>). In most environments,
+               this parameter never needs to be changed. However, to support multiple
+               <productname>PostgreSQL</> installations on the same host it is necessary.
+               Some Kerberos implementations may also require a different service name,
+               such as Microsoft Active Directory which requires the service name
+               to be in uppercase (<literal>POSTGRES</literal>).
+        </para>
+        <para>
     <replaceable>hostname</> is the fully qualified host name of the
     server machine. The service principal's realm is the preferred realm
     of the server machine.
@@ -658,12 +664,12 @@ local   db1,db2,@demodbs  all                         md5
    </para>
 
    <para>
-    Make sure that your server key file is readable (and preferably
+    Make sure that your server keytab file is readable (and preferably
     only readable) by the <productname>PostgreSQL</productname> server
     account.  (See also <xref linkend="postgres-user">.) The location
     of the key file is specified by the <xref
     linkend="guc-krb-server-keyfile"> configuration
-    parameter. (See also <xref linkend="runtime-config">.) The default
+    parameter. The default
     is <filename>/etc/srvtab</> if you are using Kerberos 4 and
     <filename>/usr/local/pgsql/etc/krb5.keytab</> (or whichever
     directory was specified as <varname>sysconfdir</> at build time)
@@ -671,12 +677,13 @@ local   db1,db2,@demodbs  all                         md5
    </para>
 
    <para>
-    To generate the keytab file, use for example (with version 5)
+         The keytab file is generated in the Kerberos system, see the 
+               Kerberos documentation for details. The following example is 
+               for MIT-compatible Kerberos 5 implementations:
 <screen>
 <prompt>kadmin% </><userinput>ank -randkey postgres/server.my.domain.org</>
 <prompt>kadmin% </><userinput>ktadd -k krb5.keytab postgres/server.my.domain.org</>
 </screen>
-    Read the <productname>Kerberos</> documentation for details.
    </para>
 
    <para>
index 6896337284a456da79e7a2c4d32255de2370b5af..b5d6740e2b881d999ca41f29cadfc44a047c287f 100644 (file)
@@ -816,8 +816,8 @@ su - postgres
        <term><option>--with-krb-srvnam=<replaceable>NAME</></option></term>
        <listitem>
         <para>
-         The name of the Kerberos service principal.
-         <literal>postgres</literal> is the default. There's probably no
+         The default name of the Kerberos service principal.
+         <literal>postgres</literal> is the default. There's usually no
          reason to change this.
         </para>
        </listitem>
index 0f7f58ec7ac2eca1ceafd30687a2ef645cf0789d..84393566918c91dc0bdb1d697090c8c4cd644748 100644 (file)
@@ -279,6 +279,18 @@ PGconn *PQconnectdb(const char *conninfo);
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><literal>krbsrvname</literal></term>
+     <listitem>
+      <para>
+       Kerberos service name to use when authenticating with Kerberos 4 or 5.
+       This must match the service name specified in the server
+       configuration for Kerberos authentication to succeed. (See also
+                        <xref linkend="kerberos-auth">.)
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><literal>service</literal></term>
      <listitem>
@@ -3770,6 +3782,15 @@ setting, and is only available if
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGKRBSRVNAME</envar></primary>
+</indexterm>
+<envar>PGKRBSRVNAME</envar> sets the Kerberos service name to use when
+authenticating with Kerberos 4 or 5.
+</para>
+</listitem>
+<listitem>
+<para>
 <indexterm>
  <primary><envar>PGCONNECT_TIMEOUT</envar></primary>
 </indexterm>
index 6544ded2932a30fb8cf7ecdf685e52d4e6a3b85d..9eaab4f2517cf2984887f3ebf8503523369c5fb3 100644 (file)
@@ -955,11 +955,39 @@ SET ENABLE_SEQSCAN TO OFF;
       <listitem>
        <para>
         Sets the location of the Kerberos server key file. See
-        <xref linkend="kerberos-auth"> for details.
+        <xref linkend="kerberos-auth"> for details. This parameter
+               can only be set at server start.
        </para>
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-krb-srvname" xreflabel="krb_srvname">
+      <term><varname>krb_srvname</varname> (<type>string</type>)</term>
+      <indexterm>
+       <primary><varname>krb_srvname</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Sets the Kerberos service name. See <xref linkend="kerberos-auth">
+        for details. This parameter can only be set at server start.
+       </para>
+      </listitem>
+     </varlistentry>
+
+        <varlistentry id="guc-krb-caseins-users" xreflabel="krb_caseins_users">
+         <term><varname>krb_caseins_users</varname> (<type>boolean</type>)</term>
+         <indexterm>
+          <primary><varname>krb_caseins_users</varname> configuration parameter</primary>
+      </indexterm>
+         <listitem>
+          <para>
+           Sets if Kerberos usernames should be treated case-insensitive.
+               The default is off (case sensitive). This parameter can only be
+               set at server start.
+       </para>
+         </listitem>
+        </varlistentry>
+
      <varlistentry id="guc-db-user-namespace" xreflabel="db_user_namespace">
       <term><varname>db_user_namespace</varname> (<type>boolean</type>)</term>
       <indexterm>
index 1efde724ab69be026080b4fa7865c87c3ae59997..88523099a58bc4d68083dbb5ef234501033ce603 100644 (file)
@@ -41,6 +41,8 @@ static char *recv_password_packet(Port *port);
 static int     recv_and_check_password_packet(Port *port);
 
 char      *pg_krb_server_keyfile;
+char       *pg_krb_srvnam;
+bool           pg_krb_caseins_users;
 
 #ifdef USE_PAM
 #ifdef HAVE_PAM_PAM_APPL_H
@@ -99,7 +101,7 @@ pg_krb4_recvauth(Port *port)
        status = krb_recvauth(krbopts,
                                                  port->sock,
                                                  &clttkt,
-                                                 PG_KRB_SRVNAM,
+                                                 pg_krb_srvnam,
                                                  instance,
                                                  &port->raddr.in,
                                                  &port->laddr.in,
@@ -219,16 +221,16 @@ pg_krb5_init(void)
                return STATUS_ERROR;
        }
 
-       retval = krb5_sname_to_principal(pg_krb5_context, NULL, PG_KRB_SRVNAM,
+       retval = krb5_sname_to_principal(pg_krb5_context, NULL, pg_krb_srvnam,
                                                                         KRB5_NT_SRV_HST, &pg_krb5_server);
        if (retval)
        {
                ereport(LOG,
                 (errmsg("Kerberos sname_to_principal(\"%s\") returned error %d",
-                                PG_KRB_SRVNAM, retval)));
+                                pg_krb_srvnam, retval)));
                com_err("postgres", retval,
                                "while getting server principal for service \"%s\"",
-                               PG_KRB_SRVNAM);
+                               pg_krb_srvnam);
                krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
                krb5_free_context(pg_krb5_context);
                return STATUS_ERROR;
@@ -264,7 +266,7 @@ pg_krb5_recvauth(Port *port)
                return ret;
 
        retval = krb5_recvauth(pg_krb5_context, &auth_context,
-                                                  (krb5_pointer) & port->sock, PG_KRB_SRVNAM,
+                                                  (krb5_pointer) & port->sock, "postgres",
                                                   pg_krb5_server, 0, pg_krb5_keytab, &ticket);
        if (retval)
        {
@@ -303,7 +305,11 @@ pg_krb5_recvauth(Port *port)
        }
 
        kusername = pg_an_to_ln(kusername);
-       if (strncmp(port->user_name, kusername, SM_DATABASE_USER))
+       if (pg_krb_caseins_users)
+               ret = strncasecmp(port->user_name, kusername, SM_DATABASE_USER);
+       else
+               ret = strncmp(port->user_name, kusername, SM_DATABASE_USER);
+       if (ret)
        {
                ereport(LOG,
                                (errmsg("unexpected Kerberos user name received from client (received \"%s\", expected \"%s\")",
index e10eca51530f68ecdec1c35dcefd3dcb67ab7956..2f92ed8e7640493f7c1a9cc8e0aa39f5e66b518b 100644 (file)
@@ -63,6 +63,9 @@
 #ifndef PG_KRB_SRVTAB
 #define PG_KRB_SRVTAB ""
 #endif
+#ifndef PG_KRB_SRVNAM
+#define PG_KRB_SRVNAM ""
+#endif
 
 #define CONFIG_FILENAME        "postgresql.conf"
 #define HBA_FILENAME   "pg_hba.conf"
@@ -860,6 +863,15 @@ static struct config_bool ConfigureNamesBool[] =
 #endif
        },
 
+       {
+               {"krb_caseins_users", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+                       gettext_noop("Sets if Kerberos user names should be treated case insensitive."),
+                       NULL
+               },
+               &pg_krb_caseins_users,
+               false, NULL, NULL
+       },
+
        /* End-of-list marker */
        {
                {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL
@@ -1572,6 +1584,15 @@ static struct config_string ConfigureNamesString[] =
                PG_KRB_SRVTAB, NULL, NULL
        },
 
+       {
+               {"krb_srvname", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+                       gettext_noop("Sets the name of the Kerberos service."),
+                       NULL
+               },
+               &pg_krb_srvnam,
+               PG_KRB_SRVNAM, NULL, NULL
+       },
+
        {
                {"bonjour_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
                        gettext_noop("Sets the Bonjour broadcast service name."),
index 0e88d4c5ed09b4536699fc012f2e7304b2dba5ed..d54ae5fcfda19ffc4616e912d53ef99ad982448e 100644 (file)
 #authentication_timeout = 60   # 1-600, in seconds
 #ssl = false
 #password_encryption = true
-#krb_server_keyfile = ''
 #db_user_namespace = false
+# Kerberos
+#krb_server_keyfile = ''
+#krb_caseins_users = false
+#krb_srvname = 'postgres'
 
 
 #---------------------------------------------------------------------------
index d1dd5b2945954809b27637516b3c455b0b08c9ab..66aa55829abff3b410b668718b7d6d50f31839f8 100644 (file)
@@ -27,5 +27,7 @@ extern void ClientAuthentication(Port *port);
 #define PG_KRB5_VERSION "PGVER5.1"
 
 extern char *pg_krb_server_keyfile;
+extern char *pg_krb_srvnam;
+extern bool pg_krb_caseins_users;
 
 #endif   /* AUTH_H */
index 51a13907bb0d7d9865b89ddde26c59d8226398c4..da29557e9271f2373354ddaa7bea53699d370209 100644 (file)
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
-/* Define to the name of the PostgreSQL service principal in Kerberos.
+/* Define to the name of the default PostgreSQL service principal in Kerberos.
    (--with-krb-srvnam=NAME) */
 #undef PG_KRB_SRVNAM
 
 /* Define to 1 to build with assertion checks. (--enable-cassert) */
 #undef USE_ASSERT_CHECKING
 
+/* Define to 1 to build with Bonjour support. (--with-bonjour) */
+#undef USE_BONJOUR
+
 /* Define to 1 if you want 64-bit integer timestamp and interval support.
    (--enable-integer-datetimes) */
 #undef USE_INTEGER_DATETIMES
 /* Define to 1 to build with PAM support. (--with-pam) */
 #undef USE_PAM
 
-/* Define to 1 to build with Bonjour support. (--with-bonjour) */
-#undef USE_BONJOUR
-
 /* Use replacement snprintf() functions. */
 #undef USE_SNPRINTF
 
index 9c43cc298ae2281e545cdb0aeb7f325d94f3fdd5..8d4beb43fbc9b68ca1b405e99e20672a0369bbec 100644 (file)
@@ -196,7 +196,8 @@ static int
 pg_krb4_sendauth(char *PQerrormsg, int sock,
                                 struct sockaddr_in * laddr,
                                 struct sockaddr_in * raddr,
-                                const char *hostname)
+                                const char *hostname, 
+                                const char *servicename)
 {
        long            krbopts = 0;    /* one-way authentication */
        KTEXT_ST        clttkt;
@@ -216,7 +217,7 @@ pg_krb4_sendauth(char *PQerrormsg, int sock,
        status = krb_sendauth(krbopts,
                                                  sock,
                                                  &clttkt,
-                                                 PG_KRB_SRVNAM,
+                                                 servicename,
                                                  hostname,
                                                  realm,
                                                  (u_long) 0,
@@ -260,6 +261,10 @@ pg_krb4_sendauth(char *PQerrormsg, int sock,
  *        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.
+ *
+ * For WIN32, convert username to lowercase because the Win32 kerberos library
+ * generates tickets with the username as the user entered it instead of as
+ * it is entered in the directory.
  */
 static char *
 pg_an_to_ln(char *aname)
@@ -268,6 +273,11 @@ pg_an_to_ln(char *aname)
 
        if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
                *p = '\0';
+#ifdef WIN32
+       for (p = aname; *p ; p++)
+               *p = pg_tolower(*p);
+#endif
+
        return aname;
 }
 
@@ -360,7 +370,7 @@ pg_krb5_authname(char *PQerrormsg)
  *                                        the server
  */
 static int
-pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname)
+pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname, const char *servicename)
 {
        krb5_error_code retval;
        int                     ret;
@@ -379,7 +389,7 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname)
        if (ret != STATUS_OK)
                return ret;
 
-       retval = krb5_sname_to_principal(pg_krb5_context, hostname, PG_KRB_SRVNAM,
+       retval = krb5_sname_to_principal(pg_krb5_context, hostname, servicename,
                                                                         KRB5_NT_SRV_HST, &server);
        if (retval)
        {
@@ -405,7 +415,7 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname)
        }
 
        retval = krb5_sendauth(pg_krb5_context, &auth_context,
-                                                  (krb5_pointer) & sock, PG_KRB_SRVNAM,
+                                                  (krb5_pointer) & sock, "postgres",
                                                   pg_krb5_client, server,
                                                   AP_OPTS_MUTUAL_REQUIRED,
                                                   NULL, 0,             /* no creds, use ccache instead */
@@ -602,7 +612,7 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
                        if (pg_krb4_sendauth(PQerrormsg, conn->sock,
                                                           (struct sockaddr_in *) & conn->laddr.addr,
                                                           (struct sockaddr_in *) & conn->raddr.addr,
-                                                                hostname) != STATUS_OK)
+                                                                hostname, conn->krbsrvname) != STATUS_OK)
                        {
                                /* PQerrormsg already filled in */
                                pgunlock_thread();
@@ -620,7 +630,7 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
 #ifdef KRB5
                        pglock_thread();
                        if (pg_krb5_sendauth(PQerrormsg, conn->sock,
-                                                                hostname) != STATUS_OK)
+                                                                hostname, conn->krbsrvname) != STATUS_OK)
                        {
                                /* PQerrormsg already filled in */
                                pgunlock_thread();
index e8eb036deccb980c0baa75582d879814f47f48f5..07157a3403c6eecf3aca50fe13e0fc5eed9ad203 100644 (file)
@@ -170,6 +170,12 @@ static const PQconninfoOption PQconninfoOptions[] = {
        {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
        "SSL-Mode", "", 8},                     /* sizeof("disable") == 8 */
 
+#if defined(KRB4) || defined(KRB5)
+       /* Kerberos authentication supports specifying the service name */
+       {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
+        "Kerberos-service-name", "", 20},
+#endif
+
        /* Terminating entry --- MUST BE LAST */
        {NULL, NULL, NULL, NULL,
        NULL, NULL, 0}
@@ -393,6 +399,10 @@ connectOptions1(PGconn *conn, const char *conninfo)
                conn->sslmode = strdup("require");
        }
 #endif
+#if defined(KRB4) || defined(KRB5)
+       tmp = conninfo_getval(connOptions, "krbsrvname");
+       conn->krbsrvname = tmp ? strdup(tmp) : NULL;
+#endif
 
        /*
         * Free the option info - all is in conn now
@@ -2074,6 +2084,10 @@ freePGconn(PGconn *conn)
                free(conn->pgpass);
        if (conn->sslmode)
                free(conn->sslmode);
+#if defined(KRB4) || defined(KRB5)
+       if (conn->krbsrvname)
+               free(conn->krbsrvname);
+#endif
        /* Note that conn->Pfdebug is not ours to close or free */
        notify = conn->notifyHead;
        while (notify != NULL)
index 407e8c551758b1b7164374bda00ab2a5304fa4cc..fb60edb01ed8111e754759b123539a0c34e4cd74 100644 (file)
@@ -261,6 +261,9 @@ struct pg_conn
        char       *pguser;                     /* Postgres username and password, if any */
        char       *pgpass;
        char       *sslmode;            /* SSL mode (require,prefer,allow,disable) */
+#if defined(KRB5) || defined(KRB4)
+       char       *krbsrvname;     /* Kerberos service name */
+#endif
 
        /* Optional file to write trace info to */
        FILE       *Pfdebug;