diff options
-rw-r--r-- | doc/src/sgml/client-auth.sgml | 10 | ||||
-rw-r--r-- | doc/src/sgml/config.sgml | 17 | ||||
-rw-r--r-- | src/backend/libpq/auth.c | 116 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 12 | ||||
-rw-r--r-- | src/backend/utils/misc/postgresql.conf.sample | 1 | ||||
-rw-r--r-- | src/include/libpq/auth.h | 3 |
6 files changed, 120 insertions, 39 deletions
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index b4a851588ea..9e3ab2440d9 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.101 2007/09/14 03:53:54 momjian Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.102 2007/11/09 17:31:07 mha Exp $ --> <chapter id="client-authentication"> <title>Client Authentication</title> @@ -773,10 +773,10 @@ local db1,db2,@demodbs all md5 <para> Client principals must have their <productname>PostgreSQL</> database user name as their first component, for example - <literal>pgusername/otherstuff@realm</>. At present the realm of - the client is not checked by <productname>PostgreSQL</>; so if you - have cross-realm authentication enabled, then any principal in any - realm that can communicate with yours will be accepted. + <literal>pgusername@realm</>. By default, the realm of the client is + not checked by <productname>PostgreSQL</>. If you have cross-realm + authentication enabled and need to verify the realm, use the + <xref linkend="guc-krb-realm"> parameter. </para> <para> diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index f070290f483..d8d8c4deb14 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.153 2007/11/05 17:35:38 momjian Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.154 2007/11/09 17:31:07 mha Exp $ --> <chapter Id="runtime-config"> <title>Server Configuration</title> @@ -601,6 +601,21 @@ SET ENABLE_SEQSCAN TO OFF; </listitem> </varlistentry> + <varlistentry id="guc-krb-realm" xreflabel="krb_realm"> + <term><varname>krb_realm</varname> (<type>string</type>)</term> + <indexterm> + <primary><varname>krb_realm</> configuration parameter</primary> + </indexterm> + <listitem> + <para> + Sets the realm to match Kerberos, GSSAPI and SSPI usernames against. + See <xref linkend="kerberos-auth">, <xref linkend="gssapi-auth"> or + <xref linkend="sspi-auth"> for details. This parameter can only be + set at server start. + </para> + </listitem> + </varlistentry> + <varlistentry id="guc-krb-server-keyfile" xreflabel="krb_server_keyfile"> <term><varname>krb_server_keyfile</varname> (<type>string</type>)</term> <indexterm> diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 403a9664b46..bba3ebf5b45 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 @@ -103,30 +104,6 @@ static int CheckLDAPAuth(Port *port); #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 64eeaabef3d..49a4cc722e0 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * 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 $ * *-------------------------------------------------------------------- */ @@ -2044,6 +2044,16 @@ static struct config_string ConfigureNamesString[] = }, { + {"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."), NULL, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 48023bc4ddf..3a94829ced1 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 65c9d512d84..da0871d9ffe 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); |