Assume that KRB5_PREAUTH_FAILED is subject to propagation delay between the master and replicas (this error is only returned when ENC_TIMESTAMP fails), and if we get a key-expired error right after changing the password, try again against the master KDC. RT#6108 Index: src/lib/krb5/krb/gic_pwd.c =================================================================== --- src/lib/krb5/krb/gic_pwd.c (revision 20704) +++ src/lib/krb5/krb/gic_pwd.c (working copy) @@ -147,10 +147,10 @@ goto cleanup; /* If all the kdc's are unavailable, or if the error was due to a - user interrupt, or preauth errored out, fail */ + user interrupt, or preauth errored out against the master, fail */ if ((ret == KRB5_KDC_UNREACH) || - (ret == KRB5_PREAUTH_FAILED) || + ((ret == KRB5_PREAUTH_FAILED) && use_master) || (ret == KRB5_LIBOS_PWDINTR) || (ret == KRB5_REALM_CANT_RESOLVE)) goto cleanup; @@ -320,6 +320,25 @@ krb5_get_as_key_password, (void *) &pw0, &use_master, &as_reply); + if ((ret != KRB5KDC_ERR_KEY_EXP) || use_master) + goto cleanup; + else { + /* Okay, we *just* changed the password. Retry against a master KDC, + * because either the non-master's using outdated data or the admin + * has set an impossibly low maximum password lifetime. */ + use_master = 1; + ret2 = krb5_get_init_creds(context, creds, client, prompter, data, + start_time, in_tkt_service, opte, + krb5_get_as_key_password, (void *) &pw0, + &use_master, &as_reply); + if ((ret2 != KRB5_KDC_UNREACH) && + (ret2 != KRB5_REALM_CANT_RESOLVE) && + (ret2 != KRB5_REALM_UNKNOWN)) + ret = ret2; + else + use_master = 0; + } + cleanup: krb5int_set_prompt_types(context, 0); /* if getting the password was successful, then check to see if the