Overriding Kerberos parameters - Mailing list pgsql-hackers

From Magnus Hagander
Subject Overriding Kerberos parameters
Date
Msg-id 495E06AF.5060405@hagander.net
Whole thread Raw
List pgsql-hackers
I've for some reason been sitting on this patch for a while, it was
supposed to be a part of the pg_hba changes from a few months ago.

Anyway. Here's a patch that makes it possible to set krb_realm and
krb_server_hostname on a per-hba-row basis, instead of just for the
whole server.

Comments?

//Magnus
*** a/doc/src/sgml/client-auth.sgml
--- b/doc/src/sgml/client-auth.sgml
***************
*** 784,789 **** omicron       bryanh            guest1
--- 784,809 ----
         </para>
        </listitem>
       </varlistentry>
+
+      <varlistentry>
+       <term>krb_realm</term>
+       <listitem>
+        <para>
+         Overrides the <xref linkend="guc-krb-realm"> parameter, setting which realm
+         to verify the authenticated user principal against.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>krb_server_hostname</term>
+       <listitem>
+        <para>
+         Overrides the <xref linkend="guc-krb-server-hostname"> parameter, setting which
+         hostname will be used for the server principal when using Kerberos.
+        </para>
+       </listitem>
+      </varlistentry>
      </variablelist>
     </para>
    </sect2>
***************
*** 825,830 **** omicron       bryanh            guest1
--- 845,860 ----
         </para>
        </listitem>
       </varlistentry>
+
+      <varlistentry>
+       <term>krb_realm</term>
+       <listitem>
+        <para>
+         Overrides the <xref linkend="guc-krb-realm"> parameter, setting which realm
+         to verify the authenticated user principal against.
+        </para>
+       </listitem>
+      </varlistentry>
      </variablelist>
     </para>
    </sect2>
*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***************
*** 611,617 **** recv_and_check_password_packet(Port *port)
  #ifdef KRB5

  static int
! pg_krb5_init(void)
  {
      krb5_error_code retval;
      char       *khostname;
--- 611,617 ----
  #ifdef KRB5

  static int
! pg_krb5_init(Port *port)
  {
      krb5_error_code retval;
      char       *khostname;
***************
*** 645,651 **** pg_krb5_init(void)
       * If no hostname was specified, pg_krb_server_hostname is already NULL.
       * If it's set to blank, force it to NULL.
       */
!     khostname = pg_krb_server_hostname;
      if (khostname && khostname[0] == '\0')
          khostname = NULL;

--- 645,654 ----
       * If no hostname was specified, pg_krb_server_hostname is already NULL.
       * If it's set to blank, force it to NULL.
       */
!     if (port->hba->krb_server_hostname)
!         khostname = port->hba->krb_server_hostname;
!     else
!         khostname = pg_krb_server_hostname;
      if (khostname && khostname[0] == '\0')
          khostname = NULL;

***************
*** 691,701 **** pg_krb5_recvauth(Port *port)
      krb5_ticket *ticket;
      char       *kusername;
      char       *cp;

      if (get_role_line(port->user_name) == NULL)
          return STATUS_ERROR;

!     ret = pg_krb5_init();
      if (ret != STATUS_OK)
          return ret;

--- 694,705 ----
      krb5_ticket *ticket;
      char       *kusername;
      char       *cp;
+     char       *realmmatch;

      if (get_role_line(port->user_name) == NULL)
          return STATUS_ERROR;

!     ret = pg_krb5_init(port);
      if (ret != STATUS_OK)
          return ret;

***************
*** 736,760 **** pg_krb5_recvauth(Port *port)
          return STATUS_ERROR;
      }

      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);
--- 740,769 ----
          return STATUS_ERROR;
      }

+     if (port->hba->krb_realm)
+         realmmatch = port->hba->krb_realm;
+     else
+         realmmatch = pg_krb_realm;
+
      cp = strchr(kusername, '@');
      if (cp)
      {
          *cp = '\0';
          cp++;

!         if (realmmatch != NULL && strlen(realmmatch))
          {
              /* Match realm against configured */
              if (pg_krb_caseins_users)
!                 ret = pg_strcasecmp(realmmatch, cp);
              else
!                 ret = strcmp(realmmatch, cp);

              if (ret)
              {
                  elog(DEBUG2,
                       "krb5 realm (%s) and configured realm (%s) don't match",
!                      cp, realmmatch);

                  krb5_free_ticket(pg_krb5_context, ticket);
                  krb5_auth_con_free(pg_krb5_context, auth_context);
***************
*** 762,768 **** pg_krb5_recvauth(Port *port)
              }
          }
      }
!     else if (pg_krb_realm && strlen(pg_krb_realm))
      {
          elog(DEBUG2,
               "krb5 did not return realm but realm matching was requested");
--- 771,777 ----
              }
          }
      }
!     else if (realmmatch && strlen(realmmatch))
      {
          elog(DEBUG2,
               "krb5 did not return realm but realm matching was requested");
***************
*** 859,864 **** pg_GSS_recvauth(Port *port)
--- 868,874 ----
      int            ret;
      StringInfoData buf;
      gss_buffer_desc gbuf;
+     char       *realmmatch;

      /*
       * GSS auth is not supported for protocol versions before 3, because it
***************
*** 1018,1023 **** pg_GSS_recvauth(Port *port)
--- 1028,1038 ----
                       gettext_noop("retrieving GSS user name failed"),
                       maj_stat, min_stat);

+     if (port->hba->krb_realm)
+         realmmatch = port->hba->krb_realm;
+     else
+         realmmatch = pg_krb_realm;
+
      /*
       * Split the username at the realm separator
       */
***************
*** 1028,1055 **** pg_GSS_recvauth(Port *port)
          *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");
--- 1043,1070 ----
          *cp = '\0';
          cp++;

!         if (realmmatch != NULL && strlen(realmmatch))
          {
              /*
               * Match the realm part of the name first
               */
              if (pg_krb_caseins_users)
!                 ret = pg_strcasecmp(realmmatch, cp);
              else
!                 ret = strcmp(realmmatch, cp);

              if (ret)
              {
                  /* GSS realm does not match */
                  elog(DEBUG2,
                     "GSSAPI realm (%s) and configured realm (%s) don't match",
!                      cp, realmmatch);
                  gss_release_buffer(&lmin_s, &gbuf);
                  return STATUS_ERROR;
              }
          }
      }
!     else if (realmmatch && strlen(realmmatch))
      {
          elog(DEBUG2,
               "GSSAPI did not return realm but realm matching was requested");
***************
*** 1113,1118 **** pg_SSPI_recvauth(Port *port)
--- 1128,1134 ----
      SID_NAME_USE accountnameuse;
      HMODULE        secur32;
      QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken;
+     char       *realmmatch;

      /*
       * SSPI auth is not supported for protocol versions before 3, because it
***************
*** 1325,1337 **** pg_SSPI_recvauth(Port *port)
       * 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;
          }
--- 1341,1358 ----
       * Compare realm/domain if requested. In SSPI, always compare case
       * insensitive.
       */
!     if (port->hba->krb_realm)
!         realmmatch = port->hba->krb_realm;
!     else
!         realmmatch = pg_krb_realm;
!
!     if (realmmatch && strlen(realmmatch))
      {
!         if (pg_strcasecmp(realmmatch, domainname))
          {
              elog(DEBUG2,
                   "SSPI domain (%s) and configured domain (%s) don't match",
!                  domainname, realmmatch);

              return STATUS_ERROR;
          }
*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 1040,1045 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline)
--- 1040,1060 ----
                  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
                  parsedline->ldapsuffix = pstrdup(c);
              }
+             else if (strcmp(token, "krb_server_hostname") == 0)
+             {
+                 if (parsedline->auth_method != uaKrb5 &&
+                     parsedline->auth_method != uaGSS)
+                     INVALID_AUTH_OPTION("krb_server_hostname", "krb5 and gssapi");
+                 parsedline->krb_server_hostname = pstrdup(c);
+             }
+             else if (strcmp(token, "krb_realm") == 0)
+             {
+                 if (parsedline->auth_method != uaKrb5 &&
+                     parsedline->auth_method != uaGSS &&
+                     parsedline->auth_method != uaSSPI)
+                     INVALID_AUTH_OPTION("krb_realm", "krb5, gssapi and sspi");
+                 parsedline->krb_realm = pstrdup(c);
+             }
              else
              {
                  ereport(LOG,
***************
*** 1242,1247 **** free_hba_record(HbaLine *record)
--- 1257,1266 ----
          pfree(record->ldapprefix);
      if (record->ldapsuffix)
          pfree(record->ldapsuffix);
+     if (record->krb_server_hostname)
+         pfree(record->krb_server_hostname);
+     if (record->krb_realm)
+         pfree(record->krb_realm);
  }

  /*
*** a/src/include/libpq/hba.h
--- b/src/include/libpq/hba.h
***************
*** 56,61 **** typedef struct
--- 56,63 ----
      char       *ldapprefix;
      char       *ldapsuffix;
      bool        clientcert;
+     char       *krb_server_hostname;
+     char       *krb_realm;
  } HbaLine;

  typedef struct Port hbaPort;

pgsql-hackers by date:

Previous
From: Greg Smith
Date:
Subject: Re: benchmarking the query planner
Next
From: Magnus Hagander
Date:
Subject: Including kerberos realm