[29020] in CVS-changelog-for-Kerberos-V5

home help back first fref pref prev next nref lref last post

krb5 commit: Make cross-realm S4U2Self work

daemon@ATHENA.MIT.EDU (Greg Hudson)
Thu Aug 13 11:54:24 2015

Date: Thu, 13 Aug 2015 11:53:29 -0400
From: Greg Hudson <ghudson@mit.edu>
Message-Id: <201508131553.t7DFrTVd012813@drugstore.mit.edu>
To: cvs-krb5@mit.edu
Reply-To: krbdev@mit.edu
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: cvs-krb5-bounces@mit.edu

https://github.com/krb5/krb5/commit/16128e80d30b4f5e03c2f4fd3d1024216eed3fa4
commit 16128e80d30b4f5e03c2f4fd3d1024216eed3fa4
Author: Greg Hudson <ghudson@mit.edu>
Date:   Mon Aug 3 20:45:17 2015 -0400

    Make cross-realm S4U2Self work
    
    When sending a S4U2Self query to a foreign realm, send an enterprise
    server principal so that the foreign KDC can identify the home realm
    of the server principal.
    
    To make this work, adjust the memory management of
    krb5_get_self_cred_from_kdc().  s4u_creds is now a shallow copy of
    in_creds which owns no memory.  A new variable eprinc owns the
    enterprise form of the server principal, constructed using a new
    helper function convert_to_enterprise().  Since we have to set the
    server realm for KDC-REQ encoding to work, a new temporary variable
    sprinc holds a shallow copy of *eprinc with the realm pointing to the
    realm we are currently querying.
    
    Based on a patch by Sumit Bose.
    
    ticket: 7790

 src/lib/krb5/krb/s4u_creds.c |   58 ++++++++++++++++++++++++++---------------
 src/tests/gssapi/t_s4u.py    |   17 ++++++++++++
 2 files changed, 54 insertions(+), 21 deletions(-)

diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
index c85c0d4..ed05b67 100644
--- a/src/lib/krb5/krb/s4u_creds.c
+++ b/src/lib/krb5/krb/s4u_creds.c
@@ -440,6 +440,24 @@ cleanup:
     return code;
 }
 
+/* Unparse princ and re-parse it as an enterprise principal. */
+static krb5_error_code
+convert_to_enterprise(krb5_context context, krb5_principal princ,
+                      krb5_principal *eprinc_out)
+{
+    krb5_error_code code;
+    char *str;
+
+    *eprinc_out = NULL;
+    code = krb5_unparse_name(context, princ, &str);
+    if (code != 0)
+        return code;
+    code = krb5_parse_name_flags(context, str, KRB5_PRINCIPAL_PARSE_ENTERPRISE,
+                                 eprinc_out);
+    krb5_free_unparsed_name(context, str);
+    return code;
+}
+
 static krb5_error_code
 krb5_get_self_cred_from_kdc(krb5_context context,
                             krb5_flags options,
@@ -450,7 +468,8 @@ krb5_get_self_cred_from_kdc(krb5_context context,
                             krb5_creds **out_creds)
 {
     krb5_error_code code;
-    krb5_principal tgs = NULL;
+    krb5_principal tgs = NULL, eprinc = NULL;
+    krb5_principal_data sprinc;
     krb5_creds tgtq, s4u_creds, *tgt = NULL, *tgtptr;
     krb5_creds *referral_tgts[KRB5_REFERRAL_MAXHOPS];
     krb5_pa_s4u_x509_user s4u_user;
@@ -458,7 +477,6 @@ krb5_get_self_cred_from_kdc(krb5_context context,
     krb5_flags kdcopt;
 
     memset(&tgtq, 0, sizeof(tgtq));
-    memset(&s4u_creds, 0, sizeof(s4u_creds));
     memset(referral_tgts, 0, sizeof(referral_tgts));
     *out_creds = NULL;
 
@@ -510,18 +528,16 @@ krb5_get_self_cred_from_kdc(krb5_context context,
 
     tgtptr = tgt;
 
-    code = k5_copy_creds_contents(context, in_creds, &s4u_creds);
+    /* Convert the server principal to an enterprise principal, for use with
+     * foreign realms. */
+    code = convert_to_enterprise(context, in_creds->server, &eprinc);
     if (code != 0)
         goto cleanup;
 
-    if (s4u_creds.client != NULL) {
-        krb5_free_principal(context, s4u_creds.client);
-        s4u_creds.client = NULL;
-    }
-
-    code = krb5_copy_principal(context, in_creds->server, &s4u_creds.client);
-    if (code != 0)
-        goto cleanup;
+    /* Make a shallow copy of in_creds with client pointing to the server
+     * principal.  We will set s4u_creds.server for each request. */
+    s4u_creds = *in_creds;
+    s4u_creds.client = in_creds->server;
 
     /* Then, walk back the referral path to S4U2Self for user */
     kdcopt = 0;
@@ -556,15 +572,15 @@ krb5_get_self_cred_from_kdc(krb5_context context,
             }
         }
 
-        /* Rewrite server realm to match TGS realm */
-        krb5_free_data_contents(context, &s4u_creds.server->realm);
-
-        code = krb5int_copy_data_contents(context,
-                                          &tgtptr->server->data[1],
-                                          &s4u_creds.server->realm);
-        if (code != 0) {
-            krb5_free_pa_data(context, in_padata);
-            goto cleanup;
+        if (data_eq(tgtptr->server->data[1], in_creds->server->realm)) {
+            /* When asking the server realm, use the real principal. */
+            s4u_creds.server = in_creds->server;
+        } else {
+            /* When asking a foreign realm, use the enterprise principal, with
+             * the realm set to the TGS realm. */
+            sprinc = *eprinc;
+            sprinc.realm = tgtptr->server->data[1];
+            s4u_creds.server = &sprinc;
         }
 
         code = krb5_get_cred_via_tkt_ext(context, tgtptr,
@@ -635,8 +651,8 @@ cleanup:
             krb5_free_creds(context, referral_tgts[i]);
     }
     krb5_free_principal(context, tgs);
+    krb5_free_principal(context, eprinc);
     krb5_free_creds(context, tgt);
-    krb5_free_cred_contents(context, &s4u_creds);
     krb5_free_principal(context, s4u_user.user_id.user);
     krb5_free_checksum_contents(context, &s4u_user.cksum);
 
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index 5a2b807..7366e39 100755
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -142,4 +142,21 @@ out = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, '-',
 if 'auth1: user@' not in out or 'auth2: user@' not in out:
     fail('krb5 -> s4u2proxy')
 
+realm.stop()
+
+# Exercise cross-realm S4U2Self.  The query in the foreign realm will
+# fail, but we can check that the right server principal was used.
+r1, r2 = cross_realms(2, create_user=False)
+r1.run([kinit, '-k', r1.host_princ])
+out = r1.run(['./t_s4u', 'p:' + r2.host_princ], expected_code=1)
+if 'Server not found in Kerberos database' not in out:
+    fail('cross-realm s4u2self (t_s4u output)')
+r1.stop()
+r2.stop()
+with open(os.path.join(r2.testdir, 'kdc.log')) as f:
+    kdclog = f.read()
+exp_princ = r1.host_princ.replace('/', '\\/').replace('@', '\\@')
+if ('for %s@%s, Server not found' % (exp_princ, r2.realm)) not in kdclog:
+    fail('cross-realm s4u2self (kdc log)')
+
 success('S4U test cases')
_______________________________________________
cvs-krb5 mailing list
cvs-krb5@mit.edu
https://mailman.mit.edu/mailman/listinfo/cvs-krb5

home help back first fref pref prev next nref lref last post