diff options
Diffstat (limited to 'src/lib/krb5/krb')
-rw-r--r-- | src/lib/krb5/krb/bld_princ.c | 30 | ||||
-rw-r--r-- | src/lib/krb5/krb/chk_trans.c | 6 | ||||
-rw-r--r-- | src/lib/krb5/krb/get_in_tkt.c | 101 | ||||
-rw-r--r-- | src/lib/krb5/krb/gic_opt.c | 20 |
4 files changed, 147 insertions, 10 deletions
diff --git a/src/lib/krb5/krb/bld_princ.c b/src/lib/krb5/krb/bld_princ.c index ac2c92a9e..8378599d3 100644 --- a/src/lib/krb5/krb/bld_princ.c +++ b/src/lib/krb5/krb/bld_princ.c @@ -187,3 +187,33 @@ krb5_build_principal(krb5_context context, return retval; } + +/*Anonymous and well known principals*/ +static const char anon_realm_str[] += KRB5_ANONYMOUS_REALMSTR; +static const krb5_data anon_realm_data = { + KV5M_DATA, sizeof(anon_realm_str)-1, + (char *) anon_realm_str}; +static const char wellknown_str[] = KRB5_WELLKNOWN_NAMESTR; +static const char anon_str[] = KRB5_ANONYMOUS_PRINCSTR; +static const krb5_data anon_princ_data[] = { + {KV5M_DATA, sizeof(wellknown_str)-1, (char *) wellknown_str}, + {KV5M_DATA, sizeof(anon_str)-1, (char *)anon_str} +}; + +const krb5_principal_data anon_princ = { + KV5M_PRINCIPAL, + {KV5M_DATA, sizeof(anon_realm_str)-1, (char *) anon_realm_str}, + (krb5_data *) anon_princ_data, 2, KRB5_NT_WELLKNOWN +}; + +const krb5_data * KRB5_CALLCONV +krb5_anonymous_realm() +{ + return &anon_realm_data; +} +krb5_const_principal KRB5_CALLCONV +krb5_anonymous_principal() +{ + return &anon_princ; +} diff --git a/src/lib/krb5/krb/chk_trans.c b/src/lib/krb5/krb/chk_trans.c index 3c014817c..def50885c 100644 --- a/src/lib/krb5/krb/chk_trans.c +++ b/src/lib/krb5/krb/chk_trans.c @@ -315,6 +315,7 @@ krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in, krb5_data trans; struct check_data cdata; krb5_error_code r; + const krb5_data *anonymous; trans.length = trans_in->length; trans.data = (char *) trans_in->data; @@ -327,6 +328,11 @@ krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in, (int) srealm->length, srealm->data)); if (trans.length == 0) return 0; + anonymous = krb5_anonymous_realm(); + if (crealm->length == anonymous->length + && (memcmp(crealm->data, anonymous->data, anonymous->length) == 0)) + return 0; /*Nothing to check for anonymous*/ + r = krb5_walk_realm_tree (ctx, crealm, srealm, &cdata.tgs, KRB5_REALM_BRANCH_CHAR); if (r) { diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 06b3c3874..315bdc943 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -283,6 +283,71 @@ cleanup: return (retval); } +/** + * Fully anonymous replies include a pa_pkinit_kx padata type including the KDC + * contribution key. This routine confirms that the session key is of the + * right form for fully anonymous requests. It is here rather than in the + * preauth code because the session key cannot be verified until the AS reply + * is decrypted and the preauth code all runs before the AS reply is decrypted. + */ +static krb5_error_code +verify_anonymous( krb5_context context, krb5_kdc_req *request, + krb5_kdc_rep *reply, krb5_keyblock *as_key) +{ + krb5_error_code ret = 0; + krb5_pa_data *pa; + krb5_data scratch; + krb5_keyblock *kdc_key = NULL, *expected = NULL; + krb5_enc_data *enc = NULL; + krb5_keyblock *session = reply->enc_part2->session; + if (!krb5_principal_compare_any_realm(context, request->client, + krb5_anonymous_principal())) + return 0; /*Only applies to fully anonymous*/ + pa = krb5int_find_pa_data(context, reply->padata, KRB5_PADATA_PKINIT_KX); + if (pa == NULL) + goto verification_error; + scratch.length = pa->length; + scratch.data = (char *) pa->contents; + ret = decode_krb5_enc_data( &scratch, &enc); + if (ret) + goto cleanup; + scratch.data = k5alloc(enc->ciphertext.length, &ret); + if (ret) + goto cleanup; + scratch.length = enc->ciphertext.length; + ret = krb5_c_decrypt(context, as_key, KRB5_KEYUSAGE_PA_PKINIT_KX, + NULL /*cipherstate*/, enc, &scratch); + if (ret) { + free( scratch.data); + goto cleanup; + } + ret = decode_krb5_encryption_key( &scratch, &kdc_key); + zap(scratch.data, scratch.length); + free(scratch.data); + if (ret) + goto cleanup; + ret = krb5_c_fx_cf2_simple( context, kdc_key, "PKINIT", + as_key, "KEYEXCHANGE", &expected); + if (ret) + goto cleanup; + if ((expected->enctype != session->enctype) + || (expected->length != session->length) + || (memcmp(expected->contents, session->contents, expected->length) != 0)) + goto verification_error; +cleanup: + if (kdc_key) + krb5_free_keyblock(context, kdc_key); + if (expected) + krb5_free_keyblock(context, expected); + if (enc) + krb5_free_enc_data(context, enc); + return ret; +verification_error: + ret = KRB5_KDCREP_MODIFIED; + krb5_set_error_message(context, ret, "Reply has wrong form of session key for anonymous request"); + goto cleanup; +} + static krb5_error_code verify_as_reply(krb5_context context, krb5_timestamp time_now, @@ -304,10 +369,14 @@ verify_as_reply(krb5_context context, * principal) and we requested (and received) a TGT. */ canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) || - (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL); + (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL) + || (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS); if (canon_req) { canon_ok = IS_TGS_PRINC(context, request->server) && IS_TGS_PRINC(context, as_reply->enc_part2->server); + if ((!canon_ok ) && (request->kdc_options &KDC_OPT_REQUEST_ANONYMOUS)) + canon_ok = krb5_principal_compare_any_realm(context, as_reply->client, + krb5_anonymous_principal()); } else canon_ok = 0; @@ -1394,6 +1463,32 @@ krb5_init_creds_init(krb5_context context, ctx->salt.data = NULL; } + /*Anonymous*/ + if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) { + ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS; + /*Remap @REALM to WELLKNOWN/ANONYMOUS@REALM*/ + if (client->length == 1 && client->data[0].length ==0) { + krb5_principal new_client; + code = krb5_build_principal_ext(context, &new_client, client->realm.length, + client->realm.data, + strlen(KRB5_WELLKNOWN_NAMESTR), + KRB5_WELLKNOWN_NAMESTR, + strlen(KRB5_ANONYMOUS_PRINCSTR), + KRB5_ANONYMOUS_PRINCSTR, + 0); + if (code) + goto cleanup; + krb5_free_principal(context, ctx->request->client); + ctx->request->client = new_client; + krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN; + } + } + /*We will also handle anonymous if the input principal is the anonymous principal*/ + if (krb5_principal_compare_any_realm(context, ctx->request->client, + krb5_anonymous_principal())) { + ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS; + krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN; + } code = restart_init_creds_loop(context, ctx, NULL); *pctx = ctx; @@ -1829,6 +1924,10 @@ init_creds_step_reply(krb5_context context, ctx->request, ctx->reply); if (code != 0) goto cleanup; + code = verify_anonymous( context, ctx->request, ctx->reply, + &encrypting_key); + if (code) + goto cleanup; code = stash_as_reply(context, ctx->request_time, ctx->request, ctx->reply, &ctx->cred, NULL); diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c index d326ac570..c94ee3487 100644 --- a/src/lib/krb5/krb/gic_opt.c +++ b/src/lib/krb5/krb/gic_opt.c @@ -53,6 +53,15 @@ krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opt, int canon } void KRB5_CALLCONV +krb5_get_init_creds_opt_set_anonymous (krb5_get_init_creds_opt *opt, + int anonymous) +{ + if (anonymous) + opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS; + else opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ANONYMOUS; +} + +void KRB5_CALLCONV krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, int etype_list_length) { opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST; @@ -149,8 +158,6 @@ krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte) free_gic_opt_ext_preauth_data(context, opte); if (opte->opt_private->fast_ccache_name) free(opte->opt_private->fast_ccache_name); - if (opte->opt_private->out_ccache) - krb5_cc_close(context, opte->opt_private->out_ccache); free(opte->opt_private); opte->opt_private = NULL; return 0; @@ -504,13 +511,8 @@ krb5_get_init_creds_opt_set_out_ccache(krb5_context context, "krb5_get_init_creds_opt_set_out_ccache"); if (retval) return retval; - if (opte->opt_private->out_ccache) { - krb5_cc_close(context, opte->opt_private->out_ccache); - opte->opt_private->out_ccache = NULL; - } - retval = krb5_cc_resolve(context, krb5_cc_get_name(context, ccache), - &opte->opt_private->out_ccache); - return retval; + opte->opt_private->out_ccache = ccache; + return 0; } krb5_error_code KRB5_CALLCONV |