]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add support for start_realm cache config 1143/head
authorGreg Hudson <ghudson@mit.edu>
Mon, 14 Dec 2020 18:16:17 +0000 (13:16 -0500)
committerGreg Hudson <ghudson@mit.edu>
Fri, 18 Dec 2020 17:41:30 +0000 (12:41 -0500)
When making TGS requests, if start_realm is set in the cache, use the
named realm to look up the initial TGT for referral or cross-realm
requests.  (Also correct a comment in struct _tkt_creds_context: the
ccache field is an owner pointer, not an alias.)

Add an internal API k5_cc_store_primary_cred(), which sets start_realm
if the cred being stored is a TGT for a realm other than the client
realm.  Use this API when acquiring initial tickets with a
caller-specified output ccache, when renewing or validating tickets
with kinit, when accepting a delegated credential in a GSS context,
and when storing a single cred with kvno --out-cache.

ticket: 8332
tags: pullup
target_version: 1.19

12 files changed:
doc/formats/ccache_file_format.rst
src/clients/kinit/kinit.c
src/clients/kvno/kvno.c
src/include/k5-int.h
src/lib/gssapi/krb5/accept_sec_context.c
src/lib/krb5/ccache/ccfns.c
src/lib/krb5/krb/get_creds.c
src/lib/krb5/krb/get_in_tkt.c
src/lib/krb5/libkrb5.exports
src/lib/krb5_32.def
src/tests/t_crossrealm.py
src/tests/t_pkinit.py

index 6349e0d294348ff03c8b9892dd9c88f1ccb2d6f0..6138c1b58cdf1f8b480e1034635c536445f2b203 100644 (file)
@@ -174,3 +174,9 @@ refresh_time
     decimal representation of a timestamp at which the GSS mechanism
     should attempt to refresh the credential cache from the client
     keytab.
+
+start_realm
+    This key indicates the realm of the ticket-granting ticket to be
+    used for TGS requests, when making a referrals request or
+    beginning a cross-realm request.  If it is not present, the client
+    realm is used.
index 3fdae2878482b73cb3c092256aa4d61adfc0e21b..e5ebeb8952b916c2227dceb65886e7e8c349f82e 100644 (file)
@@ -828,7 +828,7 @@ k5_kinit(struct k_opts *opts, struct k5_data *k5)
         if (opts->verbose)
             fprintf(stderr, _("Initialized cache\n"));
 
-        ret = krb5_cc_store_cred(k5->ctx, k5->out_cc, &my_creds);
+        ret = k5_cc_store_primary_cred(k5->ctx, k5->out_cc, &my_creds);
         if (ret) {
             com_err(progname, ret, _("while storing credentials"));
             goto cleanup;
index c5f6bf7003ead1195bf7e28557a74ba8a0b86403..f83c68a99ca59fe480a93ac896afbf4338e69c30 100644 (file)
@@ -561,7 +561,10 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
                 }
                 initialized = 1;
             }
-            ret = krb5_cc_store_cred(context, out_ccache, creds);
+            if (count == 1)
+                ret = k5_cc_store_primary_cred(context, out_ccache, creds);
+            else
+                ret = krb5_cc_store_cred(context, out_ccache, creds);
             if (ret) {
                 com_err(prog, ret, _("while storing creds in output ccache"));
                 exit(1);
index cf47485d7707615cd59d43d823e293b599713f2e..cfbb639d26c55acdc1fd25292d16ff7eba399ae5 100644 (file)
@@ -308,6 +308,7 @@ typedef unsigned char   u_char;
 #define KRB5_CC_CONF_PA_TYPE                   "pa_type"
 #define KRB5_CC_CONF_PROXY_IMPERSONATOR        "proxy_impersonator"
 #define KRB5_CC_CONF_REFRESH_TIME              "refresh_time"
+#define KRB5_CC_CONF_START_REALM               "start_realm"
 
 /* Error codes used in KRB_ERROR protocol messages.
    Return values of library routines are based on a different error table
@@ -1906,6 +1907,9 @@ krb5_ser_unpack_bytes(krb5_octet *, size_t, krb5_octet **, size_t *);
 krb5_error_code KRB5_CALLCONV
 krb5int_cc_default(krb5_context, krb5_ccache *);
 
+krb5_error_code
+k5_cc_store_primary_cred(krb5_context, krb5_ccache, krb5_creds *);
+
 /* Fill in the buffer with random alphanumeric data. */
 krb5_error_code
 krb5int_random_string(krb5_context, char *string, unsigned int length);
index 636ee303f6fbcca758c6a0debffabaa13bddaef7..75f071c3eddee9713e786b9e03327e0df6dccf03 100644 (file)
@@ -216,7 +216,7 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
         goto cleanup;
 
-    if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
+    if ((retval = k5_cc_store_primary_cred(context, ccache, creds[0])))
         goto cleanup;
 
     /* generate a delegated credential handle */
index 59982b7527939e730a8dd3e486e18fa69dc293bc..e0eb39a6124446c80de32cb194ba549317326a20 100644 (file)
@@ -298,3 +298,23 @@ krb5_cc_switch(krb5_context context, krb5_ccache cache)
         return 0;
     return cache->ops->switch_to(context, cache);
 }
+
+krb5_error_code
+k5_cc_store_primary_cred(krb5_context context, krb5_ccache cache,
+                         krb5_creds *creds)
+{
+    krb5_error_code ret;
+
+    /* Write a start realm if we're writing a TGT and the client realm isn't
+     * the same as the TGS realm. */
+    if (IS_TGS_PRINC(creds->server) &&
+        !data_eq(creds->client->realm, creds->server->data[1])) {
+        ret = krb5_cc_set_config(context, cache, NULL,
+                                 KRB5_CC_CONF_START_REALM,
+                                 &creds->server->data[1]);
+        if (ret)
+            return ret;
+    }
+
+    return krb5_cc_store_cred(context, cache, creds);
+}
index b693f5888831e12e131e5b5475f26ca3878e3a56..698c04efff8f535082a892253cf43057ee351b57 100644 (file)
@@ -201,7 +201,8 @@ struct _krb5_tkt_creds_context {
     krb5_principal client;      /* Caller-requested client principal (alias) */
     krb5_principal server;      /* Server principal (alias) */
     krb5_principal req_server;  /* Caller-requested server principal */
-    krb5_ccache ccache;         /* Caller-provided ccache (alias) */
+    krb5_ccache ccache;         /* Caller-provided ccache */
+    krb5_data start_realm;      /* Realm of starting TGT in ccache */
     krb5_flags req_options;     /* Caller-requested KRB5_GC_* options */
     krb5_flags req_kdcopt;      /* Caller-requested options as KDC options */
     krb5_authdata **authdata;   /* Caller-requested authdata */
@@ -814,7 +815,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx,
         return code;
 
     /* Construct the principal name. */
-    code = krb5int_tgtname(context, &ctx->client->realm, &ctx->client->realm,
+    code = krb5int_tgtname(context, &ctx->start_realm, &ctx->start_realm,
                            &tgtname);
     if (code != 0)
         return code;
@@ -852,7 +853,7 @@ init_realm_path(krb5_context context, krb5_tkt_creds_context ctx)
     size_t nrealms;
 
     /* Get the client realm path and count its length. */
-    code = k5_client_realm_path(context, &ctx->client->realm,
+    code = k5_client_realm_path(context, &ctx->start_realm,
                                 &ctx->server->realm, &realm_path);
     if (code != 0)
         return code;
@@ -964,7 +965,7 @@ step_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
                 ctx->cur_realm = path_realm;
                 ctx->next_realm = ctx->last_realm;
             }
-        } else if (data_eq(*tgt_realm, ctx->client->realm)) {
+        } else if (data_eq(*tgt_realm, ctx->start_realm)) {
             /* We were referred back to the local realm, which is bad. */
             return KRB5_KDCREP_MODIFIED;
         } else {
@@ -994,7 +995,7 @@ begin_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
 
     ctx->state = STATE_GET_TGT;
 
-    is_local_service = data_eq(ctx->client->realm, ctx->server->realm);
+    is_local_service = data_eq(ctx->start_realm, ctx->server->realm);
     if (!is_local_service) {
         /* See if we have a cached TGT for the server realm. */
         code = get_cached_tgt(context, ctx, &ctx->server->realm, &cached_tgt);
@@ -1073,11 +1074,11 @@ begin(krb5_context context, krb5_tkt_creds_context ctx)
 {
     krb5_error_code code;
 
-    /* If the server realm is unspecified, start with the client realm. */
+    /* If the server realm is unspecified, start with the TGT realm. */
     ctx->referral_req = krb5_is_referral_realm(&ctx->server->realm);
     if (ctx->referral_req) {
         krb5_free_data_contents(context, &ctx->server->realm);
-        code = krb5int_copy_data_contents(context, &ctx->client->realm,
+        code = krb5int_copy_data_contents(context, &ctx->start_realm,
                                           &ctx->server->realm);
         TRACE_TKT_CREDS_REFERRAL_REALM(context, ctx->server);
         if (code != 0)
@@ -1141,6 +1142,18 @@ krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache,
     code = krb5_cc_dup(context, ccache, &ctx->ccache);
     if (code != 0)
         goto cleanup;
+
+    /* Get the start realm from the cache config, defaulting to the client
+     * realm. */
+    code = krb5_cc_get_config(context, ccache, NULL, "start_realm",
+                              &ctx->start_realm);
+    if (code != 0) {
+        code = krb5int_copy_data_contents(context, &ctx->client->realm,
+                                          &ctx->start_realm);
+        if (code != 0)
+            goto cleanup;
+    }
+
     code = krb5_copy_authdata(context, in_creds->authdata, &ctx->authdata);
     if (code != 0)
         goto cleanup;
@@ -1181,6 +1194,7 @@ krb5_tkt_creds_free(krb5_context context, krb5_tkt_creds_context ctx)
     krb5_free_creds(context, ctx->in_creds);
     free_canonprinc(&ctx->iter);
     krb5_cc_close(context, ctx->ccache);
+    krb5_free_data_contents(context, &ctx->start_realm);
     krb5_free_principal(context, ctx->req_server);
     krb5_free_authdata(context, ctx->authdata);
     krb5_free_creds(context, ctx->cur_tgt);
index ab8f4eb21a77f71f5dcb4747e4db222be2a077f9..569518722dd9b85780c1f9b1a2382c989be8401c 100644 (file)
@@ -1796,7 +1796,7 @@ init_creds_step_reply(krb5_context context,
         code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
         if (code != 0)
             goto cc_cleanup;
-        code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
+        code = k5_cc_store_primary_cred(context, out_ccache, &ctx->cred);
         if (code != 0)
             goto cc_cleanup;
         if (fast_avail) {
index e862ed330616f35d6e9dbcbdb0d7606d84464ee2..05fbf982145519fc94533a062f5fa1a0252ef36c 100644 (file)
@@ -125,6 +125,7 @@ k5_add_pa_data_from_data
 k5_alloc_pa_data
 k5_authind_decode
 k5_build_conf_principals
+k5_cc_store_primary_cred
 k5_ccselect_free_context
 k5_change_error_message_code
 k5_etypes_contains
index a0734c729c1fe14d76e298eecb0b51b025af5a08..de5823c17c5600695b0064bfc5bed6d06cfc6370 100644 (file)
@@ -499,3 +499,6 @@ EXPORTS
        k5_size_context                                 @467 ; PRIVATE GSSAPI
        k5_size_keyblock                                @468 ; PRIVATE GSSAPI
        k5_size_principal                               @469 ; PRIVATE GSSAPI
+
+; new in 1.19
+       k5_cc_store_primary_cred                        @470 ; PRIVATE
index fa7fd2604b4578d8afcb2c79f6bac10893e3ea8a..28b397cfb7aacee650f6cfd6bffd716d75d86e0e 100755 (executable)
@@ -77,6 +77,14 @@ r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
                                 {'realm': 'B.X'}))
 test_kvno(r1, r3.host_princ, 'KDC domain walk')
 check_klist(r1, (tgt(r1, r1), r3.host_princ))
+
+# Test start_realm in this setup.
+r1.run([kvno, '--out-cache', r1.ccache, r2.krbtgt_princ])
+r1.run([klist, '-C'], expected_msg='config: start_realm = X')
+msgs = ('Requesting TGT krbtgt/B.X@X using TGT krbtgt/X@X',
+        'Received TGT for service realm: krbtgt/B.X@X')
+r1.run([kvno, r3.host_princ], expected_trace=msgs)
+
 stop(r1, r2, r3)
 
 # Test client capaths.  The client in A will ask for a cross TGT to D,
index ecd450e8a3558f0489b58eb06cf6bcb1ae63969f..f224383c81b757b5a2bdd4e5f43b0451fe415f2a 100755 (executable)
@@ -130,6 +130,9 @@ realm.run([kvno, realm.host_princ])
 out = realm.run(['./adata', realm.host_princ])
 if '97:' in out:
     fail('auth indicators seen in anonymous PKINIT ticket')
+# Verify start_realm setting and test referrals TGS request.
+realm.run([klist, '-C'], expected_msg='start_realm = KRBTEST.COM')
+realm.run([kvno, '-S', 'host', hostname])
 
 # Test anonymous kadmin.
 mark('anonymous kadmin')