svn rev #21588: trunk/ src/config-files/ src/lib/krb5/os/
ghudson@MIT.EDU
ghudson at MIT.EDU
Wed Dec 24 11:51:34 EST 2008
http://src.mit.edu/fisheye/changelog/krb5/?cs=21588
Commit By: ghudson
Log Message:
ticket: 6031
Add a new fallback host-to-realm heuristic to try the components of the
hostname as domains. The heuristic is off by default and is controlled
by the realm_try_domains variable under libdefaults.
Based on a patch submitted by Mark Phalan from Sun.
Changed Files:
U trunk/README
U trunk/src/config-files/krb5.conf.M
U trunk/src/lib/krb5/os/hst_realm.c
Modified: trunk/README
===================================================================
--- trunk/README 2008-12-24 07:45:18 UTC (rev 21587)
+++ trunk/README 2008-12-24 16:51:33 UTC (rev 21588)
@@ -425,6 +425,10 @@
slave/kpropd_rpc.c
slave/kproplog.c
+and marked portions of the following files:
+
+ lib/krb5/os/hst_realm.c
+
are subject to the following license:
Copyright (c) 2004 Sun Microsystems, Inc.
Modified: trunk/src/config-files/krb5.conf.M
===================================================================
--- trunk/src/config-files/krb5.conf.M 2008-12-24 07:45:18 UTC (rev 21587)
+++ trunk/src/config-files/krb5.conf.M 2008-12-24 16:51:33 UTC (rev 21588)
@@ -201,6 +201,16 @@
General flag controlling the use of DNS for Kerberos information. If both
of the preceding options are specified, this option has no effect.
+.IP realm_try_domains
+Indicate whether a host's domain components should be used to
+determine the Kerberos realm of the host. The value of this variable
+is an integer: -1 means not to search, 0 means to try the host's
+domain itself, 1 means to also try the domain's immediate parent, and
+so forth. The library's usual mechanism for locating Kerberos realms
+is used to determine whether a domain is a valid realm--which may
+involve consulting DNS if dns_lookup_kdc is set. The default is not
+to search domain components.
+
.IP extra_addresses
This allows a computer to use multiple local addresses, in order to
allow Kerberos to work in a network that uses NATs. The addresses should
Modified: trunk/src/lib/krb5/os/hst_realm.c
===================================================================
--- trunk/src/lib/krb5/os/hst_realm.c 2008-12-24 07:45:18 UTC (rev 21587)
+++ trunk/src/lib/krb5/os/hst_realm.c 2008-12-24 16:51:33 UTC (rev 21588)
@@ -78,6 +78,10 @@
#include "fake-addrinfo.h"
+static krb5_error_code
+domain_heuristic(krb5_context context, const char *domain,
+ char **realm, int limit);
+
#ifdef KRB5_DNS_LOOKUP
#include "dnsglue.h"
@@ -334,7 +338,7 @@
krb5_get_fallback_host_realm(krb5_context context, krb5_data *hdata, char ***realmsp)
{
char **retrealms;
- char *default_realm, *realm, *cp, *temp_realm;
+ char *realm, *cp;
krb5_error_code retval;
char local_host[MAXDNAME+1], host[MAXDNAME+1];
@@ -348,71 +352,71 @@
krb5int_clean_hostname(context, host, local_host, sizeof local_host);
- /* Scan hostname for DNS realm, and save as last-ditch realm
- assumption. */
- cp = local_host;
-#ifdef DEBUG_REFERRALS
- printf(" local_host: %s\n",local_host);
-#endif
- realm = default_realm = (char *)NULL;
- temp_realm = 0;
- while (cp && !default_realm) {
- if (*cp == '.') {
- cp++;
- if (default_realm == (char *)NULL) {
- /* If nothing else works, use the host's domain */
- default_realm = cp;
- }
- } else {
- cp = strchr(cp, '.');
- }
+ /*
+ * Try looking up a _kerberos.<hostname> TXT record in DNS. This
+ * heuristic is turned off by default since, in the absence of
+ * secure DNS, it can allow an attacker to control the realm used
+ * for a host.
+ */
+ realm = (char *)NULL;
+#ifdef KRB5_DNS_LOOKUP
+ if (_krb5_use_dns_realm(context)) {
+ cp = local_host;
+ do {
+ retval = krb5_try_realm_txt_rr("_kerberos", cp, &realm);
+ cp = strchr(cp,'.');
+ if (cp)
+ cp++;
+ } while (retval && cp && cp[0]);
}
-#ifdef DEBUG_REFERRALS
- printf(" done finding DNS-based default realm: >%s<\n",default_realm);
-#endif
+#endif /* KRB5_DNS_LOOKUP */
-#ifdef KRB5_DNS_LOOKUP
+ /*
+ * Next try searching the domain components as realms. This
+ * heuristic is also turned off by default. If DNS lookups for
+ * KDCs are enabled (as they are by default), an attacker could
+ * control which domain component is used as the realm for a host.
+ */
if (realm == (char *)NULL) {
- int use_dns = _krb5_use_dns_realm(context);
- if ( use_dns ) {
- /*
- * Since this didn't appear in our config file, try looking
- * it up via DNS. Look for a TXT records of the form:
- *
- * _kerberos.<hostname>
- *
- */
- cp = local_host;
- do {
- retval = krb5_try_realm_txt_rr("_kerberos", cp, &realm);
- cp = strchr(cp,'.');
- if (cp)
- cp++;
- } while (retval && cp && cp[0]);
- }
+ int limit;
+ errcode_t code;
+
+ code = profile_get_integer(context->profile, "libdefaults",
+ "realm_try_domains", 0, -1, &limit);
+ if (code == 0) {
+ retval = domain_heuristic(context, local_host, &realm, limit);
+ if (retval)
+ return retval;
+ }
}
-#endif /* KRB5_DNS_LOOKUP */
-
+ /*
+ * The next fallback--and the first one to apply with default
+ * configuration--is to use the upper-cased parent domain of the
+ * hostname, regardless of whether we can actually look it up as a
+ * realm.
+ */
if (realm == (char *)NULL) {
- if (default_realm != (char *)NULL) {
- /* We are defaulting to the realm of the host */
- if (!(cp = strdup(default_realm)))
- return ENOMEM;
- realm = cp;
-
- /* Assume the realm name is upper case */
+ cp = strchr(local_host, '.');
+ if (cp) {
+ if (!(realm = strdup(cp + 1)))
+ return ENOMEM;
for (cp = realm; *cp; cp++)
if (islower((int) (*cp)))
*cp = toupper((int) *cp);
- } else {
- /* We are defaulting to the local realm */
- retval = krb5_get_default_realm(context, &realm);
- if (retval) {
- return retval;
- }
- }
+ }
}
+
+ /*
+ * The final fallback--used when the fully-qualified hostname has
+ * only one component--is to use the local default realm.
+ */
+ if (realm == (char *)NULL) {
+ retval = krb5_get_default_realm(context, &realm);
+ if (retval)
+ return retval;
+ }
+
if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
if (realm != (char *)NULL)
free(realm);
@@ -488,3 +492,70 @@
#endif
return 0;
}
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Walk through the components of a domain. At each stage determine
+ * if a KDC can be located for that domain. Return a realm
+ * corresponding to the upper-cased domain name for which a KDC was
+ * found or NULL if no KDC was found. Stop searching after limit
+ * labels have been removed from the domain (-1 means don't search at
+ * all, 0 means try only the full domain itself, 1 means also try the
+ * parent domain, etc.) or when we reach a parent with only one label.
+ */
+static krb5_error_code
+domain_heuristic(krb5_context context, const char *domain,
+ char **realm, int limit)
+{
+ krb5_error_code retval = 0, r;
+ struct addrlist alist;
+ krb5_data drealm;
+ char *cp = NULL;
+ char *fqdn = NULL;
+
+ *realm = NULL;
+ if (limit < 0)
+ return 0;
+
+ memset(&drealm, 0, sizeof (drealm));
+ if (!(fqdn = strdup(domain))) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+
+ /* Upper case the domain (for use as a realm) */
+ for (cp = fqdn; *cp; cp++)
+ if (islower((int)(*cp)))
+ *cp = toupper((int)*cp);
+
+ /* Search up to limit parents, as long as we have multiple labels. */
+ cp = fqdn;
+ while (limit-- >= 0 && strchr(cp, '.') != NULL) {
+
+ drealm.length = strlen(cp);
+ drealm.data = cp;
+
+ /* Find a kdc based on this part of the domain name. */
+ r = krb5_locate_kdc(context, &drealm, &alist, 0, SOCK_DGRAM, 0);
+ if (!r) { /* Found a KDC! */
+ krb5int_free_addrlist(&alist);
+ if (!(*realm = strdup(cp))) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ break;
+ }
+
+ cp = strchr(cp, '.');
+ cp++;
+ }
+
+cleanup:
+ if (fqdn)
+ free(fqdn);
+ return retval;
+}
More information about the cvs-krb5
mailing list