summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/krb5/init_creds_pw.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/krb5/init_creds_pw.c')
-rw-r--r--source4/heimdal/lib/krb5/init_creds_pw.c191
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,