5 krb5_get_as_key_password(context, client, etype, prompter, prompter_data,
6 salt, as_key, gak_data)
10 krb5_prompter_fct prompter;
13 krb5_keyblock *as_key;
22 krb5_prompt_type prompt_type;
24 password = (krb5_data *) gak_data;
26 /* If there's already a key of the correct etype, we're done.
27 If the etype is wrong, free the existing key, and make
30 XXX This was the old behavior, and was wrong in hw preauth
31 cases. Is this new behavior -- always asking -- correct in all
35 if (as_key->enctype != etype) {
36 krb5_free_keyblock_contents (context, as_key);
41 if (password->data[0] == '\0') {
45 if ((ret = krb5_unparse_name(context, client, &clientstr)))
48 strcpy(promptstr, "Password for ");
49 strncat(promptstr, clientstr, sizeof(promptstr)-strlen(promptstr)-1);
50 promptstr[sizeof(promptstr)-1] = '\0';
54 prompt.prompt = promptstr;
56 prompt.reply = password;
57 prompt_type = KRB5_PROMPT_TYPE_PASSWORD;
59 /* PROMPTER_INVOCATION */
60 krb5int_set_prompt_types(context, &prompt_type);
61 if (ret = (((*prompter)(context, prompter_data, NULL, NULL,
63 krb5int_set_prompt_types(context, 0);
66 krb5int_set_prompt_types(context, 0);
69 if ((salt->length == -1) && (salt->data == NULL)) {
70 if ((ret = krb5_principal2salt(context, client, &defsalt)))
78 ret = krb5_c_string_to_key(context, etype, password, salt, as_key);
81 krb5_xfree(defsalt.data);
86 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
87 krb5_get_init_creds_password(context, creds, client, password, prompter, data,
88 start_time, in_tkt_service, options)
91 krb5_principal client;
93 krb5_prompter_fct prompter;
95 krb5_deltat start_time;
97 krb5_get_init_creds_opt *options;
99 krb5_error_code ret, ret2;
101 krb5_kdc_rep *as_reply;
103 krb5_creds chpw_creds;
104 krb5_get_init_creds_opt chpw_opts;
106 char banner[1024], pw0array[1024], pw1array[1024];
107 krb5_prompt prompt[2];
108 krb5_prompt_type prompt_types[sizeof(prompt)/sizeof(prompt[0])];
112 memset(&chpw_creds, 0, sizeof(chpw_creds));
117 if ((pw0.length = strlen(password)) > sizeof(pw0array)) {
121 strcpy(pw0.data, password);
124 pw0.length = sizeof(pw0array);
129 pw1.length = sizeof(pw1array);
131 /* first try: get the requested tkt from any kdc */
133 ret = krb5_get_init_creds(context, creds, client, prompter, data,
134 start_time, in_tkt_service, options,
135 krb5_get_as_key_password, (void *) &pw0,
136 use_master, &as_reply);
138 /* check for success */
143 /* If all the kdc's are unavailable, or if the error was due to a
144 user interrupt, fail */
146 if ((ret == KRB5_KDC_UNREACH) ||
147 (ret == KRB5_LIBOS_PWDINTR) ||
148 (ret == KRB5_REALM_CANT_RESOLVE))
151 /* if the reply did not come from the master kdc, try again with
157 ret2 = krb5_get_init_creds(context, creds, client, prompter, data,
158 start_time, in_tkt_service, options,
159 krb5_get_as_key_password, (void *) &pw0,
160 use_master, &as_reply);
167 /* if the master is unreachable, return the error from the
168 slave we were able to contact */
170 if ((ret2 == KRB5_KDC_UNREACH) ||
171 (ret2 == KRB5_REALM_CANT_RESOLVE))
177 #ifdef USE_LOGIN_LIBRARY
178 if (ret == KRB5KDC_ERR_KEY_EXP)
179 goto cleanup; /* Login library will deal appropriately with this error */
182 /* at this point, we have an error from the master. if the error
183 is not password expired, or if it is but there's no prompter,
186 if ((ret != KRB5KDC_ERR_KEY_EXP) ||
190 /* ok, we have an expired password. Give the user a few chances
193 /* use a minimal set of options */
195 krb5_get_init_creds_opt_init(&chpw_opts);
196 krb5_get_init_creds_opt_set_tkt_life(&chpw_opts, 5*60);
197 krb5_get_init_creds_opt_set_renew_life(&chpw_opts, 0);
198 krb5_get_init_creds_opt_set_forwardable(&chpw_opts, 0);
199 krb5_get_init_creds_opt_set_proxiable(&chpw_opts, 0);
201 if ((ret = krb5_get_init_creds(context, &chpw_creds, client,
203 start_time, "kadmin/changepw", &chpw_opts,
204 krb5_get_as_key_password, (void *) &pw0,
208 prompt[0].prompt = "Enter new password";
209 prompt[0].hidden = 1;
210 prompt[0].reply = &pw0;
211 prompt_types[0] = KRB5_PROMPT_TYPE_NEW_PASSWORD;
213 prompt[1].prompt = "Enter it again";
214 prompt[1].hidden = 1;
215 prompt[1].reply = &pw1;
216 prompt_types[1] = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
218 strcpy(banner, "Password expired. You must change it now.");
220 for (tries = 3; tries; tries--) {
221 pw0.length = sizeof(pw0array);
222 pw1.length = sizeof(pw1array);
224 /* PROMPTER_INVOCATION */
225 krb5int_set_prompt_types(context, prompt_types);
226 if (ret = ((*prompter)(context, data, 0, banner,
227 sizeof(prompt)/sizeof(prompt[0]), prompt)))
229 krb5int_set_prompt_types(context, 0);
232 if (strcmp(pw0.data, pw1.data) != 0) {
233 ret = KRB5_LIBOS_BADPWDMATCH;
234 sprintf(banner, "%s. Please try again.", error_message(ret));
235 } else if (pw0.length == 0) {
236 ret = KRB5_CHPW_PWDNULL;
237 sprintf(banner, "%s. Please try again.", error_message(ret));
240 krb5_data code_string;
241 krb5_data result_string;
243 if ((ret = krb5_change_password(context, &chpw_creds, pw0array,
244 &result_code, &code_string,
248 /* the change succeeded. go on */
250 if (result_code == 0) {
251 krb5_xfree(result_string.data);
255 /* set this in case the retry loop falls through */
257 ret = KRB5_CHPW_FAIL;
259 if (result_code != KRB5_KPASSWD_SOFTERROR) {
260 krb5_xfree(result_string.data);
264 /* the error was soft, so try again */
266 /* 100 is I happen to know that no code_string will be longer
269 if (result_string.length > (sizeof(banner)-100))
270 result_string.length = sizeof(banner)-100;
272 sprintf(banner, "%.*s%s%.*s. Please try again.\n",
273 code_string.length, code_string.data,
274 result_string.length?": ":"",
275 result_string.length, result_string.data);
277 krb5_xfree(code_string.data);
278 krb5_xfree(result_string.data);
285 /* the password change was successful. Get an initial ticket
286 from the master. this is the last try. the return from this
289 ret = krb5_get_init_creds(context, creds, client, prompter, data,
290 start_time, in_tkt_service, options,
291 krb5_get_as_key_password, (void *) &pw0,
292 use_master, &as_reply);
295 krb5int_set_prompt_types(context, 0);
296 /* if getting the password was successful, then check to see if the
297 password is about to expire, and warn if so */
303 /* XXX 7 days should be configurable. This is all pretty ad hoc,
304 and could probably be improved if I was willing to screw around
305 with timezones, etc. */
309 (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
310 ((ret = krb5_timeofday(context, &now)) == 0) &&
311 as_reply->enc_part2->key_exp &&
312 ((hours = ((as_reply->enc_part2->key_exp-now)/(60*60))) <= 7*24) &&
316 "Warning: Your password will expire in less than one hour.");
317 else if (hours <= 48)
318 sprintf(banner, "Warning: Your password will expire in %d hour%s.",
319 hours, (hours == 1)?"":"s");
321 sprintf(banner, "Warning: Your password will expire in %d days.",
324 /* ignore an error here */
325 /* PROMPTER_INVOCATION */
326 (*prompter)(context, data, 0, banner, 0, 0);
330 memset(pw0array, 0, sizeof(pw0array));
331 memset(pw1array, 0, sizeof(pw1array));
332 krb5_free_cred_contents(context, &chpw_creds);
334 krb5_free_kdc_rep(context, as_reply);