Index: backend/libpq/auth.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/libpq/auth.c,v retrieving revision 1.156 diff -c -r1.156 auth.c *** backend/libpq/auth.c 14 Sep 2007 15:58:02 -0000 1.156 --- backend/libpq/auth.c 1 Nov 2007 11:28:54 -0000 *************** *** 42,47 **** --- 42,48 ---- char *pg_krb_srvnam; bool pg_krb_caseins_users; char *pg_krb_server_hostname = NULL; + char *pg_krb_match_realm = NULL; #ifdef USE_PAM #ifdef HAVE_PAM_PAM_APPL_H *************** *** 103,132 **** #endif /* - * pg_an_to_ln -- return the local name corresponding to an authentication - * name - * - * XXX Assumes that the first aname component is the user name. This is NOT - * necessarily so, since an aname can actually be something out of your - * worst X.400 nightmare, like - * ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU - * Note that the MIT an_to_ln code does the same thing if you don't - * 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. - */ - static char * - pg_an_to_ln(char *aname) - { - char *p; - - if ((p = strchr(aname, '/')) || (p = strchr(aname, '@'))) - *p = '\0'; - return aname; - } - - - /* * Various krb5 state which is not connection specfic, and a flag to * indicate whether we have initialised it yet. */ --- 104,109 ---- *************** *** 216,221 **** --- 193,199 ---- krb5_auth_context auth_context = NULL; krb5_ticket *ticket; char *kusername; + char *cp; if (get_role_line(port->user_name) == NULL) return STATUS_ERROR; *************** *** 240,247 **** * The "client" structure comes out of the ticket and is therefore * authenticated. Use it to check the username obtained from the * postmaster startup packet. - * - * I have no idea why this is considered necessary. */ #if defined(HAVE_KRB5_TICKET_ENC_PART2) retval = krb5_unparse_name(pg_krb5_context, --- 218,223 ---- *************** *** 263,269 **** return STATUS_ERROR; } ! kusername = pg_an_to_ln(kusername); if (pg_krb_caseins_users) ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER); else --- 239,280 ---- return STATUS_ERROR; } ! cp = strchr(kusername, '@'); ! if (cp) ! { ! *cp = '\0'; ! cp++; ! ! if (pg_krb_match_realm != NULL && strlen(pg_krb_match_realm)) ! { ! /* Match realm against configured */ ! if (pg_krb_caseins_users) ! ret = pg_strcasecmp(pg_krb_match_realm, cp); ! else ! ret = strcmp(pg_krb_match_realm, cp); ! ! if (ret) ! { ! elog(DEBUG2, ! "krb5 realm (%s) and configured realm (%s) don't match", ! cp, pg_krb_match_realm); ! ! krb5_free_ticket(pg_krb5_context, ticket); ! krb5_auth_con_free(pg_krb5_context, auth_context); ! return STATUS_ERROR; ! } ! } ! } ! else if (pg_krb_match_realm && strlen(pg_krb_match_realm)) ! { ! elog(DEBUG2, ! "krb5 did not return realm but realm matching was requested"); ! ! krb5_free_ticket(pg_krb5_context, ticket); ! krb5_auth_con_free(pg_krb5_context, auth_context); ! return STATUS_ERROR; ! } ! if (pg_krb_caseins_users) ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER); else *************** *** 509,522 **** maj_stat, min_stat); /* ! * Compare the part of the username that comes before the @ ! * sign only (ignore realm). The GSSAPI libraries won't have ! * authenticated the user if he's from an invalid realm. */ if (strchr(gbuf.value, '@')) { char *cp = strchr(gbuf.value, '@'); *cp = '\0'; } if (pg_krb_caseins_users) --- 520,561 ---- maj_stat, min_stat); /* ! * Split the username at the realm separator */ if (strchr(gbuf.value, '@')) { char *cp = strchr(gbuf.value, '@'); *cp = '\0'; + cp++; + + if (pg_krb_match_realm != NULL && strlen(pg_krb_match_realm)) + { + /* + * Match the realm part of the name first + */ + if (pg_krb_caseins_users) + ret = pg_strcasecmp(pg_krb_match_realm, cp); + else + ret = strcmp(pg_krb_match_realm, cp); + + if (ret) + { + /* GSS realm does not match */ + elog(DEBUG2, + "GSSAPI realm (%s) and configured realm (%s) don't match", + cp, pg_krb_match_realm); + gss_release_buffer(&lmin_s, &gbuf); + return STATUS_ERROR; + } + } + } + else if (pg_krb_match_realm && strlen(pg_krb_match_realm)) + { + elog(DEBUG2, + "GSSAPI did not return realm but realm matching was requested"); + + gss_release_buffer(&lmin_s, &gbuf); + return STATUS_ERROR; } if (pg_krb_caseins_users) *************** *** 792,797 **** --- 831,851 ---- free(tokenuser); + /* + * Compare realm/domain if requested. In SSPI, always compare case insensitive. + */ + if (pg_krb_match_realm && strlen(pg_krb_match_realm)) + { + if (pg_strcasecmp(pg_krb_match_realm, domainname)) + { + elog(DEBUG2, + "SSPI domain (%s) does and configured domain (%s) don't match", + domainname, pg_krb_match_realm); + + return STATUS_ERROR; + } + } + /* * We have the username (without domain/realm) in accountname, compare * to the supplied value. In SSPI, always compare case insensitive. Index: backend/utils/misc/guc.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v retrieving revision 1.423 diff -c -r1.423 guc.c *** backend/utils/misc/guc.c 26 Sep 2007 22:36:30 -0000 1.423 --- backend/utils/misc/guc.c 1 Nov 2007 11:28:54 -0000 *************** *** 2044,2049 **** --- 2044,2059 ---- }, { + {"krb_match_realm", PGC_POSTMASTER, CONN_AUTH_SECURITY, + gettext_noop("Sets realm to match Kerberos and GSSAPI users against."), + NULL, + GUC_SUPERUSER_ONLY + }, + &pg_krb_match_realm, + NULL, NULL, NULL + }, + + { {"krb_server_keyfile", PGC_POSTMASTER, CONN_AUTH_SECURITY, gettext_noop("Sets the location of the Kerberos server key file."), NULL, Index: backend/utils/misc/postgresql.conf.sample =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v retrieving revision 1.231 diff -c -r1.231 postgresql.conf.sample *** backend/utils/misc/postgresql.conf.sample 26 Sep 2007 22:36:30 -0000 1.231 --- backend/utils/misc/postgresql.conf.sample 1 Nov 2007 11:28:54 -0000 *************** *** 85,90 **** --- 85,91 ---- #krb_server_hostname = '' # empty string matches any keytab entry # (change requires restart, kerberos only) #krb_caseins_users = off # (change requires restart) + #krb_match_realm = '' # (change requires restart) # - TCP Keepalives - # see 'man 7 tcp' for details Index: include/libpq/auth.h =================================================================== RCS file: /cvsroot/pgsql/src/include/libpq/auth.h,v retrieving revision 1.33 diff -c -r1.33 auth.h *** include/libpq/auth.h 5 Jan 2007 22:19:55 -0000 1.33 --- include/libpq/auth.h 1 Nov 2007 11:28:54 -0000 *************** *** 20,25 **** --- 20,26 ---- extern char *pg_krb_srvnam; extern bool pg_krb_caseins_users; extern char *pg_krb_server_hostname; + extern char *pg_krb_match_realm; extern void ClientAuthentication(Port *port);