1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 4 */ 5 6 7 #include "k5-int.h" 8 9 #include <kadm5/admin.h> 10 #include "admin_internal.h" 11 12 13 #define string_text error_message 14 15 /* 16 * Function: kadm5_chpass_principal_util 17 * 18 * Purpose: Wrapper around chpass_principal. We can read new pw, change pw and return useful messages 19 * 20 * Arguments: 21 * 22 * princ (input) a krb5b_principal structure for the 23 * principal whose password we should change. 24 * 25 * new_password (input) NULL or a null terminated string with the 26 * the principal's desired new password. If new_password 27 * is NULL then this routine will read a new password. 28 * 29 * pw_ret (output) if non-NULL, points to a static buffer 30 * containing the new password (if password is prompted 31 * internally), or to the new_password argument (if 32 * that is non-NULL). If the former, then the buffer 33 * is only valid until the next call to the function, 34 * and the caller should be sure to zero it when 35 * it is no longer needed. 36 * 37 * msg_ret (output) a useful message is copied here. 38 * 39 * <return value> exit status of 0 for success, else the com err code 40 * for the last significant routine called. 41 * 42 * Requires: 43 * 44 * A msg_ret should point to a buffer large enough for the messasge. 45 * 46 * Effects: 47 * 48 * Modifies: 49 * 50 * 51 */ 52 53 kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle, 54 void *lhandle, 55 krb5_principal princ, 56 char *new_pw, 57 char **ret_pw, 58 char *msg_ret, 59 unsigned int msg_len) 60 { 61 int code, code2; 62 unsigned int pwsize; 63 static char buffer[255]; 64 char *new_password; 65 kadm5_principal_ent_rec princ_ent; 66 kadm5_policy_ent_rec policy_ent; 67 68 _KADM5_CHECK_HANDLE(server_handle); 69 70 if (ret_pw) 71 *ret_pw = NULL; 72 73 if (new_pw != NULL) { 74 new_password = new_pw; 75 } else { /* read the password */ 76 krb5_context context; 77 78 if ((code = (int) kadm5_init_krb5_context(&context)) == 0) { 79 pwsize = sizeof(buffer); 80 code = krb5_read_password(context, KADM5_PW_FIRST_PROMPT, 81 KADM5_PW_SECOND_PROMPT, 82 buffer, &pwsize); 83 krb5_free_context(context); 84 } 85 86 if (code == 0) 87 new_password = buffer; 88 else { 89 #ifdef ZEROPASSWD 90 memset(buffer, 0, sizeof(buffer)); 91 #endif 92 if (code == KRB5_LIBOS_BADPWDMATCH) { 93 strncpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH), 94 msg_len - 1); 95 msg_ret[msg_len - 1] = '\0'; 96 return(code); 97 } else { 98 snprintf(msg_ret, msg_len, "%s %s\n\n%s", 99 error_message(code), 100 string_text(CHPASS_UTIL_WHILE_READING_PASSWORD), 101 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); 102 msg_ret[msg_len - 1] = '\0'; 103 return(code); 104 } 105 } 106 if (pwsize == 0) { 107 #ifdef ZEROPASSWD 108 memset(buffer, 0, sizeof(buffer)); 109 #endif 110 strncpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ), msg_len - 1); 111 msg_ret[msg_len - 1] = '\0'; 112 return(KRB5_LIBOS_CANTREADPWD); /* could do better */ 113 } 114 } 115 116 if (ret_pw) 117 *ret_pw = new_password; 118 119 code = kadm5_chpass_principal(server_handle, princ, new_password); 120 121 #ifdef ZEROPASSWD 122 if (!ret_pw) 123 memset(buffer, 0, sizeof(buffer)); /* in case we read a new password */ 124 #endif 125 126 if (code == KADM5_OK) { 127 strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_CHANGED), msg_len - 1); 128 msg_ret[msg_len - 1] = '\0'; 129 return(0); 130 } 131 132 if ((code != KADM5_PASS_Q_TOOSHORT) && 133 (code != KADM5_PASS_REUSE) &&(code != KADM5_PASS_Q_CLASS) && 134 (code != KADM5_PASS_Q_DICT) && (code != KADM5_PASS_TOOSOON)) { 135 /* Can't get more info for other errors */ 136 snprintf(msg_ret, msg_len, "%s\n%s %s\n", 137 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), 138 error_message(code), 139 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE)); 140 return(code); 141 } 142 143 /* Ok, we have a password quality error. Return a good message */ 144 145 if (code == KADM5_PASS_REUSE) { 146 strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_REUSE), msg_len - 1); 147 msg_ret[msg_len - 1] = '\0'; 148 return(code); 149 } 150 151 if (code == KADM5_PASS_Q_DICT) { 152 strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY), 153 msg_len - 1); 154 msg_ret[msg_len - 1] = '\0'; 155 return(code); 156 } 157 158 /* Look up policy for the remaining messages */ 159 160 code2 = kadm5_get_principal (lhandle, princ, &princ_ent, 161 KADM5_PRINCIPAL_NORMAL_MASK); 162 if (code2 != 0) { 163 snprintf(msg_ret, msg_len, "%s %s\n%s %s\n\n%s\n", 164 error_message(code2), 165 string_text(CHPASS_UTIL_GET_PRINC_INFO), 166 error_message(code), 167 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE), 168 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); 169 msg_ret[msg_len - 1] = '\0'; 170 return(code); 171 } 172 173 if ((princ_ent.aux_attributes & KADM5_POLICY) == 0) { 174 /* Some module implements its own password policy. */ 175 snprintf(msg_ret, msg_len, "%s\n\n%s", 176 error_message(code), 177 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); 178 msg_ret[msg_len - 1] = '\0'; 179 (void) kadm5_free_principal_ent(lhandle, &princ_ent); 180 return(code); 181 } 182 183 code2 = kadm5_get_policy(lhandle, princ_ent.policy, 184 &policy_ent); 185 if (code2 != 0) { 186 snprintf(msg_ret, msg_len, "%s %s\n%s %s\n\n%s\n ", error_message(code2), 187 string_text(CHPASS_UTIL_GET_POLICY_INFO), 188 error_message(code), 189 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE), 190 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); 191 (void) kadm5_free_principal_ent(lhandle, &princ_ent); 192 return(code); 193 } 194 195 if (code == KADM5_PASS_Q_TOOSHORT) { 196 snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_PASSWORD_TOO_SHORT), 197 policy_ent.pw_min_length); 198 (void) kadm5_free_principal_ent(lhandle, &princ_ent); 199 (void) kadm5_free_policy_ent(lhandle, &policy_ent); 200 return(code); 201 } 202 203 /* Can't get more info for other errors */ 204 205 if (code == KADM5_PASS_Q_CLASS) { 206 snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_TOO_FEW_CLASSES), 207 policy_ent.pw_min_classes); 208 (void) kadm5_free_principal_ent(lhandle, &princ_ent); 209 (void) kadm5_free_policy_ent(lhandle, &policy_ent); 210 return(code); 211 } 212 213 if (code == KADM5_PASS_TOOSOON) { 214 time_t until; 215 char *time_string, *ptr; 216 217 until = ts_incr(princ_ent.last_pwd_change, policy_ent.pw_min_life); 218 219 time_string = ctime(&until); 220 if (time_string == NULL) 221 time_string = "(error)"; 222 else if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') 223 *ptr = '\0'; 224 225 snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON), 226 time_string); 227 (void) kadm5_free_principal_ent(lhandle, &princ_ent); 228 (void) kadm5_free_policy_ent(lhandle, &policy_ent); 229 return(code); 230 } 231 232 /* We should never get here, but just in case ... */ 233 snprintf(msg_ret, msg_len, "%s\n%s %s\n", 234 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), 235 error_message(code), 236 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE)); 237 (void) kadm5_free_principal_ent(lhandle, &princ_ent); 238 (void) kadm5_free_policy_ent(lhandle, &policy_ent); 239 return(code); 240 } 241