88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.156 2007/09/14 15:58:02 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.157 2007/11/09 17:31:07 mha Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -42,6 +42,7 @@ char *pg_krb_server_keyfile;
4242char * pg_krb_srvnam ;
4343bool pg_krb_caseins_users ;
4444char * pg_krb_server_hostname = NULL ;
45+ char * pg_krb_realm = NULL ;
4546
4647#ifdef USE_PAM
4748#ifdef HAVE_PAM_PAM_APPL_H
@@ -102,30 +103,6 @@ static intCheckLDAPAuth(Port *port);
102103#include <com_err.h>
103104#endif
104105
105- /*
106- * pg_an_to_ln -- return the local name corresponding to an authentication
107- * name
108- *
109- * XXX Assumes that the first aname component is the user name. This is NOT
110- * necessarily so, since an aname can actually be something out of your
111- * worst X.400 nightmare, like
112- * ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
113- * Note that the MIT an_to_ln code does the same thing if you don't
114- * provide an aname mapping database...it may be a better idea to use
115- * krb5_an_to_ln, except that it punts if multiple components are found,
116- * and we can't afford to punt.
117- */
118- static char *
119- pg_an_to_ln (char * aname )
120- {
121- char * p ;
122-
123- if ((p = strchr (aname ,'/' ))|| (p = strchr (aname ,'@' )))
124- * p = '\0' ;
125- return aname ;
126- }
127-
128-
129106/*
130107 * Various krb5 state which is not connection specfic, and a flag to
131108 * indicate whether we have initialised it yet.
@@ -216,6 +193,7 @@ pg_krb5_recvauth(Port *port)
216193krb5_auth_context auth_context = NULL ;
217194krb5_ticket * ticket ;
218195char * kusername ;
196+ char * cp ;
219197
220198if (get_role_line (port -> user_name )== NULL )
221199return STATUS_ERROR ;
@@ -240,8 +218,6 @@ pg_krb5_recvauth(Port *port)
240218 * The "client" structure comes out of the ticket and is therefore
241219 * authenticated. Use it to check the username obtained from the
242220 * postmaster startup packet.
243- *
244- * I have no idea why this is considered necessary.
245221 */
246222#if defined(HAVE_KRB5_TICKET_ENC_PART2 )
247223retval = krb5_unparse_name (pg_krb5_context ,
@@ -263,7 +239,42 @@ pg_krb5_recvauth(Port *port)
263239return STATUS_ERROR ;
264240}
265241
266- kusername = pg_an_to_ln (kusername );
242+ cp = strchr (kusername ,'@' );
243+ if (cp )
244+ {
245+ * cp = '\0' ;
246+ cp ++ ;
247+
248+ if (pg_krb_realm != NULL && strlen (pg_krb_realm ))
249+ {
250+ /* Match realm against configured */
251+ if (pg_krb_caseins_users )
252+ ret = pg_strcasecmp (pg_krb_realm ,cp );
253+ else
254+ ret = strcmp (pg_krb_realm ,cp );
255+
256+ if (ret )
257+ {
258+ elog (DEBUG2 ,
259+ "krb5 realm (%s) and configured realm (%s) don't match" ,
260+ cp ,pg_krb_realm );
261+
262+ krb5_free_ticket (pg_krb5_context ,ticket );
263+ krb5_auth_con_free (pg_krb5_context ,auth_context );
264+ return STATUS_ERROR ;
265+ }
266+ }
267+ }
268+ else if (pg_krb_realm && strlen (pg_krb_realm ))
269+ {
270+ elog (DEBUG2 ,
271+ "krb5 did not return realm but realm matching was requested" );
272+
273+ krb5_free_ticket (pg_krb5_context ,ticket );
274+ krb5_auth_con_free (pg_krb5_context ,auth_context );
275+ return STATUS_ERROR ;
276+ }
277+
267278if (pg_krb_caseins_users )
268279ret = pg_strncasecmp (port -> user_name ,kusername ,SM_DATABASE_USER );
269280else
@@ -509,14 +520,42 @@ pg_GSS_recvauth(Port *port)
509520maj_stat ,min_stat );
510521
511522/*
512- * Compare the part of the username that comes before the @
513- * sign only (ignore realm). The GSSAPI libraries won't have
514- * authenticated the user if he's from an invalid realm.
523+ * Split the username at the realm separator
515524 */
516525if (strchr (gbuf .value ,'@' ))
517526{
518527char * cp = strchr (gbuf .value ,'@' );
519528* cp = '\0' ;
529+ cp ++ ;
530+
531+ if (pg_krb_realm != NULL && strlen (pg_krb_realm ))
532+ {
533+ /*
534+ * Match the realm part of the name first
535+ */
536+ if (pg_krb_caseins_users )
537+ ret = pg_strcasecmp (pg_krb_realm ,cp );
538+ else
539+ ret = strcmp (pg_krb_realm ,cp );
540+
541+ if (ret )
542+ {
543+ /* GSS realm does not match */
544+ elog (DEBUG2 ,
545+ "GSSAPI realm (%s) and configured realm (%s) don't match" ,
546+ cp ,pg_krb_realm );
547+ gss_release_buffer (& lmin_s ,& gbuf );
548+ return STATUS_ERROR ;
549+ }
550+ }
551+ }
552+ else if (pg_krb_realm && strlen (pg_krb_realm ))
553+ {
554+ elog (DEBUG2 ,
555+ "GSSAPI did not return realm but realm matching was requested" );
556+
557+ gss_release_buffer (& lmin_s ,& gbuf );
558+ return STATUS_ERROR ;
520559}
521560
522561if (pg_krb_caseins_users )
@@ -792,6 +831,21 @@ pg_SSPI_recvauth(Port *port)
792831
793832free (tokenuser );
794833
834+ /*
835+ * Compare realm/domain if requested. In SSPI, always compare case insensitive.
836+ */
837+ if (pg_krb_realm && strlen (pg_krb_realm ))
838+ {
839+ if (pg_strcasecmp (pg_krb_realm ,domainname ))
840+ {
841+ elog (DEBUG2 ,
842+ "SSPI domain (%s) and configured domain (%s) don't match" ,
843+ domainname ,pg_krb_realm );
844+
845+ return STATUS_ERROR ;
846+ }
847+ }
848+
795849/*
796850 * We have the username (without domain/realm) in accountname, compare
797851 * to the supplied value. In SSPI, always compare case insensitive.