aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/client-auth.sgml10
-rw-r--r--doc/src/sgml/config.sgml17
-rw-r--r--src/backend/libpq/auth.c116
-rw-r--r--src/backend/utils/misc/guc.c12
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample1
-rw-r--r--src/include/libpq/auth.h3
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);