krb5 commit: Move S4U2Proxy client code to s4u_creds.c

Greg Hudson ghudson at mit.edu
Mon Sep 9 10:33:02 EDT 2019


https://github.com/krb5/krb5/commit/2b29619aa27c2e63fea80cac60b5607a3fce972f
commit 2b29619aa27c2e63fea80cac60b5607a3fce972f
Author: Isaac Boukris <iboukris at gmail.com>
Date:   Mon Jun 17 00:21:38 2019 +0300

    Move S4U2Proxy client code to s4u_creds.c
    
    Add an internal libkrb5 interface k5_get_proxy_cred_from_kdc(), which
    implements S4U2Proxy requests synchronously.  Call it from
    krb5_get_credentials() if constrained delegation is requested.
    
    [ghudson at mit.edu: rewrote commit message; made style changes]
    
    ticket: 8479

 src/lib/krb5/krb/get_creds.c |   28 +++-------
 src/lib/krb5/krb/int-proto.h |   10 +++
 src/lib/krb5/krb/s4u_creds.c |  130 ++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 143 insertions(+), 25 deletions(-)

diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c
index 0a04d68..e0a3b5c 100644
--- a/src/lib/krb5/krb/get_creds.c
+++ b/src/lib/krb5/krb/get_creds.c
@@ -332,8 +332,7 @@ make_request_for_service(krb5_context context, krb5_tkt_creds_context ctx,
     extra_options = ctx->req_kdcopt;
 
     /* Automatically set the enc-tkt-in-skey flag for user-to-user requests. */
-    if (ctx->in_creds->second_ticket.length != 0 &&
-        (extra_options & KDC_OPT_CNAME_IN_ADDL_TKT) == 0)
+    if (ctx->in_creds->second_ticket.length != 0)
         extra_options |= KDC_OPT_ENC_TKT_IN_SKEY;
 
     /* Set the canonicalize flag for referral requests. */
@@ -444,12 +443,6 @@ complete(krb5_context context, krb5_tkt_creds_context ctx)
         (void) krb5_cc_store_cred(context, ctx->ccache, ctx->reply_creds);
     }
 
-    /* If we were doing constrained delegation, make sure we got a forwardable
-     * ticket, or it won't work. */
-    if ((ctx->req_options & KRB5_GC_CONSTRAINED_DELEGATION)
-        && (ctx->reply_creds->ticket_flags & TKT_FLG_FORWARDABLE) == 0)
-        return KRB5_TKT_NOT_FORWARDABLE;
-
     ctx->state = STATE_COMPLETE;
     return 0;
 }
@@ -1023,11 +1016,6 @@ check_cache(krb5_context context, krb5_tkt_creds_context ctx)
     krb5_creds mcreds;
     krb5_flags fields;
 
-    /* For constrained delegation, the expected result is in second_ticket, so
-     * we can't really do a cache check here. */
-    if (ctx->req_options & KRB5_GC_CONSTRAINED_DELEGATION)
-        return (ctx->req_options & KRB5_GC_CACHED) ? KRB5_CC_NOTFOUND : 0;
-
     /* Perform the cache lookup. */
     code = krb5int_construct_matching_creds(context, ctx->req_options,
                                             ctx->in_creds, &mcreds, &fields);
@@ -1098,13 +1086,6 @@ krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache,
         ctx->req_kdcopt |= KDC_OPT_FORWARDABLE;
     if (options & KRB5_GC_NO_TRANSIT_CHECK)
         ctx->req_kdcopt |= KDC_OPT_DISABLE_TRANSITED_CHECK;
-    if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
-        if (options & KRB5_GC_USER_USER) {
-            code = EINVAL;
-            goto cleanup;
-        }
-        ctx->req_kdcopt |= KDC_OPT_FORWARDABLE | KDC_OPT_CNAME_IN_ADDL_TKT;
-    }
 
     ctx->state = STATE_BEGIN;
 
@@ -1284,6 +1265,13 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
 
     *out_creds = NULL;
 
+    /* If S4U2Proxy is requested, use the synchronous implementation in
+     * s4u_creds.c. */
+    if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
+        return k5_get_proxy_cred_from_kdc(context, options, ccache, in_creds,
+                                          out_creds);
+    }
+
     /* Allocate a container. */
     ncreds = k5alloc(sizeof(*ncreds), &code);
     if (ncreds == NULL)
diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
index d45adab..fe61beb 100644
--- a/src/lib/krb5/krb/int-proto.h
+++ b/src/lib/krb5/krb/int-proto.h
@@ -376,4 +376,14 @@ krb5_error_code
 k5_get_etype_info(krb5_context context, krb5_init_creds_context ctx,
                   krb5_pa_data **padata);
 
+/*
+ * Make an S4U2Proxy (constrained delegation) request.  in_creds->client is the
+ * impersonator principal, and in_creds->second_ticket is the evidence
+ * ticket.
+ */
+krb5_error_code
+k5_get_proxy_cred_from_kdc(krb5_context context, krb5_flags options,
+                           krb5_ccache ccache, krb5_creds *in_creds,
+                           krb5_creds **out_creds);
+
 #endif /* KRB5_INT_FUNC_PROTO__ */
diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
index 283417a..26c15fe 100644
--- a/src/lib/krb5/krb/s4u_creds.c
+++ b/src/lib/krb5/krb/s4u_creds.c
@@ -725,6 +725,128 @@ cleanup:
     return code;
 }
 
+/* Set *tgt_out to a local TGT for the client realm retrieved from ccache. */
+static krb5_error_code
+get_client_tgt(krb5_context context, krb5_flags options, krb5_ccache ccache,
+               krb5_principal client, krb5_creds **tgt_out)
+{
+    krb5_error_code code;
+    krb5_principal tgs;
+    krb5_creds mcreds;
+
+    *tgt_out = NULL;
+
+    code = krb5int_tgtname(context, &client->realm, &client->realm, &tgs);
+    if (code)
+        return code;
+
+    memset(&mcreds, 0, sizeof(mcreds));
+    mcreds.client = client;
+    mcreds.server = tgs;
+    code = krb5_get_credentials(context, options, ccache, &mcreds, tgt_out);
+    krb5_free_principal(context, tgs);
+    return code;
+}
+
+/* Copy req_server to *out_server.  If req_server has the referral realm, set
+ * the realm of *out_server to realm. */
+static krb5_error_code
+normalize_server_princ(krb5_context context, const krb5_data *realm,
+                       krb5_principal req_server, krb5_principal *out_server)
+{
+    krb5_error_code code;
+    krb5_principal server;
+
+    *out_server = NULL;
+
+    code = krb5_copy_principal(context, req_server, &server);
+    if (code)
+        return code;
+
+    if (krb5_is_referral_realm(&server->realm)) {
+        krb5_free_data_contents(context, &server->realm);
+        code = krb5int_copy_data_contents(context, realm, &server->realm);
+        if (code) {
+            krb5_free_principal(context, server);
+            return code;
+        }
+    }
+
+    *out_server = server;
+    return 0;
+}
+
+krb5_error_code
+k5_get_proxy_cred_from_kdc(krb5_context context, krb5_flags options,
+                           krb5_ccache ccache, krb5_creds *in_creds,
+                           krb5_creds **out_creds)
+{
+    krb5_error_code code;
+    krb5_flags kdcopt, flags;
+    krb5_principal server = NULL;
+    krb5_creds mcreds, *tgt = NULL, *tkt = NULL;
+
+    *out_creds = NULL;
+
+    if (in_creds->second_ticket.length == 0 ||
+        (options & KRB5_GC_CONSTRAINED_DELEGATION) == 0)
+        return EINVAL;
+
+    options &= ~KRB5_GC_CONSTRAINED_DELEGATION;
+
+    code = get_client_tgt(context, options, ccache, in_creds->client, &tgt);
+    if (code)
+        goto cleanup;
+
+    code = normalize_server_princ(context, &in_creds->client->realm,
+                                  in_creds->server, &server);
+    if (code)
+        goto cleanup;
+
+    kdcopt = KDC_OPT_CNAME_IN_ADDL_TKT;
+    if (options & KRB5_GC_CANONICALIZE)
+        kdcopt |= KDC_OPT_CANONICALIZE;
+    if (options & KRB5_GC_FORWARDABLE)
+        kdcopt |= KDC_OPT_FORWARDABLE;
+    if (options & KRB5_GC_NO_TRANSIT_CHECK)
+        kdcopt |= KDC_OPT_DISABLE_TRANSITED_CHECK;
+
+    mcreds = *in_creds;
+    mcreds.server = server;
+
+    flags = kdcopt | FLAGS2OPTS(tgt->ticket_flags);
+    code = krb5_get_cred_via_tkt_ext(context, tgt, flags, tgt->addresses,
+                                     NULL, &mcreds, NULL, NULL, NULL, NULL,
+                                     &tkt, NULL);
+    if (code)
+        goto cleanup;
+
+    if (!krb5_principal_compare(context, server, tkt->server)) {
+        code = KRB5KRB_AP_WRONG_PRINC;
+        goto cleanup;
+    }
+
+    if (!krb5_principal_compare(context, in_creds->server, tkt->server)) {
+        krb5_free_principal(context, tkt->server);
+        tkt->server = NULL;
+        code = krb5_copy_principal(context, in_creds->server, &tkt->server);
+        if (code)
+            goto cleanup;
+    }
+
+    if (!(options & KRB5_GC_NO_STORE))
+        (void)krb5_cc_store_cred(context, ccache, tkt);
+
+    *out_creds = tkt;
+    tkt = NULL;
+
+cleanup:
+    krb5_free_creds(context, tgt);
+    krb5_free_creds(context, tkt);
+    krb5_free_principal(context, server);
+    return code;
+}
+
 /*
  * Exported API for constrained delegation (S4U2Proxy).
  *
@@ -801,11 +923,9 @@ krb5_get_credentials_for_proxy(krb5_context context,
     s4u_creds.client = evidence_tkt->server;
     s4u_creds.second_ticket = *evidence_tkt_data;
 
-    code = krb5_get_credentials(context,
-                                options | KRB5_GC_CONSTRAINED_DELEGATION,
-                                ccache,
-                                &s4u_creds,
-                                out_creds);
+    code = k5_get_proxy_cred_from_kdc(context,
+                                      options | KRB5_GC_CONSTRAINED_DELEGATION,
+                                      ccache, &s4u_creds, out_creds);
     if (code != 0)
         goto cleanup;
 


More information about the cvs-krb5 mailing list