From 7dd00aea5c305566d1e07ac6709fed49e9a747b5 Mon Sep 17 00:00:00 2001 From: Alexandra Ellwood Date: Thu, 25 Sep 2008 19:53:18 +0000 Subject: [PATCH] Added support to track number of prompts so UIs do not try again unless there is something the user can do differently the next time. ticket: 6055 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20752 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kim/lib/kim_credential.c | 46 ++++++++++---- src/kim/lib/kim_credential_private.h | 3 +- src/kim/lib/kim_identity.c | 92 ++++++++++++++++++++-------- src/kim/lib/kim_identity_private.h | 5 ++ src/kim/lib/kim_ui.c | 3 + src/kim/lib/kim_ui_cli.c | 10 ++- src/kim/lib/kim_ui_private.h | 1 + 7 files changed, 121 insertions(+), 39 deletions(-) diff --git a/src/kim/lib/kim_credential.c b/src/kim/lib/kim_credential.c index f77be0993..b03cba183 100644 --- a/src/kim/lib/kim_credential.c +++ b/src/kim/lib/kim_credential.c @@ -260,7 +260,11 @@ kim_error kim_credential_create_new (kim_credential *out_credential, while (!err && !done) { krb5_creds creds; kim_boolean free_creds = 0; - + kim_count prompt_count; + + /* set counter to zero so we can tell if we got prompted */ + context.prompt_count = 0; + err = krb5_error (credential->context, krb5_get_init_creds_password (credential->context, &creds, @@ -271,6 +275,7 @@ kim_error kim_credential_create_new (kim_credential *out_credential, (char *) service, init_cred_options)); + prompt_count = context.prompt_count; /* remember if we got prompts */ if (!err) { free_creds = 1; } if (!err) { @@ -280,15 +285,27 @@ kim_error kim_credential_create_new (kim_credential *out_credential, &credential->creds)); } + + if (err == KRB5KDC_ERR_KEY_EXP) { + err = kim_identity_change_password_common (in_identity, 1, + &context); + } + if (!err || err == KIM_USER_CANCELED_ERR) { /* new creds obtained or the user gave up */ done = 1; - } else { + } else { /* new creds failed, report error to user */ - err = kim_ui_handle_kim_error (&context, in_identity, - kim_ui_error_type_authentication, - err); + kim_error terr = kim_ui_handle_kim_error (&context, in_identity, + kim_ui_error_type_authentication, + err); + + if (prompt_count) { + /* User was prompted and might have entered bad info + * so let them try again. */ + err = terr; + } } if (free_creds) { krb5_free_cred_contents (credential->context, &creds); } @@ -495,7 +512,8 @@ kim_error kim_credential_create_from_krb5_creds (kim_credential *out_credential, kim_error kim_credential_create_for_change_password (kim_credential *out_credential, kim_identity in_identity, kim_string in_old_password, - kim_ui_context *in_ui_context) + kim_ui_context *in_ui_context, + kim_boolean *out_user_was_prompted) { kim_error err = KIM_NO_ERROR; kim_credential credential = NULL; @@ -504,9 +522,10 @@ kim_error kim_credential_create_for_change_password (kim_credential *out_creden krb5_principal principal = NULL; kim_string service_format = "kadmin/changepw@%s"; - if (!err && !out_credential ) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); } - if (!err && !in_old_password) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_credential ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !in_old_password ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !out_user_was_prompted) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { err = kim_credential_allocate (&credential); @@ -541,6 +560,9 @@ kim_error kim_credential_create_for_change_password (kim_credential *out_creden krb5_get_init_creds_opt_set_forwardable (&opts, 0); krb5_get_init_creds_opt_set_proxiable (&opts, 0); + /* set counter to zero so we can tell if we got prompted */ + in_ui_context->prompt_count = 0; + err = krb5_error (credential->context, krb5_get_init_creds_password (credential->context, &creds, @@ -549,8 +571,9 @@ kim_error kim_credential_create_for_change_password (kim_credential *out_creden kim_ui_prompter, in_ui_context, 0, (char *) service, - &opts)); - if (!err) { free_creds = 1; } + &opts)); + + if (!err) { free_creds = 1; } if (!err) { err = krb5_error (credential->context, @@ -565,6 +588,7 @@ kim_error kim_credential_create_for_change_password (kim_credential *out_creden if (principal) { krb5_free_principal (credential->context, principal); } if (!err) { + *out_user_was_prompted = (in_ui_context->prompt_count > 0); *out_credential = credential; credential = NULL; } diff --git a/src/kim/lib/kim_credential_private.h b/src/kim/lib/kim_credential_private.h index f5045ad85..3f30d6c73 100644 --- a/src/kim/lib/kim_credential_private.h +++ b/src/kim/lib/kim_credential_private.h @@ -33,6 +33,7 @@ kim_error kim_credential_create_for_change_password (kim_credential *out_credential, kim_identity in_identity, kim_string in_old_password, - kim_ui_context *in_ui_context); + kim_ui_context *in_ui_context, + kim_boolean *out_user_was_prompted); #endif /* KIM_CREDENTIAL_PRIVATE_H */ diff --git a/src/kim/lib/kim_identity.c b/src/kim/lib/kim_identity.c index 1ef30c257..1308c3d7a 100644 --- a/src/kim/lib/kim_identity.c +++ b/src/kim/lib/kim_identity.c @@ -653,19 +653,15 @@ static kim_error kim_identity_change_password_with_credential (kim_identity i /* ------------------------------------------------------------------------ */ -kim_error kim_identity_change_password (kim_identity in_identity) +kim_error kim_identity_change_password_common (kim_identity in_identity, + kim_boolean in_old_password_expired, + kim_ui_context *in_ui_context) { kim_error err = KIM_NO_ERROR; - kim_ui_context context; - kim_boolean ui_inited = 0; kim_boolean done = 0; - if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); } - - if (!err) { - err = kim_ui_init (&context); - if (!err) { ui_inited = 1; } - } + if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); } + if (!err && !in_ui_context) { err = check_error (KIM_NULL_PARAMETER_ERR); } while (!err && !done) { char *old_password = NULL; @@ -674,10 +670,11 @@ kim_error kim_identity_change_password (kim_identity in_identity) kim_error rejected_err = KIM_NO_ERROR; kim_string rejected_message = NULL; kim_string rejected_description = NULL; + kim_boolean was_prompted = 0; - err = kim_ui_change_password (&context, + err = kim_ui_change_password (in_ui_context, in_identity, - 0 /* old password not expired */, + in_old_password_expired, &old_password, &new_password, &verify_password); @@ -694,21 +691,22 @@ kim_error kim_identity_change_password (kim_identity in_identity) if (!err) { kim_credential credential = NULL; - if (context.type == kim_ui_type_cli && context.tcontext) { + if (in_ui_context->type == kim_ui_type_cli && in_ui_context->tcontext) { /* command line has already gotten the credentials for us */ - credential = (kim_credential) context.tcontext; + credential = (kim_credential) in_ui_context->tcontext; } else { err = kim_credential_create_for_change_password (&credential, in_identity, old_password, - &context); + in_ui_context, + &was_prompted); } if (!err) { err = kim_identity_change_password_with_credential (in_identity, credential, new_password, - &context, + in_ui_context, &rejected_err, &rejected_message, &rejected_description); @@ -719,27 +717,73 @@ kim_error kim_identity_change_password (kim_identity in_identity) if (!err && rejected_err) { /* Password rejected, report it to the user */ - err = kim_ui_handle_error (&context, in_identity, + err = kim_ui_handle_error (in_ui_context, in_identity, rejected_err, rejected_message, rejected_description); - + } else if (err && err != KIM_USER_CANCELED_ERR) { - /* new creds failed, report error to user */ - err = kim_ui_handle_kim_error (&context, in_identity, - kim_ui_error_type_change_password, - err); + /* new creds failed, report error to user */ + kim_error terr = KIM_NO_ERROR; + + terr = kim_ui_handle_kim_error (in_ui_context, in_identity, + kim_ui_error_type_change_password, + err); + + if (was_prompted) { + /* User was prompted and might have entered bad info + * so let them try again. */ + err = terr; + } } else { /* password change succeeded or the user gave up */ done = 1; + + if (!err) { + kim_error terr = KIM_NO_ERROR; + kim_string saved_password = NULL; + + terr = kim_os_identity_get_saved_password (in_identity, + &saved_password); + if (!terr) { + /* We changed the password and the user had their + * old password saved. Update it. */ + terr = kim_os_identity_set_saved_password (in_identity, + new_password); + } + + kim_string_free (&saved_password); + } } kim_string_free (&rejected_message); kim_string_free (&rejected_description); - kim_ui_free_string (&context, &old_password); - kim_ui_free_string (&context, &new_password); - kim_ui_free_string (&context, &verify_password); + kim_ui_free_string (in_ui_context, &old_password); + kim_ui_free_string (in_ui_context, &new_password); + kim_ui_free_string (in_ui_context, &verify_password); + } + + return check_error (err); +} + +/* ------------------------------------------------------------------------ */ + +kim_error kim_identity_change_password (kim_identity in_identity) +{ + kim_error err = KIM_NO_ERROR; + kim_ui_context context; + kim_boolean ui_inited = 0; + + if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); } + + if (!err) { + err = kim_ui_init (&context); + if (!err) { ui_inited = 1; } + } + + if (!err) { + err = kim_identity_change_password_common (in_identity, 0, &context); } if (ui_inited) { diff --git a/src/kim/lib/kim_identity_private.h b/src/kim/lib/kim_identity_private.h index d22417955..44f8c631d 100644 --- a/src/kim/lib/kim_identity_private.h +++ b/src/kim/lib/kim_identity_private.h @@ -29,6 +29,7 @@ #include #include "kim_library_private.h" +#include "kim_ui_private.h" kim_error kim_identity_get_components (kim_identity in_identity, kim_string *out_components); @@ -45,4 +46,8 @@ kim_error kim_os_identity_get_saved_password (kim_identity in_identity, kim_error kim_os_identity_set_saved_password (kim_identity in_identity, kim_string in_password); +kim_error kim_identity_change_password_common (kim_identity in_identity, + kim_boolean in_old_password_expired, + kim_ui_context *in_ui_context); + #endif /* KIM_IDENTITY_PRIVATE_H */ diff --git a/src/kim/lib/kim_ui.c b/src/kim/lib/kim_ui.c index 4c1ad8b62..5060fb049 100644 --- a/src/kim/lib/kim_ui.c +++ b/src/kim/lib/kim_ui.c @@ -82,6 +82,7 @@ kim_error kim_ui_init (kim_ui_context *io_context) if (!err) { io_context->identity = NULL; + io_context->prompt_count = 0; } return check_error (err); @@ -199,6 +200,8 @@ krb5_error_code kim_ui_prompter (krb5_context in_krb5_context, } if (!got_saved_password) { + context->prompt_count++; + if (context->type == kim_ui_type_gui_plugin) { err = kim_ui_plugin_auth_prompt (context, context->identity, diff --git a/src/kim/lib/kim_ui_cli.c b/src/kim/lib/kim_ui_cli.c index 79f28e0ff..0e5fc9ec4 100644 --- a/src/kim/lib/kim_ui_cli.c +++ b/src/kim/lib/kim_ui_cli.c @@ -349,6 +349,8 @@ kim_error kim_ui_cli_change_password (kim_ui_context *in_context, } while (!err && !done) { + kim_boolean was_prompted = 0; /* ignore because we always prompt */ + kim_string_free (&old_password); err = kim_ui_cli_read_string (&old_password, @@ -359,14 +361,16 @@ kim_error kim_ui_cli_change_password (kim_ui_context *in_context, err = kim_credential_create_for_change_password ((kim_credential *) &in_context->tcontext, in_identity, old_password, - in_context); + in_context, + &was_prompted); } if (err && err != KIM_USER_CANCELED_ERR) { - /* new creds failed, report error to user */ + /* new creds failed, report error to user */ err = kim_ui_handle_kim_error (in_context, in_identity, - kim_ui_error_type_change_password, + kim_ui_error_type_authentication, err); + } else { done = 1; } diff --git a/src/kim/lib/kim_ui_private.h b/src/kim/lib/kim_ui_private.h index abaffcf04..548836f8d 100644 --- a/src/kim/lib/kim_ui_private.h +++ b/src/kim/lib/kim_ui_private.h @@ -48,6 +48,7 @@ typedef struct kim_ui_context { enum kim_ui_type type; void *tcontext; kim_identity identity; + kim_count prompt_count; } kim_ui_context; -- 2.26.2