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;
23 password = (krb5_data *) gak_data;
25 /* If there's already a key of the correct etype, we're done.
26 If the etype is wrong, free the existing key, and make
29 XXX This was the old behavior, and was wrong in hw preauth
30 cases. Is this new behavior -- always asking -- correct in all
34 if (as_key->enctype != etype) {
35 krb5_free_keyblock_contents (context, as_key);
40 if (password->data[0] == '\0') {
44 if ((ret = krb5_unparse_name(context, client, &clientstr)))
47 strcpy(promptstr, "Password for ");
48 strncat(promptstr, clientstr, sizeof(promptstr)-strlen(promptstr)-1);
49 promptstr[sizeof(promptstr)-1] = '\0';
53 prompt.prompt = promptstr;
55 prompt.reply = password;
57 if (ret = (((*prompter)(context, prompter_data, NULL, NULL,
62 if ((salt->length == -1) && (salt->data == NULL)) {
63 if ((ret = krb5_principal2salt(context, client, &defsalt)))
71 ret = krb5_c_string_to_key(context, etype, password, salt, as_key);
74 krb5_xfree(defsalt.data);
79 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
80 krb5_get_init_creds_password(context, creds, client, password, prompter, data,
81 start_time, in_tkt_service, options)
84 krb5_principal client;
86 krb5_prompter_fct prompter;
88 krb5_deltat start_time;
90 krb5_get_init_creds_opt *options;
92 krb5_error_code ret, ret2;
94 krb5_kdc_rep *as_reply;
96 krb5_creds chpw_creds;
97 krb5_get_init_creds_opt chpw_opts;
99 char banner[1024], pw0array[1024], pw1array[1024];
100 krb5_prompt prompt[2];
104 memset(&chpw_creds, 0, sizeof(chpw_creds));
109 if ((pw0.length = strlen(password)) > sizeof(pw0array)) {
113 strcpy(pw0.data, password);
116 pw0.length = sizeof(pw0array);
121 pw1.length = sizeof(pw1array);
123 /* first try: get the requested tkt from any kdc */
125 ret = krb5_get_init_creds(context, creds, client, prompter, data,
126 start_time, in_tkt_service, options,
127 krb5_get_as_key_password, (void *) &pw0,
130 /* check for success */
135 /* If all the kdc's are unavailable, or if the error was due to a
136 user interrupt, fail */
138 if ((ret == KRB5_KDC_UNREACH) ||
139 (ret == KRB5_LIBOS_PWDINTR))
142 /* if the reply did not come from the master kdc, try again with
148 ret2 = krb5_get_init_creds(context, creds, client, prompter, data,
149 start_time, in_tkt_service, options,
150 krb5_get_as_key_password, (void *) &pw0,
158 /* if the master is unreachable, return the error from the
159 slave we were able to contact */
161 if (ret2 == KRB5_KDC_UNREACH)
167 /* at this point, we have an error from the master. if the error
168 is not password expired, or if it is but there's no prompter,
171 if ((ret != KRB5KDC_ERR_KEY_EXP) ||
175 /* ok, we have an expired password. Give the user a few chances
178 /* use a minimal set of options */
180 krb5_get_init_creds_opt_init(&chpw_opts);
181 krb5_get_init_creds_opt_set_tkt_life(&chpw_opts, 5*60);
182 krb5_get_init_creds_opt_set_renew_life(&chpw_opts, 0);
183 krb5_get_init_creds_opt_set_forwardable(&chpw_opts, 0);
184 krb5_get_init_creds_opt_set_proxiable(&chpw_opts, 0);
186 if ((ret = krb5_get_init_creds(context, &chpw_creds, client,
188 start_time, "kadmin/changepw", &chpw_opts,
189 krb5_get_as_key_password, (void *) &pw0,
193 prompt[0].prompt = "Enter new password";
194 prompt[0].hidden = 1;
195 prompt[0].reply = &pw0;
197 prompt[1].prompt = "Enter it again";
198 prompt[1].hidden = 1;
199 prompt[1].reply = &pw1;
201 strcpy(banner, "Password expired. You must change it now.");
203 for (tries = 3; tries; tries--) {
204 pw0.length = sizeof(pw0array);
205 pw1.length = sizeof(pw1array);
207 if (ret = ((*prompter)(context, data, 0, banner,
208 sizeof(prompt)/sizeof(prompt[0]), prompt)))
211 if (strcmp(pw0.data, pw1.data) != 0) {
212 ret = KRB5_LIBOS_BADPWDMATCH;
213 sprintf(banner, "%s. Please try again.", error_message(ret));
214 } else if (pw0.length == 0) {
215 ret = KRB5_CHPW_PWDNULL;
216 sprintf(banner, "%s. Please try again.", error_message(ret));
219 krb5_data code_string;
220 krb5_data result_string;
222 if ((ret = krb5_change_password(context, &chpw_creds, pw0array,
223 &result_code, &code_string,
227 /* the change succeeded. go on */
229 if (result_code == 0) {
230 krb5_xfree(result_string.data);
234 /* set this in case the retry loop falls through */
236 ret = KRB5_CHPW_FAIL;
238 if (result_code != KRB5_KPASSWD_SOFTERROR) {
239 krb5_xfree(result_string.data);
243 /* the error was soft, so try again */
245 /* 100 is I happen to know that no code_string will be longer
248 if (result_string.length > (sizeof(banner)-100))
249 result_string.length = sizeof(banner)-100;
251 sprintf(banner, "%.*s%s%.*s. Please try again.\n",
252 code_string.length, code_string.data,
253 result_string.length?": ":"",
254 result_string.length, result_string.data);
256 krb5_xfree(code_string.data);
257 krb5_xfree(result_string.data);
264 /* the password change was successful. Get an initial ticket
265 from the master. this is the last try. the return from this
268 ret = krb5_get_init_creds(context, creds, client, prompter, data,
269 start_time, in_tkt_service, options,
270 krb5_get_as_key_password, (void *) &pw0,
274 /* if getting the password was successful, then check to see if the
275 password is about to expire, and warn if so */
281 /* XXX 7 days should be configurable. This is all pretty ad hoc,
282 and could probably be improved if I was willing to screw around
283 with timezones, etc. */
287 (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
288 ((ret = krb5_timeofday(context, &now)) == 0) &&
289 as_reply->enc_part2->key_exp &&
290 ((hours = ((as_reply->enc_part2->key_exp-now)/(60*60))) <= 7*24) &&
294 "Warning: Your password will expire in less than one hour.");
295 else if (hours <= 48)
296 sprintf(banner, "Warning: Your password will expire in %d hour%s.",
297 hours, (hours == 1)?"":"s");
299 sprintf(banner, "Warning: Your password will expire in %d days.",
302 /* ignore an error here */
303 (*prompter)(context, data, 0, banner, 0, 0);
307 memset(pw0array, 0, sizeof(pw0array));
308 memset(pw1array, 0, sizeof(pw1array));
309 krb5_free_cred_contents(context, &chpw_creds);
311 krb5_free_kdc_rep(context, as_reply);