diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index b4a851588e..9e3ab2440d 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -1,4 +1,4 @@ - + Client Authentication @@ -773,10 +773,10 @@ local db1,db2,@demodbs all md5 Client principals must have their PostgreSQL database user name as their first component, for example - pgusername/otherstuff@realm. At present the realm of - the client is not checked by PostgreSQL; so if you - have cross-realm authentication enabled, then any principal in any - realm that can communicate with yours will be accepted. + pgusername@realm. By default, the realm of the client is + not checked by PostgreSQL. If you have cross-realm + authentication enabled and need to verify the realm, use the + parameter. diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index f070290f48..d8d8c4deb1 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1,4 +1,4 @@ - + Server Configuration @@ -601,6 +601,21 @@ SET ENABLE_SEQSCAN TO OFF; + + krb_realm (string) + + krb_realm configuration parameter + + + + Sets the realm to match Kerberos, GSSAPI and SSPI usernames against. + See , or + for details. This parameter can only be + set at server start. + + + + krb_server_keyfile (string) diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 403a9664b4..bba3ebf5b4 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.156 2007/09/14 15:58:02 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.157 2007/11/09 17:31:07 mha Exp $ * *------------------------------------------------------------------------- */ @@ -42,6 +42,7 @@ char *pg_krb_server_keyfile; char *pg_krb_srvnam; bool pg_krb_caseins_users; char *pg_krb_server_hostname = NULL; +char *pg_krb_realm = NULL; #ifdef USE_PAM #ifdef HAVE_PAM_PAM_APPL_H @@ -102,30 +103,6 @@ static int CheckLDAPAuth(Port *port); #include #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. @@ -216,6 +193,7 @@ pg_krb5_recvauth(Port *port) 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,8 +218,6 @@ pg_krb5_recvauth(Port *port) * 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, @@ -263,7 +239,42 @@ pg_krb5_recvauth(Port *port) return STATUS_ERROR; } - kusername = pg_an_to_ln(kusername); + 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); + return STATUS_ERROR; + } + } + } + else if (pg_krb_realm && strlen(pg_krb_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,14 +520,42 @@ pg_GSS_recvauth(Port *port) 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. + * Split the username at the realm separator */ if (strchr(gbuf.value, '@')) { char *cp = strchr(gbuf.value, '@'); *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"); + + gss_release_buffer(&lmin_s, &gbuf); + return STATUS_ERROR; } if (pg_krb_caseins_users) @@ -792,6 +831,21 @@ pg_SSPI_recvauth(Port *port) free(tokenuser); + /* + * 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; + } + } + /* * We have the username (without domain/realm) in accountname, compare * to the supplied value. In SSPI, always compare case insensitive. diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 64eeaabef3..49a4cc722e 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.423 2007/09/26 22:36:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.424 2007/11/09 17:31:07 mha Exp $ * *-------------------------------------------------------------------- */ @@ -2043,6 +2043,16 @@ static struct config_string ConfigureNamesString[] = "$libdir", NULL, NULL }, + { + {"krb_realm", PGC_POSTMASTER, CONN_AUTH_SECURITY, + gettext_noop("Sets realm to match Kerberos and GSSAPI users against."), + NULL, + GUC_SUPERUSER_ONLY + }, + &pg_krb_realm, + NULL, NULL, NULL + }, + { {"krb_server_keyfile", PGC_POSTMASTER, CONN_AUTH_SECURITY, gettext_noop("Sets the location of the Kerberos server key file."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 48023bc4dd..3a94829ced 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -85,6 +85,7 @@ #krb_server_hostname = '' # empty string matches any keytab entry # (change requires restart, kerberos only) #krb_caseins_users = off # (change requires restart) +#krb_realm = '' # (change requires restart) # - TCP Keepalives - # see 'man 7 tcp' for details diff --git a/src/include/libpq/auth.h b/src/include/libpq/auth.h index 65c9d512d8..da0871d9ff 100644 --- a/src/include/libpq/auth.h +++ b/src/include/libpq/auth.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/libpq/auth.h,v 1.33 2007/01/05 22:19:55 momjian Exp $ + * $PostgreSQL: pgsql/src/include/libpq/auth.h,v 1.34 2007/11/09 17:31:07 mha Exp $ * *------------------------------------------------------------------------- */ @@ -20,6 +20,7 @@ extern char *pg_krb_server_keyfile; extern char *pg_krb_srvnam; extern bool pg_krb_caseins_users; extern char *pg_krb_server_hostname; +extern char *pg_krb_realm; extern void ClientAuthentication(Port *port);