5 krb5_get_as_key_password(
9 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->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
70 if ((ret = krb5_principal2salt(context, client, &defsalt)))
78 ret = krb5_c_string_to_key_with_params(context, etype, password, salt,
79 params->data?params:NULL, as_key);
82 krb5_xfree(defsalt.data);
87 krb5_error_code KRB5_CALLCONV
88 krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_principal client, char *password, krb5_prompter_fct prompter, void *data, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options)
90 krb5_error_code ret, ret2;
92 krb5_kdc_rep *as_reply;
94 krb5_creds chpw_creds;
95 krb5_get_init_creds_opt chpw_opts;
97 char banner[1024], pw0array[1024], pw1array[1024];
98 krb5_prompt prompt[2];
99 krb5_prompt_type prompt_types[sizeof(prompt)/sizeof(prompt[0])];
103 memset(&chpw_creds, 0, sizeof(chpw_creds));
108 if ((pw0.length = strlen(password)) > sizeof(pw0array)) {
112 strcpy(pw0.data, password);
115 pw0.length = sizeof(pw0array);
120 pw1.length = sizeof(pw1array);
122 /* first try: get the requested tkt from any kdc */
124 ret = krb5_get_init_creds(context, creds, client, prompter, data,
125 start_time, in_tkt_service, options,
126 krb5_get_as_key_password, (void *) &pw0,
127 use_master, &as_reply);
129 /* check for success */
134 /* If all the kdc's are unavailable, or if the error was due to a
135 user interrupt, or preauth errored out, fail */
137 if ((ret == KRB5_KDC_UNREACH) ||
138 (ret == KRB5_PREAUTH_FAILED) ||
139 (ret == KRB5_LIBOS_PWDINTR) ||
140 (ret == KRB5_REALM_CANT_RESOLVE))
143 /* if the reply did not come from the master kdc, try again with
149 ret2 = krb5_get_init_creds(context, creds, client, prompter, data,
150 start_time, in_tkt_service, options,
151 krb5_get_as_key_password, (void *) &pw0,
152 use_master, &as_reply);
159 /* if the master is unreachable, return the error from the
160 slave we were able to contact */
162 if ((ret2 == KRB5_KDC_UNREACH) ||
163 (ret2 == KRB5_REALM_CANT_RESOLVE) ||
164 (ret2 == KRB5_REALM_UNKNOWN))
170 #ifdef USE_LOGIN_LIBRARY
171 if (ret == KRB5KDC_ERR_KEY_EXP)
172 goto cleanup; /* Login library will deal appropriately with this error */
175 /* at this point, we have an error from the master. if the error
176 is not password expired, or if it is but there's no prompter,
179 if ((ret != KRB5KDC_ERR_KEY_EXP) ||
183 /* ok, we have an expired password. Give the user a few chances
186 /* use a minimal set of options */
188 krb5_get_init_creds_opt_init(&chpw_opts);
189 krb5_get_init_creds_opt_set_tkt_life(&chpw_opts, 5*60);
190 krb5_get_init_creds_opt_set_renew_life(&chpw_opts, 0);
191 krb5_get_init_creds_opt_set_forwardable(&chpw_opts, 0);
192 krb5_get_init_creds_opt_set_proxiable(&chpw_opts, 0);
194 if ((ret = krb5_get_init_creds(context, &chpw_creds, client,
196 start_time, "kadmin/changepw", &chpw_opts,
197 krb5_get_as_key_password, (void *) &pw0,
201 prompt[0].prompt = "Enter new password";
202 prompt[0].hidden = 1;
203 prompt[0].reply = &pw0;
204 prompt_types[0] = KRB5_PROMPT_TYPE_NEW_PASSWORD;
206 prompt[1].prompt = "Enter it again";
207 prompt[1].hidden = 1;
208 prompt[1].reply = &pw1;
209 prompt_types[1] = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
211 strcpy(banner, "Password expired. You must change it now.");
213 for (tries = 3; tries; tries--) {
214 pw0.length = sizeof(pw0array);
215 pw1.length = sizeof(pw1array);
217 /* PROMPTER_INVOCATION */
218 krb5int_set_prompt_types(context, prompt_types);
219 if ((ret = ((*prompter)(context, data, 0, banner,
220 sizeof(prompt)/sizeof(prompt[0]), prompt))))
222 krb5int_set_prompt_types(context, 0);
225 if (strcmp(pw0.data, pw1.data) != 0) {
226 ret = KRB5_LIBOS_BADPWDMATCH;
227 sprintf(banner, "%s. Please try again.", error_message(ret));
228 } else if (pw0.length == 0) {
229 ret = KRB5_CHPW_PWDNULL;
230 sprintf(banner, "%s. Please try again.", error_message(ret));
233 krb5_data code_string;
234 krb5_data result_string;
236 if ((ret = krb5_change_password(context, &chpw_creds, pw0array,
237 &result_code, &code_string,
241 /* the change succeeded. go on */
243 if (result_code == 0) {
244 krb5_xfree(result_string.data);
248 /* set this in case the retry loop falls through */
250 ret = KRB5_CHPW_FAIL;
252 if (result_code != KRB5_KPASSWD_SOFTERROR) {
253 krb5_xfree(result_string.data);
257 /* the error was soft, so try again */
259 /* 100 is I happen to know that no code_string will be longer
262 if (result_string.length > (sizeof(banner)-100))
263 result_string.length = sizeof(banner)-100;
265 sprintf(banner, "%.*s%s%.*s. Please try again.\n",
266 (int) code_string.length, code_string.data,
267 result_string.length ? ": " : "",
268 (int) result_string.length,
269 result_string.data ? result_string.data : "");
271 krb5_xfree(code_string.data);
272 krb5_xfree(result_string.data);
279 /* the password change was successful. Get an initial ticket
280 from the master. this is the last try. the return from this
283 ret = krb5_get_init_creds(context, creds, client, prompter, data,
284 start_time, in_tkt_service, options,
285 krb5_get_as_key_password, (void *) &pw0,
286 use_master, &as_reply);
289 krb5int_set_prompt_types(context, 0);
290 /* if getting the password was successful, then check to see if the
291 password is about to expire, and warn if so */
295 krb5_last_req_entry **last_req;
298 /* XXX 7 days should be configurable. This is all pretty ad hoc,
299 and could probably be improved if I was willing to screw around
300 with timezones, etc. */
304 (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
305 ((ret = krb5_timeofday(context, &now)) == 0) &&
306 as_reply->enc_part2->key_exp &&
307 ((hours = ((as_reply->enc_part2->key_exp-now)/(60*60))) <= 7*24) &&
311 "Warning: Your password will expire in less than one hour.");
312 else if (hours <= 48)
313 sprintf(banner, "Warning: Your password will expire in %d hour%s.",
314 hours, (hours == 1)?"":"s");
316 sprintf(banner, "Warning: Your password will expire in %d days.",
319 /* ignore an error here */
320 /* PROMPTER_INVOCATION */
321 (*prompter)(context, data, 0, banner, 0, 0);
322 } else if (prompter &&
324 (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
325 as_reply->enc_part2 && as_reply->enc_part2->last_req) {
327 * Check the last_req fields
330 for (last_req = as_reply->enc_part2->last_req; *last_req; last_req++)
331 if ((*last_req)->lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
332 (*last_req)->lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
336 if ((ret = krb5_timeofday(context, &now)))
339 if ((ret = krb5_timestamp_to_string((*last_req)->value,
343 delta = (*last_req)->value - now;
347 "Warning: Your password will expire in less than one "
349 else if (delta < 86400*2)
351 "Warning: Your password will expire in %d hour%s on %s",
352 delta / 3600, delta < 7200 ? "" : "s", ts);
355 "Warning: Your password will expire in %d days on %s",
357 /* ignore an error here */
358 /* PROMPTER_INVOCATION */
359 (*prompter)(context, data, 0, banner, 0, 0);
364 memset(pw0array, 0, sizeof(pw0array));
365 memset(pw1array, 0, sizeof(pw1array));
366 krb5_free_cred_contents(context, &chpw_creds);
368 krb5_free_kdc_rep(context, as_reply);
372 void krb5int_populate_gic_opt (
373 krb5_context context, krb5_get_init_creds_opt *opt,
374 krb5_flags options, krb5_address * const *addrs, krb5_enctype *ktypes,
375 krb5_preauthtype *pre_auth_types)
378 krb5_get_init_creds_opt_init(opt);
380 krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
382 for (i=0; ktypes[i]; i++);
384 krb5_get_init_creds_opt_set_etype_list(opt, ktypes, i);
386 if (pre_auth_types) {
387 for (i=0; pre_auth_types[i]; i++);
389 krb5_get_init_creds_opt_set_preauth_list(opt, pre_auth_types, i);
391 if (options&KDC_OPT_FORWARDABLE)
392 krb5_get_init_creds_opt_set_forwardable(opt, 1);
393 else krb5_get_init_creds_opt_set_forwardable(opt, 0);
394 if (options&KDC_OPT_PROXIABLE)
395 krb5_get_init_creds_opt_set_proxiable(opt, 1);
396 else krb5_get_init_creds_opt_set_proxiable(opt, 0);
402 Rewrites get_in_tkt in terms of newer get_init_creds API.
403 Attempts to get an initial ticket for creds->client to use server
404 creds->server, (realm is taken from creds->client), with options
405 options, and using creds->times.starttime, creds->times.endtime,
406 creds->times.renew_till as from, till, and rtime.
407 creds->times.renew_till is ignored unless the RENEWABLE option is requested.
409 If addrs is non-NULL, it is used for the addresses requested. If it is
410 null, the system standard addresses are used.
412 If password is non-NULL, it is converted using the cryptosystem entry
413 point for a string conversion routine, seeded with the client's name.
414 If password is passed as NULL, the password is read from the terminal,
415 and then converted into a key.
417 A succesful call will place the ticket in the credentials cache ccache.
419 returns system errors, encryption errors
421 krb5_error_code KRB5_CALLCONV
422 krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
423 krb5_address *const *addrs, krb5_enctype *ktypes,
424 krb5_preauthtype *pre_auth_types,
425 const char *password, krb5_ccache ccache,
426 krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
428 krb5_error_code retval;
431 krb5_get_init_creds_opt opt;
433 krb5_principal server_princ, client_princ;
438 pw0.length = strlen(password);
439 if (pw0.length > sizeof(pw0array))
441 strncpy(pw0.data, password, sizeof(pw0array));
443 pw0.length = sizeof(pw0array);
445 pw0.length = sizeof(pw0array);
447 krb5int_populate_gic_opt(context, &opt,
448 options, addrs, ktypes,
450 retval = krb5_unparse_name( context, creds->server, &server);
453 server_princ = creds->server;
454 client_princ = creds->client;
455 retval = krb5_get_init_creds (context,
456 creds, creds->client,
457 krb5_prompter_posix, NULL,
459 krb5_get_as_key_password, &pw0,
461 krb5_free_unparsed_name( context, server);
466 krb5_free_principal( context, creds->server);
468 krb5_free_principal( context, creds->client);
469 creds->client = client_princ;
470 creds->server = server_princ;
471 /* store it in the ccache! */
473 if ((retval = krb5_cc_store_cred(context, ccache, creds)))