diff options
author | Andrew Bartlett <abartlet@samba.org> | 2010-01-12 18:16:45 +1100 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2010-03-27 11:51:27 +1100 |
commit | 89eaef025376339ef25d07cdc4748920fceaa968 (patch) | |
tree | f514f4632c9d54a372a7f1f0ca845a0c3a488fbf /source4/heimdal/lib/krb5/init_creds_pw.c | |
parent | fac8ca52ade6e490eea3cf3d0fc98287da321c13 (diff) | |
download | samba-89eaef025376339ef25d07cdc4748920fceaa968.tar.gz samba-89eaef025376339ef25d07cdc4748920fceaa968.tar.bz2 samba-89eaef025376339ef25d07cdc4748920fceaa968.zip |
s4:heimdal: import lorikeet-heimdal-201001120029 (commit a5e675fed7c5db8a7370b77ed0bfa724196aa84d)
Diffstat (limited to 'source4/heimdal/lib/krb5/init_creds_pw.c')
-rw-r--r-- | source4/heimdal/lib/krb5/init_creds_pw.c | 191 |
1 files changed, 147 insertions, 44 deletions
diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c index c326fa4df7..4637a6d941 100644 --- a/source4/heimdal/lib/krb5/init_creds_pw.c +++ b/source4/heimdal/lib/krb5/init_creds_pw.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -59,6 +61,12 @@ typedef struct krb5_get_init_creds_ctx { krb5_pk_init_ctx pk_init_ctx; int ic_flags; + int used_pa_types; +#define USED_PKINIT 1 +#define USED_PKINIT_W2K 2 +#define USED_ENC_TS_GUESS 4 +#define USED_ENC_TS_INFO 8 + METHOD_DATA md; KRB_ERROR error; AS_REP as_rep; @@ -67,8 +75,25 @@ typedef struct krb5_get_init_creds_ctx { krb5_prompter_fct prompter; void *prompter_data; + struct pa_info_data *ppaid; + } krb5_get_init_creds_ctx; + +struct pa_info_data { + krb5_enctype etype; + krb5_salt salt; + krb5_data *s2kparams; +}; + +static void +free_paid(krb5_context context, struct pa_info_data *ppaid) +{ + krb5_free_salt(context, ppaid->salt); + if (ppaid->s2kparams) + krb5_free_data(context, ppaid->s2kparams); +} + static krb5_error_code default_s2k_func(krb5_context context, krb5_enctype type, krb5_const_pointer keyseed, @@ -79,6 +104,8 @@ default_s2k_func(krb5_context context, krb5_enctype type, krb5_data password; krb5_data opaque; + _krb5_debug(context, 5, "krb5_get_init_creds: using default_s2k_func"); + password.data = rk_UNCONST(keyseed); password.length = strlen(keyseed); if (s2kparms) @@ -120,6 +147,10 @@ free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) free_EncKDCRepPart(&ctx->enc_part); free_KRB_ERROR(&ctx->error); free_AS_REQ(&ctx->as_req); + if (ctx->ppaid) { + free_paid(context, ctx->ppaid); + free(ctx->ppaid); + } memset(ctx, 0, sizeof(*ctx)); } @@ -559,7 +590,7 @@ out: } -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_keyblock_key_proc (krb5_context context, krb5_keytype type, krb5_data *salt, @@ -681,20 +712,6 @@ init_as_req (krb5_context context, return ret; } -struct pa_info_data { - krb5_enctype etype; - krb5_salt salt; - krb5_data *s2kparams; -}; - -static void -free_paid(krb5_context context, struct pa_info_data *ppaid) -{ - krb5_free_salt(context, ppaid->salt); - if (ppaid->s2kparams) - krb5_free_data(context, ppaid->s2kparams); -} - static krb5_error_code set_paid(struct pa_info_data *paid, krb5_context context, @@ -986,6 +1003,8 @@ add_enc_ts_padata(krb5_context context, for (i = 0; i < netypes; ++i) { krb5_keyblock *key; + _krb5_debug(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]); + ret = (*keyproc)(context, enctypes[i], keyseed, *salt, s2kparams, &key); if (ret) @@ -1019,6 +1038,8 @@ pa_data_to_md_ts_enc(krb5_context context, } else { krb5_salt salt; + _krb5_debug(context, 5, "krb5_get_init_creds: pa-info not found, guessing salt"); + /* make a v5 salted pa-data */ add_enc_ts_padata(context, md, client, ctx->keyproc, ctx->keyseed, @@ -1057,6 +1078,7 @@ static krb5_error_code pa_data_to_md_pkinit(krb5_context context, const AS_REQ *a, const krb5_principal client, + int win2k, krb5_get_init_creds_ctx *ctx, METHOD_DATA *md) { @@ -1064,10 +1086,12 @@ pa_data_to_md_pkinit(krb5_context context, return 0; #ifdef PKINIT return _krb5_pk_mk_padata(context, - ctx->pk_init_ctx, - &a->req_body, - ctx->pk_nonce, - md); + ctx->pk_init_ctx, + ctx->ic_flags, + win2k, + &a->req_body, + ctx->pk_nonce, + md); #else krb5_set_error_message(context, EINVAL, N_("no support for PKINIT compiled in", "")); @@ -1133,6 +1157,13 @@ process_pa_data_to_md(krb5_context context, (*out_md)->len = 0; (*out_md)->val = NULL; + if (_krb5_have_debug(context, 5)) { + unsigned i; + _krb5_debug(context, 5, "KDC send %d patypes", in_md->len); + for (i = 0; i < in_md->len; i++) + _krb5_debug(context, 5, "KDC send PA-DATA type: %d", in_md->val[i].padata_type); + } + /* * Make sure we don't sent both ENC-TS and PK-INIT pa data, no * need to expose our password protecting our PKCS12 key. @@ -1140,21 +1171,62 @@ process_pa_data_to_md(krb5_context context, if (ctx->pk_init_ctx) { - ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md); + _krb5_debug(context, 5, "krb5_get_init_creds: " + "prepareing PKINIT padata (%s)", + (ctx->used_pa_types & USED_PKINIT_W2K) ? "win2k" : "ietf"); + + if (ctx->used_pa_types & USED_PKINIT_W2K) { + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + "Already tried pkinit, looping"); + return KRB5_GET_IN_TKT_LOOP; + } + + ret = pa_data_to_md_pkinit(context, a, creds->client, + (ctx->used_pa_types & USED_PKINIT), + ctx, *out_md); if (ret) return ret; + if (ctx->used_pa_types & USED_PKINIT) + ctx->used_pa_types |= USED_PKINIT_W2K; + else + ctx->used_pa_types |= USED_PKINIT; + } else if (in_md->len != 0) { - struct pa_info_data paid, *ppaid; + struct pa_info_data *paid, *ppaid; + unsigned flag; + + paid = calloc(1, sizeof(*paid)); - memset(&paid, 0, sizeof(paid)); + paid->etype = ENCTYPE_NULL; + ppaid = process_pa_info(context, creds->client, a, paid, in_md); - paid.etype = ENCTYPE_NULL; - ppaid = process_pa_info(context, creds->client, a, &paid, in_md); + if (ppaid) + flag = USED_ENC_TS_INFO; + else + flag = USED_ENC_TS_GUESS; + + if (ctx->used_pa_types & flag) { + if (ppaid) + free_paid(context, ppaid); + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + "Already tried ENC-TS-%s, looping", + flag == USED_ENC_TS_INFO ? "info" : "guess"); + return KRB5_GET_IN_TKT_LOOP; + } pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md); - if (ppaid) - free_paid(context, ppaid); + + ctx->used_pa_types |= flag; + + if (ppaid) { + if (ctx->ppaid) { + free_paid(context, ctx->ppaid); + free(ctx->ppaid); + } + ctx->ppaid = ppaid; + } else + free(paid); } pa_data_add_pac_request(context, ctx, *out_md); @@ -1190,12 +1262,15 @@ process_pa_data_to_key(krb5_context context, ppaid = process_pa_info(context, creds->client, a, &paid, rep->padata); } + if (ppaid == NULL) + ppaid = ctx->ppaid; if (ppaid == NULL) { ret = krb5_get_pw_salt (context, creds->client, &paid.salt); if (ret) return ret; paid.etype = etype; paid.s2kparams = NULL; + ppaid = &paid; } pa = NULL; @@ -1215,6 +1290,8 @@ process_pa_data_to_key(krb5_context context, } if (pa && ctx->pk_init_ctx) { #ifdef PKINIT + _krb5_debug(context, 5, "krb5_get_init_creds: using PKINIT"); + ret = _krb5_pk_rd_pa_reply(context, a->req_body.realm, ctx->pk_init_ctx, @@ -1228,10 +1305,11 @@ process_pa_data_to_key(krb5_context context, ret = EINVAL; krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", "")); #endif - } else if (ctx->keyseed) + } else if (ctx->keyseed) { + _krb5_debug(context, 5, "krb5_get_init_creds: using keyproc"); ret = pa_data_to_key_plain(context, creds->client, ctx, - paid.salt, paid.s2kparams, etype, key); - else { + ppaid->salt, ppaid->s2kparams, etype, key); + } else { ret = EINVAL; krb5_set_error_message(context, ret, N_("No usable pa data type", "")); } @@ -1258,7 +1336,7 @@ process_pa_data_to_key(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_init(krb5_context context, krb5_principal client, krb5_prompter_fct prompter, @@ -1312,7 +1390,7 @@ krb5_init_creds_init(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_set_service(krb5_context context, krb5_init_creds_context ctx, const char *service) @@ -1352,7 +1430,7 @@ krb5_init_creds_set_service(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_set_password(krb5_context context, krb5_init_creds_context ctx, const char *password) @@ -1420,7 +1498,7 @@ keytab_key_proc(krb5_context context, krb5_enctype enctype, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_set_keytab(krb5_context context, krb5_init_creds_context ctx, krb5_keytab keytab) @@ -1512,7 +1590,7 @@ keyblock_key_proc(krb5_context context, krb5_enctype enctype, return krb5_copy_keyblock (context, keyseed, key); } -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_set_keyblock(krb5_context context, krb5_init_creds_context ctx, krb5_keyblock *keyblock) @@ -1543,7 +1621,7 @@ krb5_init_creds_set_keyblock(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_step(krb5_context context, krb5_init_creds_context ctx, krb5_data *in, @@ -1576,16 +1654,20 @@ krb5_init_creds_step(krb5_context context, } ctx->pa_counter++; + _krb5_debug(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter); + /* Lets process the input packet */ if (in && in->length) { krb5_kdc_rep rep; memset(&rep, 0, sizeof(rep)); + _krb5_debug(context, 5, "krb5_get_init_creds: processing input"); + ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); if (ret == 0) { krb5_keyblock *key = NULL; - unsigned eflags = EXTRACT_TICKET_AS_REQ; + unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC; if (ctx->flags.canonicalize) { eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; @@ -1601,6 +1683,8 @@ krb5_init_creds_step(krb5_context context, goto out; } + _krb5_debug(context, 5, "krb5_get_init_creds: extracting ticket"); + ret = _krb5_extract_ticket(context, &rep, &ctx->cred, @@ -1627,16 +1711,22 @@ krb5_init_creds_step(krb5_context context, } else { /* let's try to parse it as a KRB-ERROR */ + _krb5_debug(context, 5, "krb5_get_init_creds: got an error"); + free_KRB_ERROR(&ctx->error); ret = krb5_rd_error(context, in, &ctx->error); if(ret && in->length && ((char*)in->data)[0] == 4) ret = KRB5KRB_AP_ERR_V4_REPLY; - if (ret) + if (ret) { + _krb5_debug(context, 5, "krb5_get_init_creds: failed to read error"); goto out; + } ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); + _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d", ret); + /* * If no preauth was set and KDC requires it, give it one * more try. @@ -1668,16 +1758,29 @@ krb5_init_creds_step(krb5_context context, krb5_set_real_time(context, ctx->error.stime, -1); if (context->kdc_sec_offset) ret = 0; + + _krb5_debug(context, 10, "init_creds: err skew updateing kdc offset to %d", + context->kdc_sec_offset); + + ctx->used_pa_types = 0; + } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { /* client referal to a new realm */ + if (ctx->error.crealm == NULL) { krb5_set_error_message(context, ret, N_("Got a client referral, not but no realm", "")); goto out; } + _krb5_debug(context, 5, + "krb5_get_init_creds: got referal to realm %s", + *ctx->error.crealm); + ret = krb5_principal_set_realm(context, ctx->cred.client, *ctx->error.crealm); + + ctx->used_pa_types = 0; } if (ret) goto out; @@ -1731,7 +1834,7 @@ krb5_init_creds_step(krb5_context context, * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message(). */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_get_creds(krb5_context context, krb5_init_creds_context ctx, krb5_creds *cred) @@ -1747,7 +1850,7 @@ krb5_init_creds_get_creds(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_get_error(krb5_context context, krb5_init_creds_context ctx, KRB_ERROR *error) @@ -1770,7 +1873,7 @@ krb5_init_creds_get_error(krb5_context context, * @ingroup krb5_credential */ -void KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_init_creds_free(krb5_context context, krb5_init_creds_context ctx) { @@ -1787,7 +1890,7 @@ krb5_init_creds_free(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx) { krb5_sendto_ctx stctx = NULL; @@ -1835,7 +1938,7 @@ krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx) */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_principal client, @@ -1941,7 +2044,7 @@ krb5_get_init_creds_password(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_init_creds_keyblock(krb5_context context, krb5_creds *creds, krb5_principal client, @@ -1988,7 +2091,7 @@ krb5_get_init_creds_keyblock(krb5_context context, * @ingroup krb5_credential */ -krb5_error_code KRB5_LIB_FUNCTION +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_principal client, |