krb5 commit: Use hostrealm interface for realm mapping

Greg Hudson ghudson at MIT.EDU
Thu Aug 15 12:51:25 EDT 2013


https://github.com/krb5/krb5/commit/db21244a069e581a392dff5b320e758e06a28e4d
commit db21244a069e581a392dff5b320e758e06a28e4d
Author: Greg Hudson <ghudson at mit.edu>
Date:   Mon Aug 5 15:57:29 2013 -0400

    Use hostrealm interface for realm mapping
    
    Reimplement krb5_get_host_realm, krb5_get_fallback_host_realm, and
    krb5_get_default_realm in terms of the hostrealm interface.  Three
    built-in modules (dns, domain, and profile) implement the current
    behavior.
    
    ticket: 7687

 src/include/k5-int.h                |    4 +
 src/include/k5-trace.h              |   11 +-
 src/lib/krb5/krb/init_ctx.c         |    1 +
 src/lib/krb5/libkrb5.exports        |    1 +
 src/lib/krb5/os/Makefile.in         |   15 +-
 src/lib/krb5/os/def_realm.c         |  190 -----------------
 src/lib/krb5/os/deps                |   79 +++++--
 src/lib/krb5/os/hostrealm.c         |  401 +++++++++++++++++++++++++++++++++++
 src/lib/krb5/os/hostrealm_dns.c     |  143 +++++++++++++
 src/lib/krb5/os/hostrealm_domain.c  |  128 +++++++++++
 src/lib/krb5/os/hostrealm_profile.c |  117 ++++++++++
 src/lib/krb5/os/hst_realm.c         |  255 +----------------------
 src/lib/krb5/os/os-proto.h          |   12 +
 13 files changed, 884 insertions(+), 473 deletions(-)

diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index a9a3c3c..ab97f40 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -1117,6 +1117,7 @@ struct _kdb_log_context;
 typedef struct krb5_preauth_context_st krb5_preauth_context;
 struct ccselect_module_handle;
 struct localauth_module_handle;
+struct hostrealm_module_handle;
 struct _krb5_context {
     krb5_magic      magic;
     krb5_enctype    *in_tkt_etypes;
@@ -1163,6 +1164,9 @@ struct _krb5_context {
     /* localauth module stuff */
     struct localauth_module_handle **localauth_handles;
 
+    /* hostrealm module stuff */
+    struct hostrealm_module_handle **hostrealm_handles;
+
     /* error detail info */
     struct errinfo err;
 
diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
index ac09eb0..68672fd 100644
--- a/src/include/k5-trace.h
+++ b/src/include/k5-trace.h
@@ -183,6 +183,11 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
 #define TRACE_ENCTYPE_LIST_UNKNOWN(c, profvar, name)                    \
     TRACE(c, "Unrecognized enctype name in {str}: {str}", profvar, name)
 
+#define TRACE_HOSTREALM_VTINIT_FAIL(c, ret)                             \
+    TRACE(c, "hostrealm module failed to init vtable: {kerr}", ret)
+#define TRACE_HOSTREALM_INIT_FAIL(c, name, ret)                         \
+    TRACE(c, "hostrealm module {str} failed to init: {kerr}", name, ret)
+
 #define TRACE_INIT_CREDS(c, princ)                              \
     TRACE(c, "Getting initial credentials for {princ}", princ)
 #define TRACE_INIT_CREDS_AS_KEY_GAK(c, keyblock)                        \
@@ -402,12 +407,6 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
 #define TRACE_TXT_LOOKUP_SUCCESS(c, host, realm)                \
     TRACE(c, "TXT record {str} found: {str}", host, realm)
 
-#define TRACE_GET_HOST_REALM_RETURN(c, host, realm) \
-    TRACE(c, "Got realm {str} for host {str}", realm, host)
-
-#define TRACE_GET_FALLBACK_HOST_REALM_RETURN(c, host, realm) \
-    TRACE(c, "Got fallback realm {str} for host {str}", realm, host)
-
 #define TRACE_SNAME_TO_PRINCIPAL(c, host, sname, type) \
     TRACE(c, "Convert service {str} ({ptype}) on host {str} to principal", \
           sname, type, host)
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index 39b6853..3f4aad4 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -310,6 +310,7 @@ krb5_free_context(krb5_context ctx)
 #endif
 
     k5_ccselect_free_context(ctx);
+    k5_hostrealm_free_context(ctx);
     k5_localauth_free_context(ctx);
     k5_plugin_free_context(ctx);
     free(ctx->plugin_base_dir);
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 665db7f..59d698a 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -115,6 +115,7 @@ k5_free_otp_tokeninfo
 k5_free_pa_otp_challenge
 k5_free_pa_otp_req
 k5_free_serverlist
+k5_hostrealm_free_context
 k5_init_trace
 k5_kt_get_principal
 k5_localauth_free_context
diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in
index 0353a84..769f234 100644
--- a/src/lib/krb5/os/Makefile.in
+++ b/src/lib/krb5/os/Makefile.in
@@ -11,7 +11,6 @@ LOCALINCLUDES=-I$(top_srcdir)/util/profile
 STLIBOBJS= \
 	accessor.o	\
 	c_ustime.o	\
-	def_realm.o	\
 	ccdefname.o	\
 	changepw.o	\
 	dnsglue.o	\
@@ -22,6 +21,10 @@ STLIBOBJS= \
 	genaddrs.o	\
 	gen_rname.o	\
 	hostaddr.o	\
+	hostrealm.o	\
+	hostrealm_dns.o \
+	hostrealm_domain.o \
+	hostrealm_profile.o \
 	hst_realm.o	\
 	init_os_ctx.o	\
 	krbfileio.o	\
@@ -55,7 +58,6 @@ STLIBOBJS= \
 OBJS= \
 	$(OUTPRE)accessor.$(OBJEXT)	\
 	$(OUTPRE)c_ustime.$(OBJEXT)	\
-	$(OUTPRE)def_realm.$(OBJEXT)	\
 	$(OUTPRE)ccdefname.$(OBJEXT)	\
 	$(OUTPRE)changepw.$(OBJEXT)	\
 	$(OUTPRE)dnsglue.$(OBJEXT)	\
@@ -66,6 +68,10 @@ OBJS= \
 	$(OUTPRE)genaddrs.$(OBJEXT)	\
 	$(OUTPRE)gen_rname.$(OBJEXT)	\
 	$(OUTPRE)hostaddr.$(OBJEXT)	\
+	$(OUTPRE)hostrealm.$(OBJEXT)	\
+	$(OUTPRE)hostrealm_dns.$(OBJEXT) \
+	$(OUTPRE)hostrealm_domain.$(OBJEXT) \
+	$(OUTPRE)hostrealm_profile.$(OBJEXT) \
 	$(OUTPRE)hst_realm.$(OBJEXT)	\
 	$(OUTPRE)init_os_ctx.$(OBJEXT)	\
 	$(OUTPRE)krbfileio.$(OBJEXT)	\
@@ -99,7 +105,6 @@ OBJS= \
 SRCS= \
 	$(srcdir)/accessor.c    \
 	$(srcdir)/c_ustime.c	\
-	$(srcdir)/def_realm.c	\
 	$(srcdir)/ccdefname.c	\
 	$(srcdir)/changepw.c	\
 	$(srcdir)/dnsglue.c	\
@@ -110,6 +115,10 @@ SRCS= \
 	$(srcdir)/genaddrs.c	\
 	$(srcdir)/gen_rname.c	\
 	$(srcdir)/hostaddr.c	\
+	$(srcdir)/hostrealm.c	\
+	$(srcdir)/hostrealm_dns.c \
+	$(srcdir)/hostrealm_domain.c \
+	$(srcdir)/hostrealm_profile.c \
 	$(srcdir)/hst_realm.c	\
 	$(srcdir)/init_os_ctx.c	\
 	$(srcdir)/krbfileio.c	\
diff --git a/src/lib/krb5/os/def_realm.c b/src/lib/krb5/os/def_realm.c
deleted file mode 100644
index 81ad6f2..0000000
--- a/src/lib/krb5/os/def_realm.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/os/def_realm.c */
-/*
- * Copyright 1990,1991,2009 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * krb5_get_default_realm(), krb5_set_default_realm(),
- * krb5_free_default_realm() functions.
- */
-
-#include "k5-int.h"
-#include "os-proto.h"
-#include <stdio.h>
-
-#ifdef KRB5_DNS_LOOKUP
-#ifdef WSHELPER
-#include <wshelper.h>
-#else /* WSHELPER */
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#include <netdb.h>
-#endif /* WSHELPER */
-
-/* for old Unixes and friends ... */
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 64
-#endif
-
-#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
-
-#endif /* KRB5_DNS_LOOKUP */
-
-/*
- * Retrieves the default realm to be used if no user-specified realm is
- *  available.  [e.g. to interpret a user-typed principal name with the
- *  realm omitted for convenience]
- *
- *  returns system errors, NOT_ENOUGH_SPACE, KV5M_CONTEXT
- */
-
-/*
- * Implementation:  the default realm is stored in a configuration file,
- * named by krb5_config_file;  the first token in this file is taken as
- * the default local realm name.
- */
-
-krb5_error_code KRB5_CALLCONV
-krb5_get_default_realm(krb5_context context, char **lrealm)
-{
-    char *realm = 0;
-    krb5_error_code retval;
-
-    if (!context || (context->magic != KV5M_CONTEXT))
-        return KV5M_CONTEXT;
-
-    if (!context->default_realm) {
-        /*
-         * XXX should try to figure out a reasonable default based
-         * on the host's DNS domain.
-         */
-        context->default_realm = 0;
-        if (context->profile != 0) {
-            retval = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
-                                        KRB5_CONF_DEFAULT_REALM, 0, 0,
-                                        &realm);
-
-            if (!retval && realm) {
-                context->default_realm = strdup(realm);
-                if (!context->default_realm) {
-                    profile_release_string(realm);
-                    return ENOMEM;
-                }
-                profile_release_string(realm);
-            }
-        }
-#ifndef KRB5_DNS_LOOKUP
-        else
-            return KRB5_CONFIG_CANTOPEN;
-#else /* KRB5_DNS_LOOKUP */
-        if (context->default_realm == 0) {
-            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.<localhost>
-                 * _kerberos.<domainname>
-                 * _kerberos.<searchlist>
-                 *
-                 */
-                char localhost[MAX_DNS_NAMELEN+1];
-                char * p;
-
-                krb5int_get_fq_local_hostname (localhost, sizeof(localhost));
-
-                if ( localhost[0] ) {
-                    p = localhost;
-                    do {
-                        retval = k5_try_realm_txt_rr(context, "_kerberos", p,
-                                                     &context->default_realm);
-                        p = strchr(p,'.');
-                        if (p)
-                            p++;
-                    } while (retval && p && p[0]);
-
-                    if (retval)
-                        retval = k5_try_realm_txt_rr(context, "_kerberos", "",
-                                                     &context->default_realm);
-                } else {
-                    retval = k5_try_realm_txt_rr(context, "_kerberos", "",
-                                                 &context->default_realm);
-                }
-                if (retval) {
-                    return(KRB5_CONFIG_NODEFREALM);
-                }
-            }
-        }
-#endif /* KRB5_DNS_LOOKUP */
-    }
-
-    if (context->default_realm == 0)
-        return(KRB5_CONFIG_NODEFREALM);
-    if (context->default_realm[0] == 0) {
-        free (context->default_realm);
-        context->default_realm = 0;
-        return KRB5_CONFIG_NODEFREALM;
-    }
-
-    realm = context->default_realm;
-
-    if (!(*lrealm = strdup(realm)))
-        return ENOMEM;
-    return(0);
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_set_default_realm(krb5_context context, const char *lrealm)
-{
-    if (!context || (context->magic != KV5M_CONTEXT))
-        return KV5M_CONTEXT;
-
-    if (context->default_realm) {
-        free(context->default_realm);
-        context->default_realm = 0;
-    }
-
-    /* Allow the user to clear the default realm setting by passing in
-       NULL */
-    if (!lrealm) return 0;
-
-    context->default_realm = strdup(lrealm);
-
-    if (!context->default_realm)
-        return ENOMEM;
-
-    return(0);
-
-}
-
-void KRB5_CALLCONV
-krb5_free_default_realm(krb5_context context, char *lrealm)
-{
-    free (lrealm);
-}
diff --git a/src/lib/krb5/os/deps b/src/lib/krb5/os/deps
index 63caf75..0b53b97 100644
--- a/src/lib/krb5/os/deps
+++ b/src/lib/krb5/os/deps
@@ -24,28 +24,18 @@ c_ustime.so c_ustime.po $(OUTPRE)c_ustime.$(OBJEXT): \
   $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
   $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
   c_ustime.c
-def_realm.so def_realm.po $(OUTPRE)def_realm.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h def_realm.c os-proto.h
 ccdefname.so ccdefname.po $(OUTPRE)ccdefname.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h ccdefname.c os-proto.h
+  $(COM_ERR_DEPS) $(srcdir)/../ccache/cc-int.h $(top_srcdir)/include/k5-buf.h \
+  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+  $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  ccdefname.c os-proto.h
 changepw.so changepw.po $(OUTPRE)changepw.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
@@ -149,6 +139,54 @@ hostaddr.so hostaddr.po $(OUTPRE)hostaddr.$(OBJEXT): \
   $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
   $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
   $(top_srcdir)/include/socket-utils.h hostaddr.c os-proto.h
+hostrealm.so hostrealm.po $(OUTPRE)hostrealm.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/hostrealm_plugin.h \
+  $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  hostrealm.c os-proto.h
+hostrealm_dns.so hostrealm_dns.po $(OUTPRE)hostrealm_dns.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/hostrealm_plugin.h \
+  $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  dnsglue.h hostrealm_dns.c os-proto.h
+hostrealm_domain.so hostrealm_domain.po $(OUTPRE)hostrealm_domain.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/hostrealm_plugin.h \
+  $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  hostrealm_domain.c os-proto.h
+hostrealm_profile.so hostrealm_profile.po $(OUTPRE)hostrealm_profile.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/hostrealm_plugin.h \
+  $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  hostrealm_profile.c os-proto.h
 hst_realm.so hst_realm.po $(OUTPRE)hst_realm.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
@@ -160,8 +198,7 @@ hst_realm.so hst_realm.po $(OUTPRE)hst_realm.$(OBJEXT): \
   $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
   $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
   $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h dnsglue.h hst_realm.c \
-  os-proto.h
+  $(top_srcdir)/include/socket-utils.h hst_realm.c os-proto.h
 init_os_ctx.so init_os_ctx.po $(OUTPRE)init_os_ctx.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
diff --git a/src/lib/krb5/os/hostrealm.c b/src/lib/krb5/os/hostrealm.c
new file mode 100644
index 0000000..87f8ffb
--- /dev/null
+++ b/src/lib/krb5/os/hostrealm.c
@@ -0,0 +1,401 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/krb5/os/hostrealm.c - realm-of-host and default-realm APIs */
+/*
+ * Copyright (C) 2013 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+#include <krb5/hostrealm_plugin.h>
+#include <ctype.h>
+
+struct hostrealm_module_handle {
+    struct krb5_hostrealm_vtable_st vt;
+    krb5_hostrealm_moddata data;
+};
+
+/* Release a list of hostrealm module handles. */
+static void
+free_handles(krb5_context context, struct hostrealm_module_handle **handles)
+{
+    struct hostrealm_module_handle *h, **hp;
+
+    if (handles == NULL)
+        return;
+    for (hp = handles; *hp != NULL; hp++) {
+        h = *hp;
+        if (h->vt.fini != NULL)
+            h->vt.fini(context, h->data);
+        free(h);
+    }
+    free(handles);
+}
+
+/* Get the registered hostrealm modules including all built-in modules, in the
+ * proper order. */
+static krb5_error_code
+get_modules(krb5_context context, krb5_plugin_initvt_fn **modules_out)
+{
+    krb5_error_code ret;
+    const int intf = PLUGIN_INTERFACE_HOSTREALM;
+
+    *modules_out = NULL;
+
+    /* Register built-in modules. */
+    ret = k5_plugin_register(context, intf, "profile",
+                             hostrealm_profile_initvt);
+    if (ret)
+        return ret;
+    ret = k5_plugin_register(context, intf, "dns", hostrealm_dns_initvt);
+    if (ret)
+        return ret;
+    ret = k5_plugin_register(context, intf, "domain", hostrealm_domain_initvt);
+    if (ret)
+        return ret;
+
+    return k5_plugin_load_all(context, intf, modules_out);
+}
+
+/* Initialize context->hostrealm_handles with a list of module handles. */
+static krb5_error_code
+load_hostrealm_modules(krb5_context context)
+{
+    krb5_error_code ret;
+    struct hostrealm_module_handle **list = NULL, *handle;
+    krb5_plugin_initvt_fn *modules = NULL, *mod;
+    size_t count;
+
+    ret = get_modules(context, &modules);
+    if (ret != 0)
+        goto cleanup;
+
+    /* Allocate a large enough list of handles. */
+    for (count = 0; modules[count] != NULL; count++);
+    list = k5alloc((count + 1) * sizeof(*list), &ret);
+    if (list == NULL)
+        goto cleanup;
+
+    /* Initialize each module, ignoring ones that fail. */
+    count = 0;
+    for (mod = modules; *mod != NULL; mod++) {
+        handle = k5alloc(sizeof(*handle), &ret);
+        if (handle == NULL)
+            goto cleanup;
+        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&handle->vt);
+        if (ret != 0) {
+            TRACE_HOSTREALM_VTINIT_FAIL(context, ret);
+            free(handle);
+            continue;
+        }
+
+        handle->data = NULL;
+        if (handle->vt.init != NULL) {
+            ret = handle->vt.init(context, &handle->data);
+            if (ret != 0) {
+                TRACE_HOSTREALM_INIT_FAIL(context, handle->vt.name, ret);
+                free(handle);
+                continue;
+            }
+        }
+        list[count++] = handle;
+        list[count] = NULL;
+    }
+    list[count] = NULL;
+
+    ret = 0;
+    context->hostrealm_handles = list;
+    list = NULL;
+
+cleanup:
+    k5_plugin_free_modules(context, modules);
+    free_handles(context, list);
+    return ret;
+}
+
+/* Invoke a module's host_realm method, if it has one. */
+static krb5_error_code
+host_realm(krb5_context context, struct hostrealm_module_handle *h,
+          const char *host, char ***realms_out)
+{
+    if (h->vt.host_realm == NULL)
+        return KRB5_PLUGIN_NO_HANDLE;
+    return h->vt.host_realm(context, h->data, host, realms_out);
+}
+
+/* Invoke a module's fallback_realm method, if it has one. */
+static krb5_error_code
+fallback_realm(krb5_context context, struct hostrealm_module_handle *h,
+               const char *host, char ***realms_out)
+{
+    if (h->vt.fallback_realm == NULL)
+        return KRB5_PLUGIN_NO_HANDLE;
+    return h->vt.fallback_realm(context, h->data, host, realms_out);
+}
+
+/* Invoke a module's default_realm method, if it has one. */
+static krb5_error_code
+default_realm(krb5_context context, struct hostrealm_module_handle *h,
+              char ***realms_out)
+{
+    if (h->vt.default_realm == NULL)
+        return KRB5_PLUGIN_NO_HANDLE;
+    return h->vt.default_realm(context, h->data, realms_out);
+}
+
+/* Invoke a module's free_list method. */
+static void
+free_list(krb5_context context, struct hostrealm_module_handle *h,
+          char **list)
+{
+    h->vt.free_list(context, h->data, list);
+}
+
+/* Copy a null-terminated list of strings. */
+static krb5_error_code
+copy_list(char **in, char ***out)
+{
+    size_t count, i;
+    char **list;
+
+    *out = NULL;
+    for (count = 0; in[count] != NULL; count++);
+    list = calloc(count + 1, sizeof(*list));
+    if (list == NULL)
+        return ENOMEM;
+    for (i = 0; i < count; i++) {
+        list[i] = strdup(in[i]);
+        if (list[i] == NULL) {
+            krb5_free_host_realm(NULL, list);
+            return ENOMEM;
+        }
+    }
+    *out = list;
+    return 0;
+}
+
+/* Construct a one-element realm list containing a copy of realm. */
+krb5_error_code
+k5_make_realmlist(const char *realm, char ***realms_out)
+{
+    char **realms;
+
+    *realms_out = NULL;
+    realms = calloc(2, sizeof(*realms));
+    if (realms == NULL)
+        return ENOMEM;
+    realms[0] = strdup(realm);
+    if (realms[0] == NULL) {
+        free(realms);
+        return ENOMEM;
+    }
+    *realms_out = realms;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_host_realm(krb5_context context, const char *host, char ***realms_out)
+{
+    krb5_error_code ret;
+    struct hostrealm_module_handle **hp;
+    char **realms, cleanname[1024];
+
+    *realms_out = NULL;
+
+    if (context->hostrealm_handles == NULL) {
+        ret = load_hostrealm_modules(context);
+        if (ret)
+            return ret;
+    }
+
+    ret = k5_clean_hostname(context, host, cleanname, sizeof(cleanname));
+    if (ret)
+        return ret;
+
+    /* Give each module a chance to determine the host's realms. */
+    for (hp = context->hostrealm_handles; *hp != NULL; hp++) {
+        ret = host_realm(context, *hp, cleanname, &realms);
+        if (ret == 0) {
+            ret = copy_list(realms, realms_out);
+            free_list(context, *hp, realms);
+            return ret;
+        } else if (ret != KRB5_PLUGIN_NO_HANDLE) {
+            return ret;
+        }
+    }
+
+    /* Return a list containing the "referral realm" (an empty realm), as a
+     * cue to try referrals. */
+    return k5_make_realmlist(KRB5_REFERRAL_REALM, realms_out);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_fallback_host_realm(krb5_context context, krb5_data *hdata,
+                             char ***realms_out)
+{
+    krb5_error_code ret;
+    struct hostrealm_module_handle **hp;
+    char **realms, *defrealm, *host, cleanname[1024];
+
+    *realms_out = NULL;
+
+    /* Convert hdata into a string and clean it. */
+    host = k5memdup0(hdata->data, hdata->length, &ret);
+    if (host == NULL)
+        return ret;
+    ret = k5_clean_hostname(context, host, cleanname, sizeof(cleanname));
+    free(host);
+    if (ret)
+        return ret;
+
+    if (context->hostrealm_handles == NULL) {
+        ret = load_hostrealm_modules(context);
+        if (ret)
+            return ret;
+    }
+
+    /* Give each module a chance to determine the fallback realms. */
+    for (hp = context->hostrealm_handles; *hp != NULL; hp++) {
+        ret = fallback_realm(context, *hp, cleanname, &realms);
+        if (ret == 0) {
+            ret = copy_list(realms, realms_out);
+            free_list(context, *hp, realms);
+            return ret;
+        } else if (ret != KRB5_PLUGIN_NO_HANDLE) {
+            return ret;
+        }
+    }
+
+    /* Return a list containing the default realm. */
+    ret = krb5_get_default_realm(context, &defrealm);
+    if (ret)
+        return ret;
+    ret = k5_make_realmlist(defrealm, realms_out);
+    krb5_free_default_realm(context, defrealm);
+    return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_free_host_realm(krb5_context context, char *const *list)
+{
+    char *const *p;
+
+    for (p = list; p != NULL && *p != NULL; p++)
+        free(*p);
+    free((char **)list);
+    return 0;
+}
+
+/* Get the system default realm using hostrealm modules. */
+static krb5_error_code
+get_default_realm(krb5_context context, char **realm_out)
+{
+    krb5_error_code ret;
+    struct hostrealm_module_handle **hp;
+    char **realms;
+
+    *realm_out = NULL;
+    if (context->hostrealm_handles == NULL) {
+        ret = load_hostrealm_modules(context);
+        if (ret)
+            return ret;
+    }
+
+    /* Give each module a chance to determine the default realm. */
+    for (hp = context->hostrealm_handles; *hp != NULL; hp++) {
+        ret = default_realm(context, *hp, &realms);
+        if (ret == 0) {
+            if (*realms == NULL) {
+                ret = KRB5_CONFIG_NODEFREALM;
+            } else {
+                *realm_out = strdup(realms[0]);
+                if (*realm_out == NULL)
+                    ret = ENOMEM;
+            }
+            free_list(context, *hp, realms);
+            return ret;
+        } else if (ret != KRB5_PLUGIN_NO_HANDLE) {
+            return ret;
+        }
+    }
+
+    return KRB5_CONFIG_NODEFREALM;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_default_realm(krb5_context context, char **realm_out)
+{
+    krb5_error_code ret;
+
+    *realm_out = NULL;
+
+    if (context == NULL || context->magic != KV5M_CONTEXT)
+        return KV5M_CONTEXT;
+
+    if (context->default_realm == NULL) {
+        ret = get_default_realm(context, &context->default_realm);
+        if (ret)
+            return ret;
+    }
+    *realm_out = strdup(context->default_realm);
+    return (*realm_out == NULL) ? ENOMEM : 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_default_realm(krb5_context context, const char *realm)
+{
+    if (context == NULL || context->magic != KV5M_CONTEXT)
+        return KV5M_CONTEXT;
+
+    if (context->default_realm != NULL) {
+        free(context->default_realm);
+        context->default_realm = NULL;
+    }
+
+    /* Allow the caller to clear the default realm setting by passing NULL. */
+    if (realm != NULL) {
+        context->default_realm = strdup(realm);
+        if (context->default_realm == NULL)
+            return ENOMEM;
+    }
+
+    return 0;
+}
+
+void KRB5_CALLCONV
+krb5_free_default_realm(krb5_context context, char *realm)
+{
+    free(realm);
+}
+
+void
+k5_hostrealm_free_context(krb5_context context)
+{
+    free_handles(context, context->hostrealm_handles);
+    context->hostrealm_handles = NULL;
+}
diff --git a/src/lib/krb5/os/hostrealm_dns.c b/src/lib/krb5/os/hostrealm_dns.c
new file mode 100644
index 0000000..7f017a8
--- /dev/null
+++ b/src/lib/krb5/os/hostrealm_dns.c
@@ -0,0 +1,143 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/krb5/os/hostream_dns.c - dns hostrealm module */
+/*
+ * Copyright (C) 1990,1991,2002,2008,2009,2013 by the Massachusetts Institute
+ * of Technology.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file implements the built-in dns module for the hostrealm interface,
+ * which uses TXT records in the DNS to determine the default realm or the
+ * fallback realm of a host.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+#include <krb5/hostrealm_plugin.h>
+
+#ifdef KRB5_DNS_LOOKUP
+#include "dnsglue.h"
+
+/* Try a _kerberos TXT lookup for fqdn and each parent domain; return the
+ * resulting realm (caller must free) or NULL. */
+static char *
+txt_lookup(krb5_context context, const char *fqdn)
+{
+    char *realm;
+
+    while (fqdn != NULL && *fqdn != '\0') {
+        if (k5_try_realm_txt_rr(context, "_kerberos", fqdn, &realm) == 0)
+            return realm;
+        fqdn = strchr(fqdn, '.');
+        if (fqdn != NULL)
+            fqdn++;
+    }
+    return NULL;
+}
+
+static krb5_error_code
+dns_fallback_realm(krb5_context context, krb5_hostrealm_moddata data,
+                   const char *host, char ***realms_out)
+{
+    krb5_error_code ret;
+    char *realm;
+
+    *realms_out = NULL;
+    if (!_krb5_use_dns_realm(context) || k5_is_numeric_address(host))
+        return KRB5_PLUGIN_NO_HANDLE;
+
+    /* Try a TXT record lookup for each component of host. */
+    realm = txt_lookup(context, host);
+    if (realm == NULL)
+        return KRB5_PLUGIN_NO_HANDLE;
+    ret = k5_make_realmlist(realm, realms_out);
+    free(realm);
+    return ret;
+}
+
+static krb5_error_code
+dns_default_realm(krb5_context context, krb5_hostrealm_moddata data,
+                  char ***realms_out)
+{
+    krb5_error_code ret;
+    char localhost[MAXDNAME + 1], *realm;
+
+    *realms_out = NULL;
+    if (!_krb5_use_dns_realm(context))
+        return KRB5_PLUGIN_NO_HANDLE;
+
+    ret = krb5int_get_fq_local_hostname(localhost, sizeof(localhost));
+    if (ret)
+        return ret;
+
+    /* If we don't find a TXT record for localhost or any parent, look for a
+     * global record. */
+    realm = txt_lookup(context, localhost);
+    if (realm == NULL)
+        (void)k5_try_realm_txt_rr(context, "_kerberos", NULL, &realm);
+
+    if (realm == NULL)
+        return KRB5_PLUGIN_NO_HANDLE;
+    ret = k5_make_realmlist(realm, realms_out);
+    free(realm);
+    return ret;
+}
+
+static void
+dns_free_realmlist(krb5_context context, krb5_hostrealm_moddata data,
+                   char **list)
+{
+    krb5_free_host_realm(context, list);
+}
+
+krb5_error_code
+hostrealm_dns_initvt(krb5_context context, int maj_ver, int min_ver,
+                     krb5_plugin_vtable vtable)
+{
+    krb5_hostrealm_vtable vt = (krb5_hostrealm_vtable)vtable;
+
+    vt->name = "dns";
+    vt->fallback_realm = dns_fallback_realm;
+    vt->default_realm = dns_default_realm;
+    vt->free_list = dns_free_realmlist;
+    return 0;
+}
+
+#else /* KRB5_DNS_LOOKUP */
+
+krb5_error_code
+hostrealm_dns_initvt(krb5_context context, int maj_ver, int min_ver,
+                     krb5_plugin_vtable vtable)
+{
+    krb5_hostrealm_vtable vt = (krb5_hostrealm_vtable)vtable;
+
+    vt->name = "dns";
+    return 0;
+}
+
+#endif /* KRB5_DNS_LOOKUP */
diff --git a/src/lib/krb5/os/hostrealm_domain.c b/src/lib/krb5/os/hostrealm_domain.c
new file mode 100644
index 0000000..dc9cc59
--- /dev/null
+++ b/src/lib/krb5/os/hostrealm_domain.c
@@ -0,0 +1,128 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/krb5/os/hostream_domain.c - domain hostrealm module */
+/*
+ * Copyright (C) 1990,1991,2002,2008,2009,2013 by the Massachusetts Institute
+ * of Technology.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file implements the built-in domain module for the hostrealm interface,
+ * which uses domain-based heuristics to determine the fallback realm of a
+ * host.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+#include <krb5/hostrealm_plugin.h>
+#include <ctype.h>
+
+static krb5_error_code
+domain_fallback_realm(krb5_context context, krb5_hostrealm_moddata data,
+                      const char *host, char ***realms_out)
+{
+    krb5_error_code ret;
+    struct serverlist slist;
+    krb5_data drealm;
+    char *uhost = NULL, *p;
+    const char *suffix, *dot;
+    int limit;
+
+    *realms_out = NULL;
+
+    /* These heuristics don't apply to address literals. */
+    if (k5_is_numeric_address(host))
+        return KRB5_PLUGIN_NO_HANDLE;
+
+    /* Make an uppercase copy of host. */
+    uhost = strdup(host);
+    if (uhost == NULL)
+        return ENOMEM;
+    for (p = uhost; *p != '\0'; p++) {
+        if (islower((unsigned char)*p))
+            *p = toupper((unsigned char)*p);
+    }
+
+    /*
+     * Try searching domain suffixes as realms.  This heuristic is 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.
+     *
+     * A realm_try_domains value of -1 (the default) means not to search at
+     * all, a value of 0 means to try only the full domain itself, 1 means to
+     * also try the parent domain, etc..  We will stop searching when we reach
+     * a suffix with only one label.
+     */
+    ret = profile_get_integer(context->profile, KRB5_CONF_LIBDEFAULTS,
+                              KRB5_CONF_REALM_TRY_DOMAINS, 0, -1, &limit);
+    if (ret)
+        return ret;
+    suffix = uhost;
+    while (limit-- >= 0 && (dot = strchr(suffix, '.')) != NULL) {
+        drealm = string2data((char *)suffix);
+        if (k5_locate_kdc(context, &drealm, &slist, FALSE, SOCK_DGRAM) == 0) {
+            k5_free_serverlist(&slist);
+            ret = k5_make_realmlist(suffix, realms_out);
+            goto cleanup;
+        }
+        suffix = dot + 1;
+    }
+
+    /*
+     * If that didn't succeed, use the upper-cased parent domain of the
+     * hostname, regardless of whether we can actually look it up as a realm.
+     */
+    dot = strchr(uhost, '.');
+    if (dot != NULL)
+        ret = k5_make_realmlist(dot + 1, realms_out);
+    else
+        ret = KRB5_PLUGIN_NO_HANDLE;
+
+cleanup:
+    free(uhost);
+    return ret;
+}
+
+static void
+domain_free_realmlist(krb5_context context, krb5_hostrealm_moddata data,
+                       char **list)
+{
+    krb5_free_host_realm(context, list);
+}
+
+krb5_error_code
+hostrealm_domain_initvt(krb5_context context, int maj_ver, int min_ver,
+                         krb5_plugin_vtable vtable)
+{
+    krb5_hostrealm_vtable vt = (krb5_hostrealm_vtable)vtable;
+
+    vt->name = "domain";
+    vt->fallback_realm = domain_fallback_realm;
+    vt->free_list = domain_free_realmlist;
+    return 0;
+}
diff --git a/src/lib/krb5/os/hostrealm_profile.c b/src/lib/krb5/os/hostrealm_profile.c
new file mode 100644
index 0000000..6b99c05
--- /dev/null
+++ b/src/lib/krb5/os/hostrealm_profile.c
@@ -0,0 +1,117 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/krb5/os/hostream_profile.c - profile hostrealm module */
+/*
+ * Copyright (C) 1990,1991,2002,2008,2009,2013 by the Massachusetts Institute
+ * of Technology.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file implements the built-in profile module for the hostrealm
+ * interface, which uses profile configuration to determine the local default
+ * realm or the authoritative realm of a host.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+#include <krb5/hostrealm_plugin.h>
+
+/*
+ * Search progressively shorter suffixes of host in the [domain_realms] section
+ * of the profile to find the realm.  For example, given a host a.b.c, try to
+ * match a.b.c, then .b.c, then b.c, then .c, then c.  If we don't find a
+ * match, return success but set *realm_out to NULL.
+ */
+static krb5_error_code
+profile_host_realm(krb5_context context, krb5_hostrealm_moddata data,
+                   const char *host, char ***realms_out)
+{
+    krb5_error_code ret;
+    const char *p;
+    char *prof_realm;
+
+    *realms_out = NULL;
+
+    /* Don't look up IP addresses in [domain_realms]. */
+    if (k5_is_numeric_address(host))
+        return KRB5_PLUGIN_NO_HANDLE;
+
+    /* Look for the host and each suffix in the [domain_realms] section. */
+    for (p = host; p != NULL; p = (*p == '.') ? p + 1 : strchr(p, '.')) {
+        ret = profile_get_string(context->profile, KRB5_CONF_DOMAIN_REALM, p,
+                                 NULL, NULL, &prof_realm);
+        if (ret)
+            return ret;
+        if (prof_realm != NULL) {
+            ret = k5_make_realmlist(prof_realm, realms_out);
+            profile_release_string(prof_realm);
+            return ret;
+        }
+    }
+    return KRB5_PLUGIN_NO_HANDLE;
+}
+
+/* Look up the default_realm variable in the [libdefaults] section of the
+ * profile. */
+static krb5_error_code
+profile_default_realm(krb5_context context, krb5_hostrealm_moddata data,
+                      char ***realms_out)
+{
+    krb5_error_code ret;
+    char *prof_realm;
+
+    *realms_out = NULL;
+    ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
+                             KRB5_CONF_DEFAULT_REALM, NULL, NULL, &prof_realm);
+    if (ret)
+        return ret;
+    if (prof_realm == NULL)
+        return KRB5_PLUGIN_NO_HANDLE;
+    ret = k5_make_realmlist(prof_realm, realms_out);
+    profile_release_string(prof_realm);
+    return ret;
+}
+
+static void
+profile_free_realmlist(krb5_context context, krb5_hostrealm_moddata data,
+                       char **list)
+{
+    krb5_free_host_realm(context, list);
+}
+
+krb5_error_code
+hostrealm_profile_initvt(krb5_context context, int maj_ver, int min_ver,
+                         krb5_plugin_vtable vtable)
+{
+    krb5_hostrealm_vtable vt = (krb5_hostrealm_vtable)vtable;
+
+    vt->name = "profile";
+    vt->host_realm = profile_host_realm;
+    vt->default_realm = profile_default_realm;
+    vt->free_list = profile_free_realmlist;
+    return 0;
+}
diff --git a/src/lib/krb5/os/hst_realm.c b/src/lib/krb5/os/hst_realm.c
index 0c1579b..7cb7c5f 100644
--- a/src/lib/krb5/os/hst_realm.c
+++ b/src/lib/krb5/os/hst_realm.c
@@ -34,14 +34,6 @@
 
 #include "fake-addrinfo.h"
 
-#ifdef KRB5_DNS_LOOKUP
-#include "dnsglue.h"
-#else
-#ifndef MAXDNAME
-#define MAXDNAME (16 * MAXHOSTNAMELEN)
-#endif /* MAXDNAME */
-#endif /* KRB5_DNS_LOOKUP */
-
 #if defined(_WIN32) && !defined(__CYGWIN32__)
 #ifndef EAFNOSUPPORT
 #define EAFNOSUPPORT WSAEAFNOSUPPORT
@@ -117,8 +109,8 @@ krb5int_get_fq_local_hostname(char *buf, size_t bufsize)
 }
 
 /* Return true if name appears to be an IPv4 or IPv6 address. */
-static krb5_boolean
-is_numeric_address(const char *name)
+krb5_boolean
+k5_is_numeric_address(const char *name)
 {
     int ndots = 0;
     const char *p;
@@ -141,236 +133,6 @@ is_numeric_address(const char *name)
     return FALSE;
 }
 
-/*
- * Search progressively shorter suffixes of host in the [domain_realms] section
- * of the profile to find the realm.  For example, given a host a.b.c, try to
- * match a.b.c, then .b.c, then b.c, then .c, then c.  If we don't find a
- * match, return success but set *realm_out to NULL.
- */
-static krb5_error_code
-search_domain_realm(krb5_context context, const char *host, char **realm_out)
-{
-    krb5_error_code ret;
-    const char *p;
-    char *prof_realm;
-
-    *realm_out = NULL;
-    for (p = host; p != NULL; p = (*p == '.') ? p + 1 : strchr(p, '.')) {
-        ret = profile_get_string(context->profile, KRB5_CONF_DOMAIN_REALM, p,
-                                 NULL, NULL, &prof_realm);
-        if (ret)
-            return ret;
-        if (prof_realm != NULL) {
-            *realm_out = strdup(prof_realm);
-            profile_release_string(prof_realm);
-            if (*realm_out == NULL)
-                return ENOMEM;
-            return 0;
-        }
-    }
-    return 0;
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_get_host_realm(krb5_context context, const char *host, char ***realmsp)
-{
-    char **retrealms, *realm = NULL;
-    krb5_error_code ret;
-    char cleanname[MAXDNAME + 1];
-
-    *realmsp = NULL;
-
-    ret = k5_clean_hostname(context, host, cleanname, sizeof(cleanname));
-    if (ret)
-        return ret;
-
-    /* Search the [domain_realm] profile section unless the hostname looks like
-     * an IP address. */
-    if (!is_numeric_address(cleanname))
-        ret = search_domain_realm(context, cleanname, &realm);
-
-    /* If we didn't find a match, return the referral realm. */
-    if (realm == NULL) {
-        realm = strdup(KRB5_REFERRAL_REALM);
-        if (realm == NULL)
-            return ENOMEM;
-    }
-
-    retrealms = calloc(2, sizeof(*retrealms));
-    if (retrealms == NULL) {
-        free(realm);
-        return ENOMEM;
-    }
-
-    retrealms[0] = realm;
-    retrealms[1] = 0;
-
-    TRACE_GET_HOST_REALM_RETURN(context, host, realm);
-    *realmsp = retrealms;
-    return 0;
-}
-
-/*
- * 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 ret = 0, r;
-    struct serverlist slist;
-    krb5_data drealm;
-    char *p = NULL, *fqdn, *dot;
-
-    *realm = NULL;
-    if (limit < 0)
-        return 0;
-
-    memset(&drealm, 0, sizeof(drealm));
-    fqdn = strdup(domain);
-    if (fqdn == NULL) {
-        ret = ENOMEM;
-        goto cleanup;
-    }
-
-    /* Upper case the domain (for use as a realm). */
-    for (p = fqdn; *p != '\0'; p++) {
-        if (islower((unsigned char)*p))
-            *p = toupper((unsigned char)*p);
-    }
-
-    /* Search up to limit parents, as long as we have multiple labels. */
-    p = fqdn;
-    while (limit-- >= 0 && (dot = strchr(p, '.')) != NULL) {
-        /* Find a KDC based on this part of the domain name. */
-        drealm = string2data(p);
-        r = k5_locate_kdc(context, &drealm, &slist, FALSE, SOCK_DGRAM);
-        if (r == 0) {
-            k5_free_serverlist(&slist);
-            *realm = strdup(p);
-            if (*realm == NULL) {
-                ret = ENOMEM;
-                goto cleanup;
-            }
-            break;
-        }
-
-        p = dot + 1;
-    }
-
-cleanup:
-    free(fqdn);
-    return ret;
-}
-
-/*
- * Determine the fallback realm.  Used by krb5_get_credentials after referral
- * processing has failed, to look at TXT records or make a DNS-based
- * assumption.
- */
-krb5_error_code KRB5_CALLCONV
-krb5_get_fallback_host_realm(krb5_context context, krb5_data *hdata,
-                             char ***realmsp)
-{
-    char **retrealms, *p, *realm = NULL, *host, cleanname[MAXDNAME + 1];
-    krb5_error_code ret;
-    int limit;
-    errcode_t code;
-    krb5_boolean is_numeric;
-
-    *realmsp = NULL;
-
-    /* Convert hdata into a string and clean it up. */
-    host = k5memdup0(hdata->data, hdata->length, &ret);
-    if (host == NULL)
-        return ret;
-    ret = k5_clean_hostname(context, host, cleanname, sizeof(cleanname));
-    free(host);
-    if (ret)
-        return ret;
-    is_numeric = is_numeric_address(cleanname);
-
-    /*
-     * 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.
-     */
-#ifdef KRB5_DNS_LOOKUP
-    if (_krb5_use_dns_realm(context) && !is_numeric) {
-        p = cleanname;
-        do {
-            ret = k5_try_realm_txt_rr(context, "_kerberos", p, &realm);
-            p = strchr(p, '.');
-            if (p != NULL)
-                p++;
-        } while (ret && p != NULL && *p != '\0');
-    }
-#endif /* 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 == NULL && !is_numeric) {
-        code = profile_get_integer(context->profile, KRB5_CONF_LIBDEFAULTS,
-                                   KRB5_CONF_REALM_TRY_DOMAINS, 0, -1, &limit);
-        if (code == 0) {
-            ret = domain_heuristic(context, cleanname, &realm, limit);
-            if (ret)
-                return ret;
-        }
-    }
-
-    /*
-     * 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 == NULL && !is_numeric) {
-        p = strchr(cleanname, '.');
-        if (p) {
-            realm = strdup(p + 1);
-            if (realm == NULL)
-                return ENOMEM;
-            for (p = realm; *p != '\0'; p++) {
-                if (islower((unsigned char)*p))
-                    *p = toupper((unsigned char)*p);
-            }
-        }
-    }
-
-    /*
-     * The final fallback--used when the fully-qualified hostname has only one
-     * component--is to use the local default realm.
-     */
-    if (realm == NULL) {
-        ret = krb5_get_default_realm(context, &realm);
-        if (ret)
-            return ret;
-    }
-
-    retrealms = calloc(2, sizeof(*retrealms));
-    if (retrealms == NULL) {
-        free(realm);
-        return ENOMEM;
-    }
-
-    retrealms[0] = realm;
-    retrealms[1] = 0;
-
-    TRACE_GET_FALLBACK_HOST_REALM_RETURN(context, host, realm);
-    *realmsp = retrealms;
-    return 0;
-}
-
 /* Common code for krb5_get_host_realm and krb5_get_fallback_host_realm
  * to do basic sanity checks on supplied hostname. */
 krb5_error_code
@@ -404,16 +166,3 @@ k5_clean_hostname(krb5_context context, const char *host, char *cleanname,
 
     return 0;
 }
-
-krb5_error_code KRB5_CALLCONV
-krb5_free_host_realm(krb5_context context, char *const *realmlist)
-{
-    char *const *p;
-
-    if (realmlist == NULL)
-        return 0;
-    for (p = realmlist; *p; p++)
-        free(*p);
-    free((char **)realmlist);
-    return 0;
-}
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index e2891a1..c6b730f 100644
--- a/src/lib/krb5/os/os-proto.h
+++ b/src/lib/krb5/os/os-proto.h
@@ -133,6 +133,8 @@ krb5_error_code k5_time_with_offset(krb5_timestamp offset,
                                     krb5_int32 *usec_out);
 void k5_set_prompt_types(krb5_context, krb5_prompt_type *);
 krb5_error_code k5_clean_hostname(krb5_context, const char *, char *, size_t);
+krb5_boolean k5_is_numeric_address(const char *name);
+krb5_error_code k5_make_realmlist(const char *realm, char ***realms_out);
 krb5_error_code k5_kt_client_default_name(krb5_context context,
                                           char **name_out);
 krb5_error_code k5_write_messages(krb5_context, krb5_pointer, krb5_data *,
@@ -146,6 +148,16 @@ extern unsigned int krb5_max_skdc_timeout;
 extern unsigned int krb5_skdc_timeout_shift;
 extern unsigned int krb5_skdc_timeout_1;
 
+void k5_hostrealm_free_context(krb5_context);
+krb5_error_code hostrealm_profile_initvt(krb5_context context, int maj_ver,
+                                         int min_ver,
+                                         krb5_plugin_vtable vtable);
+krb5_error_code hostrealm_dns_initvt(krb5_context context, int maj_ver,
+                                     int min_ver, krb5_plugin_vtable vtable);
+krb5_error_code hostrealm_domain_initvt(krb5_context context, int maj_ver,
+                                        int min_ver,
+                                        krb5_plugin_vtable vtable);
+
 void k5_localauth_free_context(krb5_context);
 krb5_error_code localauth_names_initvt(krb5_context context, int maj_ver,
                                        int min_ver, krb5_plugin_vtable vtable);


More information about the cvs-krb5 mailing list