The result string is not being generated in the KRB-PRIV message by the MIT kadmin server. The specific failure is when the password's minimum life has not expired. This is from the fact that check_min_life() never generates the result string. The causes the default (terse) error message to be returned to the user, with no indication of what the real problem is: % kpasswd poe kpasswd: Changing password for poe. Old password: New password: New password (again): kpasswd: Password change rejected I would rather see something like this: % kpasswd poe kpasswd: Changing password for poe. Old password: New password: New password (again): kpasswd: Password change rejected: Password cannot be changed because it was changed too recently. Please wait until Tue Jun 7 00:53:06 2005 before you change it. If you need to change your password before then, contact your system security administrator. The fix includes the following diffs based on MIT 1.4.1: kadmin/server/misc.c: @@ -41,11 +41,11 @@ krb5_key_salt_tuple *ks_tuple, char *password) { kadm5_ret_t ret; - ret = check_min_life(server_handle, principal); + ret = check_min_life(server_handle, principal, NULL); if (ret) return ret; return kadm5_chpass_principal_3(server_handle, principal, keepold, n_ks_tuple, ks_tuple, @@ -84,11 +84,11 @@ krb5_key_salt_tuple *ks_tuple, krb5_keyblock **keys, int *n_keys) { kadm5_ret_t ret; - ret = check_min_life(server_handle, principal); + ret = check_min_life(server_handle, principal, NULL); if (ret) return ret; return kadm5_randkey_principal_3(server_handle, principal, keepold, n_ks_tuple, ks_tuple, keys, n_keys); @@ -99,21 +99,21 @@ char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len) { kadm5_ret_t ret; - ret = check_min_life(server_handle, princ); + ret = check_min_life(server_handle, princ, msg_ret); if (ret) return ret; return kadm5_chpass_principal_util(server_handle, princ, new_pw, ret_pw, msg_ret, msg_len); } kadm5_ret_t -check_min_life(void *server_handle, krb5_principal principal) +check_min_life(void *server_handle, krb5_principal principal, char *msg_ret) { krb5_int32 now; kadm5_ret_t ret; kadm5_policy_ent_rec pol; kadm5_principal_ent_rec princ; @@ -133,10 +133,19 @@ (void) kadm5_free_principal_ent(handle->lhandle, &princ); return ret; } if((now - princ.last_pwd_change) < pol.pw_min_life && !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { + if (msg_ret != NULL) { + char *time_string; + time_t until; + + until = princ.last_pwd_change + pol.pw_min_life; + time_string = ctime(&until); + sprintf(msg_ret, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON), + time_string); + } (void) kadm5_free_policy_ent(handle->lhandle, &pol); (void) kadm5_free_principal_ent(handle->lhandle, &princ); return KADM5_PASS_TOOSOON; } kadmin/server/misc.h: @@ -22,11 +22,12 @@ kadm5_ret_t chpass_util_wrapper(void *server_handle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len); -kadm5_ret_t check_min_life(void *server_handle, krb5_principal principal); +kadm5_ret_t check_min_life(void *server_handle, krb5_principal principal, + char *msg_ret); kadm5_ret_t kadm5_get_principal_v1(void *server_handle, krb5_principal principal, kadm5_principal_ent_t_v1 *ent); @@ -39,8 +40,10 @@ char *realm, int s, krb5_keytab keytab, struct sockaddr_in *sockin, krb5_data *req, krb5_data *rep); +#define string_text error_message + #ifdef SVC_GETARGS void kadm_1(struct svc_req *, SVCXPRT *); #endif Shawn. --