Eliminate domain-based client realm walk
authorGreg Hudson <ghudson@mit.edu>
Wed, 28 Sep 2011 17:03:15 +0000 (17:03 +0000)
committerGreg Hudson <ghudson@mit.edu>
Wed, 28 Sep 2011 17:03:15 +0000 (17:03 +0000)
For a very long time, KDCs have known how to perform a domain-based
realm walk when serving requests for TGTs.  (So if a KDC for A.B.C
receives a request for krbtgt/X.B.C and doesn't have that principal,
it can return one for krbtgt/B.C instead.)  Performing the same
heuristic on the client is unnecessary and inefficient in common
cases.

Add a new function k5_client_realm_path to walk_rtree.c which uses
capaths values only, and returns a list of realms (as desired by
get_creds.c) instead of TGT names.

ticket: 6966

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25241 dc483132-0cff-0310-8789-dd5450dbe970

src/include/k5-int.h
src/lib/krb5/krb/get_creds.c
src/lib/krb5/krb/walk_rtree.c

index 0bb4c164d0fcdb713b7233340ca932c6c67b9d12..1682a345b987a6f3cb2a3193459734705a3ae603 100644 (file)
@@ -2628,6 +2628,10 @@ krb5_error_code krb5_walk_realm_tree(krb5_context, const krb5_data *,
                                      const krb5_data *, krb5_principal **,
                                      int);
 
+krb5_error_code
+k5_client_realm_path(krb5_context context, const krb5_data *client,
+                     const krb5_data *server, krb5_data **rpath_out);
+
 krb5_error_code
 krb5_auth_con_set_safe_cksumtype(krb5_context, krb5_auth_context,
                                  krb5_cksumtype);
index 7c8230b32dcf495470887ad629d3559304d75ef2..f229ba1c343e479bc8a2331b65ae56052d0b0ad3 100644 (file)
@@ -697,7 +697,7 @@ begin_get_tgt_offpath(krb5_context context, krb5_tkt_creds_context ctx)
 
 /*
  * To obtain a foreign TGT, we first construct a path of realms R1..Rn between
- * the local realm and the target realm, using krb5_walk_realm_tree().  Usually
+ * the local realm and the target realm, using k5_client_realm_path().  Usually
  * this path is based on the domain hierarchy, but it may be altered by
  * configuration.
  *
@@ -775,32 +775,16 @@ static krb5_error_code
 init_realm_path(krb5_context context, krb5_tkt_creds_context ctx)
 {
     krb5_error_code code;
-    krb5_principal *tgt_princ_list = NULL;
     krb5_data *realm_path;
-    size_t nrealms, i;
+    size_t nrealms;
 
-    /* Construct a list of TGT principals from client to server.  We will throw
-     * this away after grabbing the remote realms from each principal. */
-    code = krb5_walk_realm_tree(context, &ctx->client->realm,
-                                &ctx->server->realm,
-                                &tgt_princ_list, KRB5_REALM_BRANCH_CHAR);
+    /* Get the client realm path and count its length. */
+    code = k5_client_realm_path(context, &ctx->client->realm,
+                                &ctx->server->realm, &realm_path);
     if (code != 0)
         return code;
-
-    /* Count the number of principals and allocate the realm path. */
-    for (nrealms = 0; tgt_princ_list[nrealms]; nrealms++);
+    for (nrealms = 0; realm_path[nrealms].data != NULL; nrealms++);
     assert(nrealms > 1);
-    realm_path = k5alloc((nrealms + 1) * sizeof(*realm_path), &code);
-    if (realm_path == NULL)
-        goto cleanup;
-
-    /* Steal the remote realm field from each TGT principal. */
-    for (i = 0; i < nrealms; i++) {
-        assert(tgt_princ_list[i]->length == 2);
-        realm_path[i] = tgt_princ_list[i]->data[1];
-        tgt_princ_list[i]->data[1].data = NULL;
-    }
-    realm_path[nrealms] = empty_data();
 
     /* Initialize the realm path fields in ctx. */
     krb5int_free_data_list(context, ctx->realm_path);
@@ -808,10 +792,6 @@ init_realm_path(krb5_context context, krb5_tkt_creds_context ctx)
     ctx->last_realm = realm_path + nrealms - 1;
     ctx->cur_realm = realm_path;
     ctx->next_realm = ctx->last_realm;
-    realm_path = NULL;
-
-cleanup:
-    krb5_free_realm_tree(context, tgt_princ_list);
     return 0;
 }
 
index 6aba24f8a5b1a1f6e3afb26ffd5f2e5cf02dd07e..10711f1d67d882ab9a60ecc5373b31ba8a242490 100644 (file)
@@ -122,6 +122,50 @@ krb5_walk_realm_tree( krb5_context context,
     return retval;
 }
 
+krb5_error_code
+k5_client_realm_path(krb5_context context, const krb5_data *client,
+                     const krb5_data *server, krb5_data **rpath_out)
+{
+    krb5_error_code retval;
+    char **capvals;
+    size_t i;
+    krb5_data *rpath = NULL, d;
+
+    retval = rtree_capath_vals(context, client, server, &capvals);
+    if (retval)
+        return retval;
+
+    /* Count capaths (if any) and allocate space.  Leave room for the client
+     * realm, server realm, and terminator. */
+    for (i = 0; capvals != NULL && capvals[i] != NULL; i++);
+    rpath = calloc(i + 3, sizeof(*rpath));
+    if (rpath == NULL)
+        return ENOMEM;
+
+    /* Populate rpath with the client realm, capaths, and server realm. */
+    retval = krb5int_copy_data_contents(context, client, &rpath[0]);
+    if (retval)
+        goto cleanup;
+    for (i = 0; capvals != NULL && capvals[i] != NULL; i++) {
+        d = make_data(capvals[i], strcspn(capvals[i], "\t "));
+        retval = krb5int_copy_data_contents(context, &d, &rpath[i + 1]);
+        if (retval)
+            goto cleanup;
+    }
+    retval = krb5int_copy_data_contents(context, server, &rpath[i + 1]);
+    if (retval)
+        goto cleanup;
+
+    /* Terminate rpath and return it. */
+    rpath[i + 2] = empty_data();
+    *rpath_out = rpath;
+    rpath = NULL;
+
+cleanup:
+    krb5int_free_data_list(context, rpath);
+    return retval;
+}
+
 /* ANL - Modified to allow Configurable Authentication Paths.
  * This modification removes the restriction on the choice of realm
  * names, i.e. they nolonger have to be hierarchical. This