krb5 commit: Clean up domain->realm referrals

Tom Yu tlyu at MIT.EDU
Mon Oct 15 20:27:44 EDT 2012


https://github.com/krb5/krb5/commit/2b03bb01e37faee55b9e60c90cc8076549de0d6d
commit 2b03bb01e37faee55b9e60c90cc8076549de0d6d
Author: Tom Yu <tlyu at mit.edu>
Date:   Fri Sep 21 20:49:29 2012 -0400

    Clean up domain->realm referrals
    
    Clean up domain->realm referrals by breaking prep_reprocess_tgs_req()
    into smaller functions.  Give the resulting functions more descriptive
    names.  Also delete an unnecessary and almost exact copy of
    krb5_get_host_realm().

 src/kdc/do_tgs_req.c  |  172 +++++++++++++++++++++++++------------------------
 src/kdc/kdc_transit.c |    2 +-
 src/kdc/kdc_util.c    |   59 -----------------
 src/kdc/kdc_util.h    |    2 +
 4 files changed, 91 insertions(+), 144 deletions(-)

diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 52d456e..cb9e142 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -77,7 +77,7 @@ prepare_error_tgs(struct kdc_request_state *, krb5_kdc_req *,krb5_ticket *,int,
                   krb5_principal,krb5_data **,const char *, krb5_pa_data **);
 
 static krb5_int32
-prep_reprocess_req(kdc_realm_t *, krb5_kdc_req *, krb5_principal *);
+find_referral_tgs(kdc_realm_t *, krb5_kdc_req *, krb5_principal *);
 
 static krb5_error_code
 db_get_svc_princ(krb5_context, krb5_principal, krb5_flags,
@@ -1065,94 +1065,99 @@ cleanup:
     return retval;
 }
 
-static krb5_int32
-prep_reprocess_req(kdc_realm_t *kdc_active_realm, krb5_kdc_req *request,
-                   krb5_principal *krbtgt_princ)
+/*
+ * Check whether the request satisfies the conditions for generating a referral
+ * TGT.  The caller checks whether the hostname component looks like a FQDN.
+ */
+static krb5_boolean
+is_referral_req(kdc_realm_t *kdc_active_realm, krb5_kdc_req *request)
 {
-    krb5_error_code retval = KRB5KRB_AP_ERR_BADMATCH;
-    char **realms, **cpp, *temp_buf=NULL;
-    krb5_data *comp1 = NULL, *comp2 = NULL;
-    char *comp1_str = NULL;
-
-    /* By now we know that server principal name is unknown.
-     * If CANONICALIZE flag is set in the request
-     * If req is not U2U authn. req
-     * the requested server princ. has exactly two components
-     * either
-     *      the name type is NT-SRV-HST
-     *      or name type is NT-UNKNOWN and
-     *         the 1st component is listed in conf file under host_based_services
-     * the 1st component is not in a list in conf under "no_host_referral"
-     * the 2d component looks like fully-qualified domain name (FQDN)
-     * If all of these conditions are satisfied - try mapping the FQDN and
-     * re-process the request as if client had asked for cross-realm TGT.
-     */
-    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE) &&
-        !isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY) &&
-        krb5_princ_size(kdc_context, request->server) == 2) {
-
-        comp1 = krb5_princ_component(kdc_context, request->server, 0);
-        comp2 = krb5_princ_component(kdc_context, request->server, 1);
-
-        comp1_str = calloc(1,comp1->length+1);
-        if (!comp1_str) {
-            retval = ENOMEM;
-            goto cleanup;
-        }
-        strlcpy(comp1_str,comp1->data,comp1->length+1);
-
-        if ((krb5_princ_type(kdc_context, request->server) == KRB5_NT_SRV_HST ||
-             krb5_princ_type(kdc_context, request->server) == KRB5_NT_SRV_INST ||
-             (krb5_princ_type(kdc_context, request->server) == KRB5_NT_UNKNOWN &&
-              kdc_active_realm->realm_host_based_services != NULL &&
-              (krb5_match_config_pattern(kdc_active_realm->realm_host_based_services,
-                                         comp1_str) == TRUE ||
-               krb5_match_config_pattern(kdc_active_realm->realm_host_based_services,
-                                         KRB5_CONF_ASTERISK) == TRUE))) &&
-            (kdc_active_realm->realm_no_host_referral == NULL ||
-             (krb5_match_config_pattern(kdc_active_realm->realm_no_host_referral,
-                                        KRB5_CONF_ASTERISK) == FALSE &&
-              krb5_match_config_pattern(kdc_active_realm->realm_no_host_referral,
-                                        comp1_str) == FALSE))) {
-
-            if (memchr(comp2->data, '.', comp2->length) == NULL)
-                goto cleanup;
-            temp_buf = calloc(1, comp2->length+1);
-            if (!temp_buf) {
-                retval = ENOMEM;
+    krb5_boolean ret = FALSE;
+    char *stype = NULL;
+    char *ref_services = kdc_active_realm->realm_host_based_services;
+    char *nonref_services = kdc_active_realm->realm_no_host_referral;
+
+    if (!(request->kdc_options & KDC_OPT_CANONICALIZE))
+        return FALSE;
+
+    if (request->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY)
+        return FALSE;
+
+    if (krb5_princ_size(kdc_context, request->server) != 2)
+        return FALSE;
+
+    stype = data2string(krb5_princ_component(kdc_context, request->server, 0));
+    if (stype == NULL)
+        return FALSE;
+    switch (krb5_princ_type(kdc_context, request->server)) {
+    case KRB5_NT_UNKNOWN:
+        /* Allow referrals for NT-UNKNOWN principals, if configured. */
+        if (kdc_active_realm->realm_host_based_services != NULL) {
+            if (!krb5_match_config_pattern(ref_services, stype) &&
+                !krb5_match_config_pattern(ref_services, KRB5_CONF_ASTERISK))
                 goto cleanup;
-            }
-            strlcpy(temp_buf, comp2->data,comp2->length+1);
-            retval = krb5int_get_domain_realm_mapping(kdc_context, temp_buf, &realms);
-            free(temp_buf);
-            if (retval) {
-                /* no match found */
-                kdc_err(kdc_context, retval, "unable to find realm of host");
-                goto cleanup;
-            }
-            if (realms == 0) {
-                retval = KRB5KRB_AP_ERR_BADMATCH;
+        } else
+            goto cleanup;
+        /* FALLTHROUGH */
+    case KRB5_NT_SRV_HST:
+    case KRB5_NT_SRV_INST:
+        /* Deny referrals for specific service types, if configured. */
+        if (kdc_active_realm->realm_no_host_referral != NULL) {
+            if (krb5_match_config_pattern(nonref_services, stype))
                 goto cleanup;
-            }
-            if (realms[0] == 0) {
-                free(realms);
-                retval = KRB5KRB_AP_ERR_BADMATCH;
+            if (krb5_match_config_pattern(nonref_services, KRB5_CONF_ASTERISK))
                 goto cleanup;
-            }
-            /* Modify request.
-             * Construct cross-realm tgt :  krbtgt/REMOTE_REALM at LOCAL_REALM
-             * and use it as a principal in this req.
-             */
-            retval = krb5_build_principal(kdc_context, krbtgt_princ,
-                                          (*request->server).realm.length,
-                                          (*request->server).realm.data,
-                                          "krbtgt", realms[0], (char *)0);
-            for (cpp = realms; *cpp; cpp++)
-                free(*cpp);
         }
+        ret = TRUE;
+        break;
+    default:
+        goto cleanup;
+    }
+cleanup:
+    free(stype);
+    return ret;
+}
+
+/*
+ * Find a remote realm TGS principal for an unknown host-based service
+ * principal.
+ */
+static krb5_int32
+find_referral_tgs(kdc_realm_t *kdc_active_realm, krb5_kdc_req *request,
+                  krb5_principal *krbtgt_princ)
+{
+    krb5_error_code retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+    char **realms = NULL, *hostname = NULL;
+    krb5_data srealm = request->server->realm;
+
+    if (!is_referral_req(kdc_active_realm, request))
+        goto cleanup;
+
+    hostname = data2string(krb5_princ_component(kdc_context,
+                                                request->server, 1));
+    if (hostname == NULL) {
+        retval = ENOMEM;
+        goto cleanup;
+    }
+    /* If the hostname doesn't contain a '.', it's not a FQDN. */
+    if (strchr(hostname, '.') == NULL)
+        goto cleanup;
+    retval = krb5_get_host_realm(kdc_context, hostname, &realms);
+    if (retval) {
+        /* no match found */
+        kdc_err(kdc_context, retval, "unable to find realm of host");
+        goto cleanup;
+    }
+    if (realms == NULL || realms[0] == '\0') {
+        retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+        goto cleanup;
     }
+    retval = krb5_build_principal(kdc_context, krbtgt_princ,
+                                  srealm.length, srealm.data,
+                                  "krbtgt", realms[0], (char *)0);
 cleanup:
-    free(comp1_str);
+    krb5_free_host_realm(kdc_context, realms);
+    free(hostname);
 
     return retval;
 }
@@ -1186,8 +1191,7 @@ search_sprinc(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
         goto cleanup;
 
     if (!is_cross_tgs_principal(req->server)) {
-        /* domain->realm referral */
-        ret = prep_reprocess_req(kdc_active_realm, req, &reftgs);
+        ret = find_referral_tgs(kdc_active_realm, req, &reftgs);
         if (ret != 0)
             goto cleanup;
         ret = db_get_svc_princ(kdc_context, reftgs, flags, server, status);
diff --git a/src/kdc/kdc_transit.c b/src/kdc/kdc_transit.c
index 88b4616..9947761 100644
--- a/src/kdc/kdc_transit.c
+++ b/src/kdc/kdc_transit.c
@@ -129,7 +129,7 @@ subrealm(char *r1, char *r2)
  *        names.
  */
 
-static char *
+char *
 data2string (krb5_data *d)
 {
     char *s;
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 10ed383..387a76c 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1881,65 +1881,6 @@ cleanup:
     return retval;
 }
 
-
-krb5_error_code
-krb5int_get_domain_realm_mapping(krb5_context context,
-                                 const char *host, char ***realmsp)
-{
-    char **retrealms;
-    char *realm, *cp, *temp_realm;
-    krb5_error_code retval;
-    char temp_host[MAX_DNS_NAMELEN+1];
-
-    /* do sanity check and lower-case */
-    retval = krb5int_clean_hostname(context, host, temp_host, sizeof temp_host);
-    if (retval)
-        return retval;
-    /*
-      Search for the best match for the host or domain.
-      Example: Given a host a.b.c.d, try to match on:
-      1) a.b.c.d  2) .b.c.d.   3) b.c.d  4)  .c.d  5) c.d  6) .d   7) d
-    */
-
-    cp = temp_host;
-    realm = (char *)NULL;
-    temp_realm = 0;
-    while (cp ) {
-        retval = profile_get_string(context->profile, KRB5_CONF_DOMAIN_REALM, cp,
-                                    0, (char *)NULL, &temp_realm);
-        if (retval)
-            return retval;
-        if (temp_realm != (char *)NULL)
-            break;        /* Match found */
-
-        /* Setup for another test */
-        if (*cp == '.') {
-            cp++;
-        } else {
-            cp = strchr(cp, '.');
-        }
-    }
-    if (temp_realm != (char*)NULL) {
-        realm = strdup(temp_realm);
-        profile_release_string(temp_realm);
-        if (!realm) {
-            return ENOMEM;
-        }
-    }
-    retrealms = (char **)calloc(2, sizeof(*retrealms));
-    if (!retrealms) {
-        if (realm != (char *)NULL)
-            free(realm);
-        return ENOMEM;
-    }
-
-    retrealms[0] = realm;
-    retrealms[1] = 0;
-
-    *realmsp = retrealms;
-    return 0;
-}
-
 /*
  * Although the KDC doesn't call this function directly,
  * process_tcp_connection_read() in net-server.c does call it.
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index b89bd99..8a5c66a 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -400,4 +400,6 @@ int check_anon(kdc_realm_t *kdc_active_realm,
                krb5_principal client, krb5_principal server);
 int errcode_to_protocol(krb5_error_code code);
 
+char *data2string(krb5_data *d);
+
 #endif /* __KRB5_KDC_UTIL__ */


More information about the cvs-krb5 mailing list