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;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to