Re: patch to add krb_server_hostname to postgresql.conf - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: patch to add krb_server_hostname to postgresql.conf
Date
Msg-id 200506141743.j5EHhlc16408@candle.pha.pa.us
Whole thread Raw
In response to Re: patch to add krb_server_hostname to postgresql.conf  (Todd Kover <kovert@omniscient.com>)
List pgsql-patches
Second patch applied:

    Add GUC krb_server_hostname so the server hostname can be specified as
    part of service principal.  If not set, any service principal matching
    an entry in the keytab can be used.

I updated your documentation to reflect this.

Thanks.

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

Todd Kover wrote:
>  > Todd Kover <kovert@omniscient.com> writes:
>  >
>  > > The attached patch adds a directive to the config file,
>  > > krb_server_hostname that allows the hostname that service tickets
>  > > are obtained against to be different from the hostname of the db
>  > > server.
>  >
>  > Why is this necessary?
>
> It's largely useful in combination with restricting the interfaces
> listened to via the listen_addresses directive in the config file.  As
> the code works now you can only connect via kerberos with a service
> principal derived from the hostname of the box rather than any dns name
> associated with any of the box's interfaces.
>
> For example, if the server is named server0.example.com, but the db is
> bound to db.example.com via the listen_addresses directive, the pgsql
> server won't authenticate properly.
>
> Similarly, if server0.example.com is one interface and
> server1.example.com is another, and the hostname is server.example.com
> but doesn't correspond to any interfaces, connecting to neither will
> work.
>
>  > If it is necessary, wouldn't something similar be needed at the
>  > client end as well?
>
> No.  The decision of which principal to obtain a service ticket for is
> based on what it connects to.
>
> In the first above example, if running:
>
>     psql -h server0.example.com
>
> the client would obtain a service ticket for
> postgres/server0.example.com.  If running:
>
>     psql -h db.example.com
>
> it would obtain a service ticket for postgres/db.example.com, and
> without the directive I'm adding, it would fail to establish a
> connection because the server wouldn't be expecting that.  Of course,
> adding the directive would make the first case fail and the second
> pass.  This works fine for our environment since we're binding to
> db.example.com.
>
> (as an aside, it's actually a bit more complicated then this since the
> way the kerberos libraries are used, db.example.com is canonicalized, so
> if it were a CNAME for server0.example.com it would do the right thing,
> but we're using an A record).
>
>  > I'd have thought that host information would be established by some
>  > sort of system-wide configuration file, not by per-program options.
>
> Different applications can use different service principals.  The use
> of the hostname in the principal name at all is an application-specific
> decision.  The krb5 api encourages it to be a DNS hostname pretty
> strongly in the way it works, but it's not cast in stone.
>
> However, other kerberos clients will accept using any kerberos principal
> in the keytab but postgresql as shipped requires it to match the
> hostname.  If you want that behavior instead, then change pg_krb5_server
> to NULL when calling krb5_recvauth in src/backend/libpq/auth.c and it
> won't require that the hostnames match. (but it's still necessary for
> something to match).
>
> The second patch (kovert-krb5-patch-newbehavior.txt) makes the default
> behavior to accept any principal in the keytab.  This means that people
> using kerberos will continue to work, but they'll be slightly more broad
> in what they accept as a valid service principal (I suspect there's very
> few people in the world who care about this since it still needs to be
> something in the keytab).
>
> I left the implementation of krb_server_hostname so that someone can
> define this if they want. (and if they want to make it behave like
> versions of pgsql up until now, they'd need to set it to the hostname).
>
> The second patch's default case makes pgsql match the behavior of
> eklogind (kerberized rlogind that ships with MIT kerberos) and the
> gssapi/krb5-aware version of sshd and probably numerous other things.
>
>  > Also, the available documentation says that PG_KRB_SRVNAM is a
>  > service name, not a host name, so I feel like there's something wrong
>  > with your description of what you're doing.
>
> indeed, there was something wrong with what I was doing.  PG_KRB_SRVNAM
> defaults to 'postgres' rather than the hostname.  This was fallout from
> when I was first developing the patch.
>
> The absence of the krb_server_hostname config flag should have left the
> default behavior in place, it wasn't.  I just tested this patch against
> both cases on a dev box and it works as expected.
>
> both patches are against 8.0.0rc3.  The first implements what I
> originally was doing without changing the default, the second changes
> the default to be more accepting and also implements the directive in
> case someone wants to go back to the old behavior.
>
> -Todd
>

> Index: doc/src/sgml/runtime.sgml
> ===================================================================
> RCS file: postgresql-8.0.0rc3/doc/src/sgml/runtime.sgml,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- doc/src/sgml/runtime.sgml    26 Dec 2004 23:06:56 -0000    1.1.1.1
> +++ doc/src/sgml/runtime.sgml    3 Jan 2005 23:18:44 -0000    1.2
> @@ -952,6 +952,20 @@
>        </listitem>
>       </varlistentry>
>
> +     <varlistentry id="guc-krb_server_hostname" xreflabel="krb_server_hostname">
> +      <term><varname>krb_server_hostname</varname> (<type>string</type>)</term>
> +      <indexterm>
> +       <primary><varname>krb_server_hostname</> configuration parameter</primary>
> +      </indexterm>
> +      <listitem>
> +       <para>
> +        Sets the hostname that service tickets will be obtained against
> +    (defaults to the hostname of the postgresql server)
> +        <xref linkend="kerberos-auth"> for details.
> +       </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: src/backend/libpq/auth.c
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/backend/libpq/auth.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.3
> diff -u -r1.1.1.1 -r1.3
> --- src/backend/libpq/auth.c    31 Dec 2004 21:59:50 -0000    1.1.1.1
> +++ src/backend/libpq/auth.c    4 Jan 2005 11:14:08 -0000    1.3
> @@ -41,6 +41,7 @@
>  static int    recv_and_check_password_packet(Port *port);
>
>  char       *pg_krb_server_keyfile;
> +char       *pg_krb_server_hostname = NULL;
>
>  #ifdef USE_PAM
>  #ifdef HAVE_PAM_PAM_APPL_H
> @@ -215,9 +222,10 @@
>          return STATUS_ERROR;
>      }
>
> -    retval = krb5_sname_to_principal(pg_krb5_context, NULL, PG_KRB_SRVNAM,
> -                                     KRB5_NT_SRV_HST, &pg_krb5_server);
> -    if (retval)
> +    retval = krb5_sname_to_principal(pg_krb5_context,
> +                pg_krb_server_hostname, PG_KRB_SRVNAM,
> +                 KRB5_NT_SRV_HST, &pg_krb5_server);
> +     if (retval)
>      {
>          ereport(LOG,
>           (errmsg("Kerberos sname_to_principal(\"%s\") returned error %d",
> Index: src/backend/utils/misc/guc.c
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/backend/utils/misc/guc.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- src/backend/utils/misc/guc.c    20 Dec 2004 18:15:07 -0000    1.1.1.1
> +++ src/backend/utils/misc/guc.c    3 Jan 2005 14:59:45 -0000    1.2
> @@ -1546,6 +1546,15 @@
>      },
>
>      {
> +        {"krb_server_hostname", PGC_POSTMASTER, CONN_AUTH_SECURITY,
> +            gettext_noop("Sets the hostname of the Kerberos server."),
> +            NULL
> +        },
> +        &pg_krb_server_hostname,
> +        NULL, NULL, NULL
> +    },
> +
> +    {
>          {"rendezvous_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
>              gettext_noop("Sets the Rendezvous broadcast service name."),
>              NULL
> Index: src/bin/psql/tab-complete.c
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/bin/psql/tab-complete.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- src/bin/psql/tab-complete.c    24 Dec 2004 15:42:05 -0000    1.1.1.1
> +++ src/bin/psql/tab-complete.c    3 Jan 2005 14:59:46 -0000    1.2
> @@ -552,6 +552,7 @@
>          "geqo_threshold",
>          "join_collapse_limit",
>          "krb_server_keyfile",
> +        "krb_server_hostname",
>          "lc_messages",
>          "lc_monetary",
>          "lc_numeric",
> Index: src/include/libpq/auth.h
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/include/libpq/auth.h,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- src/include/libpq/auth.h    31 Dec 2004 22:03:32 -0000    1.1.1.1
> +++ src/include/libpq/auth.h    3 Jan 2005 14:59:47 -0000    1.2
> @@ -27,5 +27,6 @@
>  #define PG_KRB5_VERSION "PGVER5.1"
>
>  extern char *pg_krb_server_keyfile;
> +extern char *pg_krb_server_hostname;
>
>  #endif   /* AUTH_H */

> Index: doc/src/sgml/runtime.sgml
> ===================================================================
> RCS file: postgresql-8.0.0rc3/doc/src/sgml/runtime.sgml,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- doc/src/sgml/runtime.sgml    26 Dec 2004 23:06:56 -0000    1.1.1.1
> +++ doc/src/sgml/runtime.sgml    3 Jan 2005 23:18:44 -0000    1.2
> @@ -952,6 +952,20 @@
>        </listitem>
>       </varlistentry>
>
> +     <varlistentry id="guc-krb_server_hostname" xreflabel="krb_server_hostname">
> +      <term><varname>krb_server_hostname</varname> (<type>string</type>)</term>
> +      <indexterm>
> +       <primary><varname>krb_server_hostname</> configuration parameter</primary>
> +      </indexterm>
> +      <listitem>
> +       <para>
> +        Sets the hostname that service tickets will be obtained against
> +    (the default is any accept any service principal in the keytab)
> +        <xref linkend="kerberos-auth"> for details.
> +       </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: src/backend/libpq/auth.c
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/backend/libpq/auth.c,v
> retrieving revision 1.1.1.1
> diff -u -r1.1.1.1 auth.c
> --- src/backend/libpq/auth.c    31 Dec 2004 21:59:50 -0000    1.1.1.1
> +++ src/backend/libpq/auth.c    4 Jan 2005 12:09:45 -0000
> @@ -41,6 +41,7 @@
>  static int    recv_and_check_password_packet(Port *port);
>
>  char       *pg_krb_server_keyfile;
> +char       *pg_krb_server_hostname = NULL;
>
>  #ifdef USE_PAM
>  #ifdef HAVE_PAM_PAM_APPL_H
> @@ -215,19 +216,24 @@
>          return STATUS_ERROR;
>      }
>
> -    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)));
> -        com_err("postgres", retval,
> -                "while getting server principal for service \"%s\"",
> -                PG_KRB_SRVNAM);
> -        krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
> -        krb5_free_context(pg_krb5_context);
> -        return STATUS_ERROR;
> +    if(pg_krb_server_hostname) {
> +        retval = krb5_sname_to_principal(pg_krb5_context,
> +                    pg_krb_server_hostname, 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)));
> +            com_err("postgres", retval,
> +                    "while getting server principal for service \"%s\"",
> +                    PG_KRB_SRVNAM);
> +            krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
> +            krb5_free_context(pg_krb5_context);
> +            return STATUS_ERROR;
> +        }
> +    } else {
> +        pg_krb5_server = NULL;
>      }
>
>      pg_krb5_initialised = 1;
> Index: src/backend/utils/misc/guc.c
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/backend/utils/misc/guc.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- src/backend/utils/misc/guc.c    20 Dec 2004 18:15:07 -0000    1.1.1.1
> +++ src/backend/utils/misc/guc.c    3 Jan 2005 14:59:45 -0000    1.2
> @@ -1546,6 +1546,15 @@
>      },
>
>      {
> +        {"krb_server_hostname", PGC_POSTMASTER, CONN_AUTH_SECURITY,
> +            gettext_noop("Sets the hostname of the Kerberos server."),
> +            NULL
> +        },
> +        &pg_krb_server_hostname,
> +        NULL, NULL, NULL
> +    },
> +
> +    {
>          {"rendezvous_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
>              gettext_noop("Sets the Rendezvous broadcast service name."),
>              NULL
> Index: src/bin/psql/tab-complete.c
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/bin/psql/tab-complete.c,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- src/bin/psql/tab-complete.c    24 Dec 2004 15:42:05 -0000    1.1.1.1
> +++ src/bin/psql/tab-complete.c    3 Jan 2005 14:59:46 -0000    1.2
> @@ -552,6 +552,7 @@
>          "geqo_threshold",
>          "join_collapse_limit",
>          "krb_server_keyfile",
> +        "krb_server_hostname",
>          "lc_messages",
>          "lc_monetary",
>          "lc_numeric",
> Index: src/include/libpq/auth.h
> ===================================================================
> RCS file: postgresql-8.0.0rc3/src/include/libpq/auth.h,v
> retrieving revision 1.1.1.1
> retrieving revision 1.2
> diff -u -r1.1.1.1 -r1.2
> --- src/include/libpq/auth.h    31 Dec 2004 22:03:32 -0000    1.1.1.1
> +++ src/include/libpq/auth.h    3 Jan 2005 14:59:47 -0000    1.2
> @@ -27,5 +27,6 @@
>  #define PG_KRB5_VERSION "PGVER5.1"
>
>  extern char *pg_krb_server_keyfile;
> +extern char *pg_krb_server_hostname;
>
>  #endif   /* AUTH_H */

>
> ---------------------------(end of broadcast)---------------------------
> TIP 8: explain analyze is your friend

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/runtime.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v
retrieving revision 1.325
diff -c -c -r1.325 runtime.sgml
*** doc/src/sgml/runtime.sgml    13 Jun 2005 02:40:06 -0000    1.325
--- doc/src/sgml/runtime.sgml    14 Jun 2005 17:39:22 -0000
***************
*** 969,992 ****
        <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>
--- 969,1012 ----
        <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-krb-server-hostname" xreflabel="krb_server_hostname">
!       <term><varname>krb_server_hostname</varname> (<type>string</type>)</term>
!       <indexterm>
!        <primary><varname>krb_server_hostname</> configuration parameter</primary>
!       </indexterm>
!       <listitem>
!        <para>
!         Sets the hostname part of the service principal.
!         This, combined with <varname>krb_srvname</>, is used to generate
!         the complete service principal, i.e.
!         <varname>krb_server_hostname</><literal>/</><varname>krb_server_hostname</><literal>@</>REALM.
!        </para>
!        <para>
!         If not set, the default is to allow any service principal matching an entry
!         in the keytab.  See <xref linkend="kerberos-auth"> for details.
!         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>
Index: src/backend/libpq/auth.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/libpq/auth.c,v
retrieving revision 1.124
diff -c -c -r1.124 auth.c
*** src/backend/libpq/auth.c    4 Jun 2005 20:42:42 -0000    1.124
--- src/backend/libpq/auth.c    14 Jun 2005 17:39:23 -0000
***************
*** 43,48 ****
--- 43,49 ----
  char       *pg_krb_server_keyfile;
  char       *pg_krb_srvnam;
  bool        pg_krb_caseins_users;
+ char       *pg_krb_server_hostname = NULL;

  #ifdef USE_PAM
  #ifdef HAVE_PAM_PAM_APPL_H
***************
*** 221,240 ****
          return STATUS_ERROR;
      }

!     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)));
!         com_err("postgres", retval,
!                 "while getting server principal for service \"%s\"",
!                 pg_krb_srvnam);
!         krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
!         krb5_free_context(pg_krb5_context);
!         return STATUS_ERROR;
!     }

      pg_krb5_initialised = 1;
      return STATUS_OK;
--- 222,246 ----
          return STATUS_ERROR;
      }

!     if (pg_krb_server_hostname)
      {
!         retval = krb5_sname_to_principal(pg_krb5_context,
!                     pg_krb_server_hostname, 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)));
!             com_err("postgres", retval,
!                     "while getting server principal for service \"%s\"",
!                     pg_krb_srvnam);
!             krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
!             krb5_free_context(pg_krb5_context);
!             return STATUS_ERROR;
!         }
!     } else
!         pg_krb5_server = NULL;

      pg_krb5_initialised = 1;
      return STATUS_OK;
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.264
diff -c -c -r1.264 guc.c
*** src/backend/utils/misc/guc.c    4 Jun 2005 20:42:42 -0000    1.264
--- src/backend/utils/misc/guc.c    14 Jun 2005 17:39:27 -0000
***************
*** 1594,1599 ****
--- 1594,1608 ----
      },

      {
+         {"krb_server_hostname", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+             gettext_noop("Sets the hostname of the Kerberos server."),
+             NULL
+         },
+         &pg_krb_server_hostname,
+         NULL, NULL, NULL
+     },
+
+     {
          {"bonjour_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
              gettext_noop("Sets the Bonjour broadcast service name."),
              NULL
Index: src/bin/psql/tab-complete.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v
retrieving revision 1.130
diff -c -c -r1.130 tab-complete.c
*** src/bin/psql/tab-complete.c    25 May 2005 22:12:05 -0000    1.130
--- src/bin/psql/tab-complete.c    14 Jun 2005 17:39:28 -0000
***************
*** 559,565 ****
          "geqo_selection_bias",
          "geqo_threshold",
          "join_collapse_limit",
-         "krb_server_keyfile",
          "lc_messages",
          "lc_monetary",
          "lc_numeric",
--- 559,564 ----
Index: src/include/libpq/auth.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/libpq/auth.h,v
retrieving revision 1.27
diff -c -c -r1.27 auth.h
*** src/include/libpq/auth.h    4 Jun 2005 20:42:42 -0000    1.27
--- src/include/libpq/auth.h    14 Jun 2005 17:39:29 -0000
***************
*** 29,33 ****
--- 29,34 ----
  extern char *pg_krb_server_keyfile;
  extern char *pg_krb_srvnam;
  extern bool pg_krb_caseins_users;
+ extern char *pg_krb_server_hostname;

  #endif   /* AUTH_H */

pgsql-patches by date:

Previous
From: Atsushi Ogawa
Date:
Subject: replace_text() improvement
Next
From: Bruce Momjian
Date:
Subject: Re: pg_config MSVC makefile