Added support to track number of prompts so UIs do not try again unless
authorAlexandra Ellwood <lxs@mit.edu>
Thu, 25 Sep 2008 19:53:18 +0000 (19:53 +0000)
committerAlexandra Ellwood <lxs@mit.edu>
Thu, 25 Sep 2008 19:53:18 +0000 (19:53 +0000)
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
src/kim/lib/kim_credential_private.h
src/kim/lib/kim_identity.c
src/kim/lib/kim_identity_private.h
src/kim/lib/kim_ui.c
src/kim/lib/kim_ui_cli.c
src/kim/lib/kim_ui_private.h

index f77be0993d12698bc613f068575625e061982acb..b03cba1839d12425adecac69514bd646e9b04967 100644 (file)
@@ -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;
     }
index f5045ad850713c6144a9e3d17835bb294e82dba8..3f30d6c738ad63d7ada590b738c480ae5f5e4548 100644 (file)
@@ -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 */
index 1ef30c2572b932c2c4a0cc2a2465bd199de83a7e..1308c3d7adb583537937b04e8e742a1635362297 100644 (file)
@@ -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) {
index d22417955bebc79267a7b2dc2d9a69a19426e19f..44f8c631d5fd0b828a4fe91f505e3bc7577632db 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <kim/kim.h>
 #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 */
index 4c1ad8b6288a6306799d440899dfed2322a19768..5060fb0496e1efc7f1a0f3f109426c7f11a328f1 100644 (file)
@@ -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, 
index 79f28e0ff0798448f1565ee9c222d8c7460f1a97..0e5fc9ec4f01757f85aa4a84273d21a85ea69aa7 100644 (file)
@@ -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;
        }
index abaffcf0424bbb047ce42d9ce945eddcfa0dea56..548836f8d07bbbede3785e7d786f03a5dd6eb7d2 100644 (file)
@@ -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;