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