From 070d0cf9283fd8878c087e531a2f91e51f0ff2c8 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Sat, 22 Dec 2018 18:13:06 +1100 Subject: [PATCH] krb5: krb5_get_init_creds_opt_set_change_password_prompt incomplete (#322) krb5_get_init_creds_opt_set_change_password_prompt() was being ignored by krb5_init_creds_step() which broke pam_krb5 tests. MIT doesn't handle password expiration within krb5_init_creds_step(), instead deferring to higher level functions such as krb5_get_init_creds_password(). However, Heimdal kinit uses krb5_init_creds_step() directly and thus requires this behaviour to be implemented to pass its own tests. --- lib/krb5/init_creds_pw.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 0a9052413..d84c0f568 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -66,6 +66,7 @@ typedef struct krb5_get_init_creds_ctx { struct { unsigned change_password:1; + unsigned change_password_prompt:1; } runflags; int used_pa_types; @@ -386,6 +387,8 @@ static krb5_addresses no_addrs = { 0, NULL }; static krb5_error_code get_init_creds_common(krb5_context context, krb5_principal client, + krb5_prompter_fct prompter, + void *prompter_data, krb5_deltat start_time, krb5_get_init_creds_opt *options, krb5_init_creds_context ctx) @@ -502,6 +505,16 @@ get_init_creds_common(krb5_context context, } if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) ctx->flags.request_anonymous = options->anonymous; + + ctx->prompter = prompter; + ctx->prompter_data = prompter_data; + + if ((options->flags & KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT) && + !options->change_password_prompt) + ctx->runflags.change_password_prompt = 0; + else + ctx->runflags.change_password_prompt = ctx->prompter != NULL; + if (default_opt) krb5_get_init_creds_opt_free(context, default_opt); return 0; @@ -1412,7 +1425,8 @@ krb5_init_creds_init(krb5_context context, if (ctx == NULL) return krb5_enomem(context); - ret = get_init_creds_common(context, client, start_time, options, ctx); + ret = get_init_creds_common(context, client, prompter, prompter_data, + start_time, options, ctx); if (ret) { free(ctx); return ret; @@ -1424,9 +1438,6 @@ krb5_init_creds_init(krb5_context context, /* XXX these just needs to be the same when using Windows PK-INIT */ ctx->pk_nonce = ctx->nonce; - ctx->prompter = prompter; - ctx->prompter_data = prompter_data; - *rctx = ctx; return ret; @@ -2378,11 +2389,13 @@ krb5_init_creds_step(krb5_context context, memset_s(&ctx->as_req, sizeof(ctx->as_req), 0, sizeof(ctx->as_req)); ctx->used_pa_types = 0; - } else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->runflags.change_password == 0 && ctx->prompter) { + } else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->runflags.change_password == 0 && + ctx->runflags.change_password_prompt) { char buf2[1024]; ctx->runflags.change_password = 1; + heim_assert(ctx->prompter != NULL, "unexpected NULL prompter"); ctx->prompter(context, ctx->prompter_data, NULL, N_("Password has expired", ""), 0, NULL); @@ -2717,14 +2730,10 @@ krb5_get_init_creds_password(krb5_context context, if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0) goto out; - /* don't try to change password where then where none */ - if (prompter == NULL) + /* don't try to change password if no prompter or prompting disabled */ + if (!ctx->runflags.change_password_prompt) goto out; - if ((options->flags & KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT) && - !options->change_password_prompt) - goto out; - ret = change_password (context, client, ctx->password,