diff options
author | Greg Hudson <ghudson@mit.edu> | 2020-12-14 13:16:17 -0500 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2021-01-08 11:58:28 -0500 |
commit | 58b4b38e104f0a73b7ac5700c1715a22bbb4604b (patch) | |
tree | a794e0b5e8fad535d49da5ce97acfbdbe0ed9936 | |
parent | b5b45c42e5e7970f4a6e3622cd29c6fd77c8cf57 (diff) | |
download | krb5-58b4b38e104f0a73b7ac5700c1715a22bbb4604b.zip krb5-58b4b38e104f0a73b7ac5700c1715a22bbb4604b.tar.gz krb5-58b4b38e104f0a73b7ac5700c1715a22bbb4604b.tar.bz2 |
Add support for start_realm cache config
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.
(cherry picked from commit 0d56740ab9fcc40dc7f46c6fbebdf8f1214f9d96)
ticket: 8332
version_fixed: 1.19
-rw-r--r-- | doc/formats/ccache_file_format.rst | 6 | ||||
-rw-r--r-- | src/clients/kinit/kinit.c | 2 | ||||
-rw-r--r-- | src/clients/kvno/kvno.c | 5 | ||||
-rw-r--r-- | src/include/k5-int.h | 4 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/accept_sec_context.c | 2 | ||||
-rw-r--r-- | src/lib/krb5/ccache/ccfns.c | 20 | ||||
-rw-r--r-- | src/lib/krb5/krb/get_creds.c | 28 | ||||
-rw-r--r-- | src/lib/krb5/krb/get_in_tkt.c | 2 | ||||
-rw-r--r-- | src/lib/krb5/libkrb5.exports | 1 | ||||
-rw-r--r-- | src/lib/krb5_32.def | 3 | ||||
-rwxr-xr-x | src/tests/t_crossrealm.py | 8 | ||||
-rwxr-xr-x | src/tests/t_pkinit.py | 3 |
12 files changed, 73 insertions, 11 deletions
diff --git a/doc/formats/ccache_file_format.rst b/doc/formats/ccache_file_format.rst index 6349e0d..6138c1b 100644 --- a/doc/formats/ccache_file_format.rst +++ b/doc/formats/ccache_file_format.rst @@ -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. diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c index 3fdae28..e5ebeb8 100644 --- a/src/clients/kinit/kinit.c +++ b/src/clients/kinit/kinit.c @@ -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; diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c index c5f6bf7..f83c68a 100644 --- a/src/clients/kvno/kvno.c +++ b/src/clients/kvno/kvno.c @@ -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); diff --git a/src/include/k5-int.h b/src/include/k5-int.h index b3e3469..edad910 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -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 @@ -1910,6 +1911,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); diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index 636ee30..75f071c 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -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 */ diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c index 59982b7..e0eb39a 100644 --- a/src/lib/krb5/ccache/ccfns.c +++ b/src/lib/krb5/ccache/ccfns.c @@ -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); +} diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c index b693f58..698c04e 100644 --- a/src/lib/krb5/krb/get_creds.c +++ b/src/lib/krb5/krb/get_creds.c @@ -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); diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index ab8f4eb..5695187 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -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) { diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index c6472da..2ffdf95 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -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 diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def index a0734c7..de5823c 100644 --- a/src/lib/krb5_32.def +++ b/src/lib/krb5_32.def @@ -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 diff --git a/src/tests/t_crossrealm.py b/src/tests/t_crossrealm.py index fa7fd26..28b397c 100755 --- a/src/tests/t_crossrealm.py +++ b/src/tests/t_crossrealm.py @@ -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, diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py index ecd450e..f224383 100755 --- a/src/tests/t_pkinit.py +++ b/src/tests/t_pkinit.py @@ -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') |