summaryrefslogtreecommitdiffstats
path: root/src/lib/krb5/krb
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krb5/krb')
-rw-r--r--src/lib/krb5/krb/bld_princ.c30
-rw-r--r--src/lib/krb5/krb/chk_trans.c6
-rw-r--r--src/lib/krb5/krb/get_in_tkt.c101
-rw-r--r--src/lib/krb5/krb/gic_opt.c20
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