/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- default_s2k_func
- free_init_creds_ctx
- get_config_time
- init_cred
- report_expiration
- print_expire
- get_init_creds_common
- change_password
- krb5_keyblock_key_proc
- krb5_get_init_creds_keytab
- init_creds_init_as_req
- free_paid
- set_paid
- pa_etype_info2
- pa_etype_info
- pa_pw_or_afs3_salt
- find_pa_data
- process_pa_info
- make_pa_enc_timestamp
- add_enc_ts_padata
- pa_data_to_md_ts_enc
- pa_data_to_key_plain
- pa_data_to_md_pkinit
- pa_data_add_pac_request
- process_pa_data_to_md
- process_pa_data_to_key
- init_cred_loop
- krb5_get_init_creds
- krb5_get_init_creds_password
- init_creds_keyblock_key_proc
- krb5_get_init_creds_keyblock
1 /*
2 * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "krb5_locl.h"
35
36 RCSID("$Id$");
37
38 typedef struct krb5_get_init_creds_ctx {
39 KDCOptions flags;
40 krb5_creds cred;
41 krb5_addresses *addrs;
42 krb5_enctype *etypes;
43 krb5_preauthtype *pre_auth_types;
44 const char *in_tkt_service;
45 unsigned nonce;
46 unsigned pk_nonce;
47
48 krb5_data req_buffer;
49 AS_REQ as_req;
50 int pa_counter;
51
52 const char *password;
53 krb5_s2k_proc key_proc;
54
55 krb5_get_init_creds_tristate req_pac;
56
57 krb5_pk_init_ctx pk_init_ctx;
58 int ic_flags;
59 } krb5_get_init_creds_ctx;
60
61 static krb5_error_code
62 default_s2k_func(krb5_context context, krb5_enctype type,
/* [<][>][^][v][top][bottom][index][help] */
63 krb5_const_pointer keyseed,
64 krb5_salt salt, krb5_data *s2kparms,
65 krb5_keyblock **key)
66 {
67 krb5_error_code ret;
68 krb5_data password;
69 krb5_data opaque;
70
71 password.data = rk_UNCONST(keyseed);
72 password.length = strlen(keyseed);
73 if (s2kparms)
74 opaque = *s2kparms;
75 else
76 krb5_data_zero(&opaque);
77
78 *key = malloc(sizeof(**key));
79 if (*key == NULL)
80 return ENOMEM;
81 ret = krb5_string_to_key_data_salt_opaque(context, type, password,
82 salt, opaque, *key);
83 if (ret) {
84 free(*key);
85 *key = NULL;
86 }
87 return ret;
88 }
89
90 static void
91 free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx)
/* [<][>][^][v][top][bottom][index][help] */
92 {
93 if (ctx->etypes)
94 free(ctx->etypes);
95 if (ctx->pre_auth_types)
96 free (ctx->pre_auth_types);
97 free_AS_REQ(&ctx->as_req);
98 memset(&ctx->as_req, 0, sizeof(ctx->as_req));
99 }
100
101 static int
102 get_config_time (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
103 const char *realm,
104 const char *name,
105 int def)
106 {
107 int ret;
108
109 ret = krb5_config_get_time (context, NULL,
110 "realms",
111 realm,
112 name,
113 NULL);
114 if (ret >= 0)
115 return ret;
116 ret = krb5_config_get_time (context, NULL,
117 "libdefaults",
118 name,
119 NULL);
120 if (ret >= 0)
121 return ret;
122 return def;
123 }
124
125 static krb5_error_code
126 init_cred (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
127 krb5_creds *cred,
128 krb5_principal client,
129 krb5_deltat start_time,
130 const char *in_tkt_service,
131 krb5_get_init_creds_opt *options)
132 {
133 krb5_error_code ret;
134 krb5_const_realm client_realm;
135 int tmp;
136 krb5_timestamp now;
137
138 krb5_timeofday (context, &now);
139
140 memset (cred, 0, sizeof(*cred));
141
142 if (client)
143 krb5_copy_principal(context, client, &cred->client);
144 else {
145 ret = krb5_get_default_principal (context,
146 &cred->client);
147 if (ret)
148 goto out;
149 }
150
151 client_realm = krb5_principal_get_realm (context, cred->client);
152
153 if (start_time)
154 cred->times.starttime = now + start_time;
155
156 if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
157 tmp = options->tkt_life;
158 else
159 tmp = 10 * 60 * 60;
160 cred->times.endtime = now + tmp;
161
162 if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) &&
163 options->renew_life > 0) {
164 cred->times.renew_till = now + options->renew_life;
165 }
166
167 if (in_tkt_service) {
168 ret = krb5_parse_name (context, in_tkt_service, &cred->server);
169 if (ret)
170 goto out;
171 krb5_principal_set_realm (context, cred->server, client_realm);
172 } else {
173 ret = krb5_make_principal(context, &cred->server,
174 client_realm, KRB5_TGS_NAME, client_realm,
175 NULL);
176 if (ret)
177 goto out;
178 }
179 return 0;
180
181 out:
182 krb5_free_cred_contents (context, cred);
183 return ret;
184 }
185
186 /*
187 * Print a message (str) to the user about the expiration in `lr'
188 */
189
190 static void
191 report_expiration (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
192 krb5_prompter_fct prompter,
193 krb5_data *data,
194 const char *str,
195 time_t now)
196 {
197 char *p;
198
199 asprintf (&p, "%s%s", str, ctime(&now));
200 (*prompter) (context, data, NULL, p, 0, NULL);
201 free (p);
202 }
203
204 /*
205 * Parse the last_req data and show it to the user if it's interesting
206 */
207
208 static void
209 print_expire (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
210 krb5_const_realm realm,
211 krb5_kdc_rep *rep,
212 krb5_prompter_fct prompter,
213 krb5_data *data)
214 {
215 int i;
216 LastReq *lr = &rep->enc_part.last_req;
217 krb5_timestamp sec;
218 time_t t;
219 krb5_boolean reported = FALSE;
220
221 krb5_timeofday (context, &sec);
222
223 t = sec + get_config_time (context,
224 realm,
225 "warn_pwexpire",
226 7 * 24 * 60 * 60);
227
228 for (i = 0; i < lr->len; ++i) {
229 if (lr->val[i].lr_value <= t) {
230 switch (abs(lr->val[i].lr_type)) {
231 case LR_PW_EXPTIME :
232 report_expiration(context, prompter, data,
233 "Your password will expire at ",
234 lr->val[i].lr_value);
235 reported = TRUE;
236 break;
237 case LR_ACCT_EXPTIME :
238 report_expiration(context, prompter, data,
239 "Your account will expire at ",
240 lr->val[i].lr_value);
241 reported = TRUE;
242 break;
243 }
244 }
245 }
246
247 if (!reported
248 && rep->enc_part.key_expiration
249 && *rep->enc_part.key_expiration <= t) {
250 report_expiration(context, prompter, data,
251 "Your password/account will expire at ",
252 *rep->enc_part.key_expiration);
253 }
254 }
255
256 static krb5_addresses no_addrs = { 0, NULL };
257
258 static krb5_error_code
259 get_init_creds_common(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
260 krb5_principal client,
261 krb5_deltat start_time,
262 const char *in_tkt_service,
263 krb5_get_init_creds_opt *options,
264 krb5_get_init_creds_ctx *ctx)
265 {
266 krb5_get_init_creds_opt default_opt;
267 krb5_error_code ret;
268 krb5_enctype *etypes;
269 krb5_preauthtype *pre_auth_types;
270
271 memset(ctx, 0, sizeof(*ctx));
272
273 if (options == NULL) {
274 krb5_get_init_creds_opt_init (&default_opt);
275 options = &default_opt;
276 } else {
277 _krb5_get_init_creds_opt_free_krb5_error(options);
278 }
279
280 if (options->opt_private) {
281 ctx->password = options->opt_private->password;
282 ctx->key_proc = options->opt_private->key_proc;
283 ctx->req_pac = options->opt_private->req_pac;
284 ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
285 ctx->ic_flags = options->opt_private->flags;
286 } else
287 ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
288
289 if (ctx->key_proc == NULL)
290 ctx->key_proc = default_s2k_func;
291
292 if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE)
293 ctx->flags.canonicalize = 1;
294
295 ctx->pre_auth_types = NULL;
296 ctx->addrs = NULL;
297 ctx->etypes = NULL;
298 ctx->pre_auth_types = NULL;
299 ctx->in_tkt_service = in_tkt_service;
300
301 ret = init_cred (context, &ctx->cred, client, start_time,
302 in_tkt_service, options);
303 if (ret)
304 return ret;
305
306 if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
307 ctx->flags.forwardable = options->forwardable;
308
309 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
310 ctx->flags.proxiable = options->proxiable;
311
312 if (start_time)
313 ctx->flags.postdated = 1;
314 if (ctx->cred.times.renew_till)
315 ctx->flags.renewable = 1;
316 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
317 ctx->addrs = options->address_list;
318 } else if (options->opt_private) {
319 switch (options->opt_private->addressless) {
320 case KRB5_INIT_CREDS_TRISTATE_UNSET:
321 #if KRB5_ADDRESSLESS_DEFAULT == TRUE
322 ctx->addrs = &no_addrs;
323 #else
324 ctx->addrs = NULL;
325 #endif
326 break;
327 case KRB5_INIT_CREDS_TRISTATE_FALSE:
328 ctx->addrs = NULL;
329 break;
330 case KRB5_INIT_CREDS_TRISTATE_TRUE:
331 ctx->addrs = &no_addrs;
332 break;
333 }
334 }
335 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
336 etypes = malloc((options->etype_list_length + 1)
337 * sizeof(krb5_enctype));
338 if (etypes == NULL) {
339 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
340 return ENOMEM;
341 }
342 memcpy (etypes, options->etype_list,
343 options->etype_list_length * sizeof(krb5_enctype));
344 etypes[options->etype_list_length] = ETYPE_NULL;
345 ctx->etypes = etypes;
346 }
347 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
348 pre_auth_types = malloc((options->preauth_list_length + 1)
349 * sizeof(krb5_preauthtype));
350 if (pre_auth_types == NULL) {
351 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
352 return ENOMEM;
353 }
354 memcpy (pre_auth_types, options->preauth_list,
355 options->preauth_list_length * sizeof(krb5_preauthtype));
356 pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
357 ctx->pre_auth_types = pre_auth_types;
358 }
359 if (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)
360 ; /* XXX */
361 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
362 ctx->flags.request_anonymous = options->anonymous;
363 return 0;
364 }
365
366 static krb5_error_code
367 change_password (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
368 krb5_principal client,
369 const char *password,
370 char *newpw,
371 size_t newpw_sz,
372 krb5_prompter_fct prompter,
373 void *data,
374 krb5_get_init_creds_opt *old_options)
375 {
376 krb5_prompt prompts[2];
377 krb5_error_code ret;
378 krb5_creds cpw_cred;
379 char buf1[BUFSIZ], buf2[BUFSIZ];
380 krb5_data password_data[2];
381 int result_code;
382 krb5_data result_code_string;
383 krb5_data result_string;
384 char *p;
385 krb5_get_init_creds_opt options;
386
387 memset (&cpw_cred, 0, sizeof(cpw_cred));
388
389 krb5_get_init_creds_opt_init (&options);
390 krb5_get_init_creds_opt_set_tkt_life (&options, 60);
391 krb5_get_init_creds_opt_set_forwardable (&options, FALSE);
392 krb5_get_init_creds_opt_set_proxiable (&options, FALSE);
393 if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
394 krb5_get_init_creds_opt_set_preauth_list (&options,
395 old_options->preauth_list,
396 old_options->preauth_list_length);
397
398 krb5_data_zero (&result_code_string);
399 krb5_data_zero (&result_string);
400
401 ret = krb5_get_init_creds_password (context,
402 &cpw_cred,
403 client,
404 password,
405 prompter,
406 data,
407 0,
408 "kadmin/changepw",
409 &options);
410 if (ret)
411 goto out;
412
413 for(;;) {
414 password_data[0].data = buf1;
415 password_data[0].length = sizeof(buf1);
416
417 prompts[0].hidden = 1;
418 prompts[0].prompt = "New password: ";
419 prompts[0].reply = &password_data[0];
420 prompts[0].type = KRB5_PROMPT_TYPE_NEW_PASSWORD;
421
422 password_data[1].data = buf2;
423 password_data[1].length = sizeof(buf2);
424
425 prompts[1].hidden = 1;
426 prompts[1].prompt = "Repeat new password: ";
427 prompts[1].reply = &password_data[1];
428 prompts[1].type = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
429
430 ret = (*prompter) (context, data, NULL, "Changing password",
431 2, prompts);
432 if (ret) {
433 memset (buf1, 0, sizeof(buf1));
434 memset (buf2, 0, sizeof(buf2));
435 goto out;
436 }
437
438 if (strcmp (buf1, buf2) == 0)
439 break;
440 memset (buf1, 0, sizeof(buf1));
441 memset (buf2, 0, sizeof(buf2));
442 }
443
444 ret = krb5_set_password (context,
445 &cpw_cred,
446 buf1,
447 client,
448 &result_code,
449 &result_code_string,
450 &result_string);
451 if (ret)
452 goto out;
453 asprintf (&p, "%s: %.*s\n",
454 result_code ? "Error" : "Success",
455 (int)result_string.length,
456 result_string.length > 0 ? (char*)result_string.data : "");
457
458 ret = (*prompter) (context, data, NULL, p, 0, NULL);
459 free (p);
460 if (result_code == 0) {
461 strlcpy (newpw, buf1, newpw_sz);
462 ret = 0;
463 } else {
464 ret = ENOTTY;
465 krb5_set_error_message(context, ret,
466 N_("failed changing password", ""));
467 }
468
469 out:
470 memset (buf1, 0, sizeof(buf1));
471 memset (buf2, 0, sizeof(buf2));
472 krb5_data_free (&result_string);
473 krb5_data_free (&result_code_string);
474 krb5_free_cred_contents (context, &cpw_cred);
475 return ret;
476 }
477
478 krb5_error_code KRB5_LIB_FUNCTION
479 krb5_keyblock_key_proc (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
480 krb5_keytype type,
481 krb5_data *salt,
482 krb5_const_pointer keyseed,
483 krb5_keyblock **key)
484 {
485 return krb5_copy_keyblock (context, keyseed, key);
486 }
487
488 krb5_error_code KRB5_LIB_FUNCTION
489 krb5_get_init_creds_keytab(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
490 krb5_creds *creds,
491 krb5_principal client,
492 krb5_keytab keytab,
493 krb5_deltat start_time,
494 const char *in_tkt_service,
495 krb5_get_init_creds_opt *options)
496 {
497 krb5_get_init_creds_ctx ctx;
498 krb5_error_code ret;
499 krb5_keytab_key_proc_args *a;
500
501 ret = get_init_creds_common(context, client, start_time,
502 in_tkt_service, options, &ctx);
503 if (ret)
504 goto out;
505
506 a = malloc (sizeof(*a));
507 if (a == NULL) {
508 ret = ENOMEM;
509 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
510 goto out;
511 }
512 a->principal = ctx.cred.client;
513 a->keytab = keytab;
514
515 ret = krb5_get_in_cred (context,
516 KDCOptions2int(ctx.flags),
517 ctx.addrs,
518 ctx.etypes,
519 ctx.pre_auth_types,
520 NULL,
521 krb5_keytab_key_proc,
522 a,
523 NULL,
524 NULL,
525 &ctx.cred,
526 NULL);
527 free (a);
528
529 if (ret == 0 && creds)
530 *creds = ctx.cred;
531 else
532 krb5_free_cred_contents (context, &ctx.cred);
533
534 out:
535 free_init_creds_ctx(context, &ctx);
536 return ret;
537 }
538
539 /*
540 *
541 */
542
543 static krb5_error_code
544 init_creds_init_as_req (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
545 KDCOptions opts,
546 const krb5_creds *creds,
547 const krb5_addresses *addrs,
548 const krb5_enctype *etypes,
549 AS_REQ *a)
550 {
551 krb5_error_code ret;
552
553 memset(a, 0, sizeof(*a));
554
555 a->pvno = 5;
556 a->msg_type = krb_as_req;
557 a->req_body.kdc_options = opts;
558 a->req_body.cname = malloc(sizeof(*a->req_body.cname));
559 if (a->req_body.cname == NULL) {
560 ret = ENOMEM;
561 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
562 goto fail;
563 }
564 a->req_body.sname = malloc(sizeof(*a->req_body.sname));
565 if (a->req_body.sname == NULL) {
566 ret = ENOMEM;
567 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
568 goto fail;
569 }
570
571 ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
572 if (ret)
573 goto fail;
574 ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
575 if (ret)
576 goto fail;
577
578 ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
579 if (ret)
580 goto fail;
581
582 if(creds->times.starttime) {
583 a->req_body.from = malloc(sizeof(*a->req_body.from));
584 if (a->req_body.from == NULL) {
585 ret = ENOMEM;
586 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
587 goto fail;
588 }
589 *a->req_body.from = creds->times.starttime;
590 }
591 if(creds->times.endtime){
592 ALLOC(a->req_body.till, 1);
593 *a->req_body.till = creds->times.endtime;
594 }
595 if(creds->times.renew_till){
596 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
597 if (a->req_body.rtime == NULL) {
598 ret = ENOMEM;
599 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
600 goto fail;
601 }
602 *a->req_body.rtime = creds->times.renew_till;
603 }
604 a->req_body.nonce = 0;
605 ret = krb5_init_etype (context,
606 &a->req_body.etype.len,
607 &a->req_body.etype.val,
608 etypes);
609 if (ret)
610 goto fail;
611
612 /*
613 * This means no addresses
614 */
615
616 if (addrs && addrs->len == 0) {
617 a->req_body.addresses = NULL;
618 } else {
619 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
620 if (a->req_body.addresses == NULL) {
621 ret = ENOMEM;
622 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
623 goto fail;
624 }
625
626 if (addrs)
627 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
628 else {
629 ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
630 if(ret == 0 && a->req_body.addresses->len == 0) {
631 free(a->req_body.addresses);
632 a->req_body.addresses = NULL;
633 }
634 }
635 if (ret)
636 goto fail;
637 }
638
639 a->req_body.enc_authorization_data = NULL;
640 a->req_body.additional_tickets = NULL;
641
642 a->padata = NULL;
643
644 return 0;
645 fail:
646 free_AS_REQ(a);
647 memset(a, 0, sizeof(*a));
648 return ret;
649 }
650
651 struct pa_info_data {
652 krb5_enctype etype;
653 krb5_salt salt;
654 krb5_data *s2kparams;
655 };
656
657 static void
658 free_paid(krb5_context context, struct pa_info_data *ppaid)
/* [<][>][^][v][top][bottom][index][help] */
659 {
660 krb5_free_salt(context, ppaid->salt);
661 if (ppaid->s2kparams)
662 krb5_free_data(context, ppaid->s2kparams);
663 }
664
665
666 static krb5_error_code
667 set_paid(struct pa_info_data *paid, krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
668 krb5_enctype etype,
669 krb5_salttype salttype, void *salt_string, size_t salt_len,
670 krb5_data *s2kparams)
671 {
672 paid->etype = etype;
673 paid->salt.salttype = salttype;
674 paid->salt.saltvalue.data = malloc(salt_len + 1);
675 if (paid->salt.saltvalue.data == NULL) {
676 krb5_clear_error_message(context);
677 return ENOMEM;
678 }
679 memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
680 ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
681 paid->salt.saltvalue.length = salt_len;
682 if (s2kparams) {
683 krb5_error_code ret;
684
685 ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
686 if (ret) {
687 krb5_clear_error_message(context);
688 krb5_free_salt(context, paid->salt);
689 return ret;
690 }
691 } else
692 paid->s2kparams = NULL;
693
694 return 0;
695 }
696
697 static struct pa_info_data *
698 pa_etype_info2(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
699 const krb5_principal client,
700 const AS_REQ *asreq,
701 struct pa_info_data *paid,
702 heim_octet_string *data)
703 {
704 krb5_error_code ret;
705 ETYPE_INFO2 e;
706 size_t sz;
707 int i, j;
708
709 memset(&e, 0, sizeof(e));
710 ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
711 if (ret)
712 goto out;
713 if (e.len == 0)
714 goto out;
715 for (j = 0; j < asreq->req_body.etype.len; j++) {
716 for (i = 0; i < e.len; i++) {
717 if (asreq->req_body.etype.val[j] == e.val[i].etype) {
718 krb5_salt salt;
719 if (e.val[i].salt == NULL)
720 ret = krb5_get_pw_salt(context, client, &salt);
721 else {
722 salt.saltvalue.data = *e.val[i].salt;
723 salt.saltvalue.length = strlen(*e.val[i].salt);
724 ret = 0;
725 }
726 if (ret == 0)
727 ret = set_paid(paid, context, e.val[i].etype,
728 KRB5_PW_SALT,
729 salt.saltvalue.data,
730 salt.saltvalue.length,
731 e.val[i].s2kparams);
732 if (e.val[i].salt == NULL)
733 krb5_free_salt(context, salt);
734 if (ret == 0) {
735 free_ETYPE_INFO2(&e);
736 return paid;
737 }
738 }
739 }
740 }
741 out:
742 free_ETYPE_INFO2(&e);
743 return NULL;
744 }
745
746 static struct pa_info_data *
747 pa_etype_info(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
748 const krb5_principal client,
749 const AS_REQ *asreq,
750 struct pa_info_data *paid,
751 heim_octet_string *data)
752 {
753 krb5_error_code ret;
754 ETYPE_INFO e;
755 size_t sz;
756 int i, j;
757
758 memset(&e, 0, sizeof(e));
759 ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
760 if (ret)
761 goto out;
762 if (e.len == 0)
763 goto out;
764 for (j = 0; j < asreq->req_body.etype.len; j++) {
765 for (i = 0; i < e.len; i++) {
766 if (asreq->req_body.etype.val[j] == e.val[i].etype) {
767 krb5_salt salt;
768 salt.salttype = KRB5_PW_SALT;
769 if (e.val[i].salt == NULL)
770 ret = krb5_get_pw_salt(context, client, &salt);
771 else {
772 salt.saltvalue = *e.val[i].salt;
773 ret = 0;
774 }
775 if (e.val[i].salttype)
776 salt.salttype = *e.val[i].salttype;
777 if (ret == 0) {
778 ret = set_paid(paid, context, e.val[i].etype,
779 salt.salttype,
780 salt.saltvalue.data,
781 salt.saltvalue.length,
782 NULL);
783 if (e.val[i].salt == NULL)
784 krb5_free_salt(context, salt);
785 }
786 if (ret == 0) {
787 free_ETYPE_INFO(&e);
788 return paid;
789 }
790 }
791 }
792 }
793 out:
794 free_ETYPE_INFO(&e);
795 return NULL;
796 }
797
798 static struct pa_info_data *
799 pa_pw_or_afs3_salt(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
800 const krb5_principal client,
801 const AS_REQ *asreq,
802 struct pa_info_data *paid,
803 heim_octet_string *data)
804 {
805 krb5_error_code ret;
806 if (paid->etype == ENCTYPE_NULL)
807 return NULL;
808 ret = set_paid(paid, context,
809 paid->etype,
810 paid->salt.salttype,
811 data->data,
812 data->length,
813 NULL);
814 if (ret)
815 return NULL;
816 return paid;
817 }
818
819
820 struct pa_info {
821 krb5_preauthtype type;
822 struct pa_info_data *(*salt_info)(krb5_context,
823 const krb5_principal,
824 const AS_REQ *,
825 struct pa_info_data *,
826 heim_octet_string *);
827 };
828
829 static struct pa_info pa_prefs[] = {
830 { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 },
831 { KRB5_PADATA_ETYPE_INFO, pa_etype_info },
832 { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt },
833 { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt }
834 };
835
836 static PA_DATA *
837 find_pa_data(const METHOD_DATA *md, int type)
/* [<][>][^][v][top][bottom][index][help] */
838 {
839 int i;
840 if (md == NULL)
841 return NULL;
842 for (i = 0; i < md->len; i++)
843 if (md->val[i].padata_type == type)
844 return &md->val[i];
845 return NULL;
846 }
847
848 static struct pa_info_data *
849 process_pa_info(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
850 const krb5_principal client,
851 const AS_REQ *asreq,
852 struct pa_info_data *paid,
853 METHOD_DATA *md)
854 {
855 struct pa_info_data *p = NULL;
856 int i;
857
858 for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) {
859 PA_DATA *pa = find_pa_data(md, pa_prefs[i].type);
860 if (pa == NULL)
861 continue;
862 paid->salt.salttype = pa_prefs[i].type;
863 p = (*pa_prefs[i].salt_info)(context, client, asreq,
864 paid, &pa->padata_value);
865 }
866 return p;
867 }
868
869 static krb5_error_code
870 make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
/* [<][>][^][v][top][bottom][index][help] */
871 krb5_enctype etype, krb5_keyblock *key)
872 {
873 PA_ENC_TS_ENC p;
874 unsigned char *buf;
875 size_t buf_size;
876 size_t len;
877 EncryptedData encdata;
878 krb5_error_code ret;
879 int32_t usec;
880 int usec2;
881 krb5_crypto crypto;
882
883 krb5_us_timeofday (context, &p.patimestamp, &usec);
884 usec2 = usec;
885 p.pausec = &usec2;
886
887 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
888 if (ret)
889 return ret;
890 if(buf_size != len)
891 krb5_abortx(context, "internal error in ASN.1 encoder");
892
893 ret = krb5_crypto_init(context, key, 0, &crypto);
894 if (ret) {
895 free(buf);
896 return ret;
897 }
898 ret = krb5_encrypt_EncryptedData(context,
899 crypto,
900 KRB5_KU_PA_ENC_TIMESTAMP,
901 buf,
902 len,
903 0,
904 &encdata);
905 free(buf);
906 krb5_crypto_destroy(context, crypto);
907 if (ret)
908 return ret;
909
910 ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
911 free_EncryptedData(&encdata);
912 if (ret)
913 return ret;
914 if(buf_size != len)
915 krb5_abortx(context, "internal error in ASN.1 encoder");
916
917 ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
918 if (ret)
919 free(buf);
920 return ret;
921 }
922
923 static krb5_error_code
924 add_enc_ts_padata(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
925 METHOD_DATA *md,
926 krb5_principal client,
927 krb5_s2k_proc key_proc,
928 krb5_const_pointer keyseed,
929 krb5_enctype *enctypes,
930 unsigned netypes,
931 krb5_salt *salt,
932 krb5_data *s2kparams)
933 {
934 krb5_error_code ret;
935 krb5_salt salt2;
936 krb5_enctype *ep;
937 int i;
938
939 if(salt == NULL) {
940 /* default to standard salt */
941 ret = krb5_get_pw_salt (context, client, &salt2);
942 salt = &salt2;
943 }
944 if (!enctypes) {
945 enctypes = context->etypes;
946 netypes = 0;
947 for (ep = enctypes; *ep != ETYPE_NULL; ep++)
948 netypes++;
949 }
950
951 for (i = 0; i < netypes; ++i) {
952 krb5_keyblock *key;
953
954 ret = (*key_proc)(context, enctypes[i], keyseed,
955 *salt, s2kparams, &key);
956 if (ret)
957 continue;
958 ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
959 krb5_free_keyblock (context, key);
960 if (ret)
961 return ret;
962 }
963 if(salt == &salt2)
964 krb5_free_salt(context, salt2);
965 return 0;
966 }
967
968 static krb5_error_code
969 pa_data_to_md_ts_enc(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
970 const AS_REQ *a,
971 const krb5_principal client,
972 krb5_get_init_creds_ctx *ctx,
973 struct pa_info_data *ppaid,
974 METHOD_DATA *md)
975 {
976 if (ctx->key_proc == NULL || ctx->password == NULL)
977 return 0;
978
979 if (ppaid) {
980 add_enc_ts_padata(context, md, client,
981 ctx->key_proc, ctx->password,
982 &ppaid->etype, 1,
983 &ppaid->salt, ppaid->s2kparams);
984 } else {
985 krb5_salt salt;
986
987 /* make a v5 salted pa-data */
988 add_enc_ts_padata(context, md, client,
989 ctx->key_proc, ctx->password,
990 a->req_body.etype.val, a->req_body.etype.len,
991 NULL, NULL);
992
993 /* make a v4 salted pa-data */
994 salt.salttype = KRB5_PW_SALT;
995 krb5_data_zero(&salt.saltvalue);
996 add_enc_ts_padata(context, md, client,
997 ctx->key_proc, ctx->password,
998 a->req_body.etype.val, a->req_body.etype.len,
999 &salt, NULL);
1000 }
1001 return 0;
1002 }
1003
1004 static krb5_error_code
1005 pa_data_to_key_plain(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1006 const krb5_principal client,
1007 krb5_get_init_creds_ctx *ctx,
1008 krb5_salt salt,
1009 krb5_data *s2kparams,
1010 krb5_enctype etype,
1011 krb5_keyblock **key)
1012 {
1013 krb5_error_code ret;
1014
1015 ret = (*ctx->key_proc)(context, etype, ctx->password,
1016 salt, s2kparams, key);
1017 return ret;
1018 }
1019
1020
1021 static krb5_error_code
1022 pa_data_to_md_pkinit(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1023 const AS_REQ *a,
1024 const krb5_principal client,
1025 krb5_get_init_creds_ctx *ctx,
1026 METHOD_DATA *md)
1027 {
1028 if (ctx->pk_init_ctx == NULL)
1029 return 0;
1030 #ifdef PKINIT
1031 return _krb5_pk_mk_padata(context,
1032 ctx->pk_init_ctx,
1033 &a->req_body,
1034 ctx->pk_nonce,
1035 md);
1036 #else
1037 krb5_set_error_message(context, EINVAL,
1038 N_("no support for PKINIT compiled in", ""));
1039 return EINVAL;
1040 #endif
1041 }
1042
1043 static krb5_error_code
1044 pa_data_add_pac_request(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1045 krb5_get_init_creds_ctx *ctx,
1046 METHOD_DATA *md)
1047 {
1048 size_t len, length;
1049 krb5_error_code ret;
1050 PA_PAC_REQUEST req;
1051 void *buf;
1052
1053 switch (ctx->req_pac) {
1054 case KRB5_INIT_CREDS_TRISTATE_UNSET:
1055 return 0; /* don't bother */
1056 case KRB5_INIT_CREDS_TRISTATE_TRUE:
1057 req.include_pac = 1;
1058 break;
1059 case KRB5_INIT_CREDS_TRISTATE_FALSE:
1060 req.include_pac = 0;
1061 }
1062
1063 ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
1064 &req, &len, ret);
1065 if (ret)
1066 return ret;
1067 if(len != length)
1068 krb5_abortx(context, "internal error in ASN.1 encoder");
1069
1070 ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
1071 if (ret)
1072 free(buf);
1073
1074 return 0;
1075 }
1076
1077 /*
1078 * Assumes caller always will free `out_md', even on error.
1079 */
1080
1081 static krb5_error_code
1082 process_pa_data_to_md(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1083 const krb5_creds *creds,
1084 const AS_REQ *a,
1085 krb5_get_init_creds_ctx *ctx,
1086 METHOD_DATA *in_md,
1087 METHOD_DATA **out_md,
1088 krb5_prompter_fct prompter,
1089 void *prompter_data)
1090 {
1091 krb5_error_code ret;
1092
1093 ALLOC(*out_md, 1);
1094 if (*out_md == NULL) {
1095 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1096 return ENOMEM;
1097 }
1098 (*out_md)->len = 0;
1099 (*out_md)->val = NULL;
1100
1101 /*
1102 * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
1103 * need to expose our password protecting our PKCS12 key.
1104 */
1105
1106 if (ctx->pk_init_ctx) {
1107
1108 ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md);
1109 if (ret)
1110 return ret;
1111
1112 } else if (in_md->len != 0) {
1113 struct pa_info_data paid, *ppaid;
1114
1115 memset(&paid, 0, sizeof(paid));
1116
1117 paid.etype = ENCTYPE_NULL;
1118 ppaid = process_pa_info(context, creds->client, a, &paid, in_md);
1119
1120 pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
1121 if (ppaid)
1122 free_paid(context, ppaid);
1123 }
1124
1125 pa_data_add_pac_request(context, ctx, *out_md);
1126
1127 if ((*out_md)->len == 0) {
1128 free(*out_md);
1129 *out_md = NULL;
1130 }
1131
1132 return 0;
1133 }
1134
1135 static krb5_error_code
1136 process_pa_data_to_key(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1137 krb5_get_init_creds_ctx *ctx,
1138 krb5_creds *creds,
1139 AS_REQ *a,
1140 krb5_kdc_rep *rep,
1141 const krb5_krbhst_info *hi,
1142 krb5_keyblock **key)
1143 {
1144 struct pa_info_data paid, *ppaid = NULL;
1145 krb5_error_code ret;
1146 krb5_enctype etype;
1147 PA_DATA *pa;
1148
1149 memset(&paid, 0, sizeof(paid));
1150
1151 etype = rep->kdc_rep.enc_part.etype;
1152
1153 if (rep->kdc_rep.padata) {
1154 paid.etype = etype;
1155 ppaid = process_pa_info(context, creds->client, a, &paid,
1156 rep->kdc_rep.padata);
1157 }
1158 if (ppaid == NULL) {
1159 ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
1160 if (ret)
1161 return ret;
1162 paid.etype = etype;
1163 paid.s2kparams = NULL;
1164 }
1165
1166 pa = NULL;
1167 if (rep->kdc_rep.padata) {
1168 int idx = 0;
1169 pa = krb5_find_padata(rep->kdc_rep.padata->val,
1170 rep->kdc_rep.padata->len,
1171 KRB5_PADATA_PK_AS_REP,
1172 &idx);
1173 if (pa == NULL) {
1174 idx = 0;
1175 pa = krb5_find_padata(rep->kdc_rep.padata->val,
1176 rep->kdc_rep.padata->len,
1177 KRB5_PADATA_PK_AS_REP_19,
1178 &idx);
1179 }
1180 }
1181 if (pa && ctx->pk_init_ctx) {
1182 #ifdef PKINIT
1183 ret = _krb5_pk_rd_pa_reply(context,
1184 a->req_body.realm,
1185 ctx->pk_init_ctx,
1186 etype,
1187 hi,
1188 ctx->pk_nonce,
1189 &ctx->req_buffer,
1190 pa,
1191 key);
1192 #else
1193 ret = EINVAL;
1194 krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", ""));
1195 #endif
1196 } else if (ctx->password)
1197 ret = pa_data_to_key_plain(context, creds->client, ctx,
1198 paid.salt, paid.s2kparams, etype, key);
1199 else {
1200 ret = EINVAL;
1201 krb5_set_error_message(context, ret, N_("No usable pa data type", ""));
1202 }
1203
1204 free_paid(context, &paid);
1205 return ret;
1206 }
1207
1208 static krb5_error_code
1209 init_cred_loop(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1210 krb5_get_init_creds_opt *init_cred_opts,
1211 const krb5_prompter_fct prompter,
1212 void *prompter_data,
1213 krb5_get_init_creds_ctx *ctx,
1214 krb5_creds *creds,
1215 krb5_kdc_rep *ret_as_reply)
1216 {
1217 krb5_error_code ret;
1218 krb5_kdc_rep rep;
1219 METHOD_DATA md;
1220 krb5_data resp;
1221 size_t len;
1222 size_t size;
1223 krb5_krbhst_info *hi = NULL;
1224 krb5_sendto_ctx stctx = NULL;
1225
1226
1227 memset(&md, 0, sizeof(md));
1228 memset(&rep, 0, sizeof(rep));
1229
1230 _krb5_get_init_creds_opt_free_krb5_error(init_cred_opts);
1231
1232 if (ret_as_reply)
1233 memset(ret_as_reply, 0, sizeof(*ret_as_reply));
1234
1235 ret = init_creds_init_as_req(context, ctx->flags, creds,
1236 ctx->addrs, ctx->etypes, &ctx->as_req);
1237 if (ret)
1238 return ret;
1239
1240 ret = krb5_sendto_ctx_alloc(context, &stctx);
1241 if (ret)
1242 goto out;
1243 krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
1244
1245 /* Set a new nonce. */
1246 krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
1247 ctx->nonce &= 0xffffffff;
1248 /* XXX these just needs to be the same when using Windows PK-INIT */
1249 ctx->pk_nonce = ctx->nonce;
1250
1251 /*
1252 * Increase counter when we want other pre-auth types then
1253 * KRB5_PA_ENC_TIMESTAMP.
1254 */
1255 #define MAX_PA_COUNTER 3
1256
1257 ctx->pa_counter = 0;
1258 while (ctx->pa_counter < MAX_PA_COUNTER) {
1259
1260 ctx->pa_counter++;
1261
1262 if (ctx->as_req.padata) {
1263 free_METHOD_DATA(ctx->as_req.padata);
1264 free(ctx->as_req.padata);
1265 ctx->as_req.padata = NULL;
1266 }
1267
1268 /* Set a new nonce. */
1269 ctx->as_req.req_body.nonce = ctx->nonce;
1270
1271 /* fill_in_md_data */
1272 ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx,
1273 &md, &ctx->as_req.padata,
1274 prompter, prompter_data);
1275 if (ret)
1276 goto out;
1277
1278 krb5_data_free(&ctx->req_buffer);
1279
1280 ASN1_MALLOC_ENCODE(AS_REQ,
1281 ctx->req_buffer.data, ctx->req_buffer.length,
1282 &ctx->as_req, &len, ret);
1283 if (ret)
1284 goto out;
1285 if(len != ctx->req_buffer.length)
1286 krb5_abortx(context, "internal error in ASN.1 encoder");
1287
1288 ret = krb5_sendto_context (context, stctx, &ctx->req_buffer,
1289 creds->client->realm, &resp);
1290 if (ret)
1291 goto out;
1292
1293 memset (&rep, 0, sizeof(rep));
1294 ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
1295 if (ret == 0) {
1296 krb5_data_free(&resp);
1297 krb5_clear_error_message(context);
1298 break;
1299 } else {
1300 /* let's try to parse it as a KRB-ERROR */
1301 KRB_ERROR error;
1302
1303 ret = krb5_rd_error(context, &resp, &error);
1304 if(ret && resp.data && ((char*)resp.data)[0] == 4)
1305 ret = KRB5KRB_AP_ERR_V4_REPLY;
1306 krb5_data_free(&resp);
1307 if (ret)
1308 goto out;
1309
1310 ret = krb5_error_from_rd_error(context, &error, creds);
1311
1312 /*
1313 * If no preauth was set and KDC requires it, give it one
1314 * more try.
1315 */
1316
1317 if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
1318 free_METHOD_DATA(&md);
1319 memset(&md, 0, sizeof(md));
1320
1321 if (error.e_data) {
1322 ret = decode_METHOD_DATA(error.e_data->data,
1323 error.e_data->length,
1324 &md,
1325 NULL);
1326 if (ret)
1327 krb5_set_error_message(context, ret,
1328 N_("failed to decode METHOD DATA", ""));
1329 } else {
1330 /* XXX guess what the server want here add add md */
1331 }
1332 krb5_free_error_contents(context, &error);
1333 if (ret)
1334 goto out;
1335 } else {
1336 _krb5_get_init_creds_opt_set_krb5_error(context,
1337 init_cred_opts,
1338 &error);
1339 if (ret_as_reply)
1340 rep.error = error;
1341 else
1342 krb5_free_error_contents(context, &error);
1343 goto out;
1344 }
1345 }
1346 }
1347
1348 {
1349 krb5_keyblock *key = NULL;
1350 unsigned flags = EXTRACT_TICKET_AS_REQ;
1351
1352 if (ctx->flags.request_anonymous)
1353 flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1354 if (ctx->flags.canonicalize) {
1355 flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1356 flags |= EXTRACT_TICKET_MATCH_REALM;
1357 }
1358 if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
1359 flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
1360
1361 ret = process_pa_data_to_key(context, ctx, creds,
1362 &ctx->as_req, &rep, hi, &key);
1363 if (ret)
1364 goto out;
1365
1366 ret = _krb5_extract_ticket(context,
1367 &rep,
1368 creds,
1369 key,
1370 NULL,
1371 KRB5_KU_AS_REP_ENC_PART,
1372 NULL,
1373 ctx->nonce,
1374 flags,
1375 NULL,
1376 NULL);
1377 krb5_free_keyblock(context, key);
1378 }
1379 out:
1380 if (stctx)
1381 krb5_sendto_ctx_free(context, stctx);
1382 krb5_data_free(&ctx->req_buffer);
1383 free_METHOD_DATA(&md);
1384 memset(&md, 0, sizeof(md));
1385
1386 if (ret == 0 && ret_as_reply)
1387 *ret_as_reply = rep;
1388 else
1389 krb5_free_kdc_rep (context, &rep);
1390 return ret;
1391 }
1392
1393 krb5_error_code KRB5_LIB_FUNCTION
1394 krb5_get_init_creds(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1395 krb5_creds *creds,
1396 krb5_principal client,
1397 krb5_prompter_fct prompter,
1398 void *data,
1399 krb5_deltat start_time,
1400 const char *in_tkt_service,
1401 krb5_get_init_creds_opt *options)
1402 {
1403 krb5_get_init_creds_ctx ctx;
1404 krb5_kdc_rep kdc_reply;
1405 krb5_error_code ret;
1406 char buf[BUFSIZ];
1407 int done;
1408
1409 memset(&kdc_reply, 0, sizeof(kdc_reply));
1410
1411 ret = get_init_creds_common(context, client, start_time,
1412 in_tkt_service, options, &ctx);
1413 if (ret)
1414 goto out;
1415
1416 done = 0;
1417 while(!done) {
1418 memset(&kdc_reply, 0, sizeof(kdc_reply));
1419
1420 ret = init_cred_loop(context,
1421 options,
1422 prompter,
1423 data,
1424 &ctx,
1425 &ctx.cred,
1426 &kdc_reply);
1427
1428 switch (ret) {
1429 case 0 :
1430 done = 1;
1431 break;
1432 case KRB5KDC_ERR_KEY_EXPIRED :
1433 /* try to avoid recursion */
1434
1435 /* don't try to change password where then where none */
1436 if (prompter == NULL || ctx.password == NULL)
1437 goto out;
1438
1439 krb5_clear_error_message (context);
1440
1441 if (ctx.in_tkt_service != NULL
1442 && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0)
1443 goto out;
1444
1445 ret = change_password (context,
1446 client,
1447 ctx.password,
1448 buf,
1449 sizeof(buf),
1450 prompter,
1451 data,
1452 options);
1453 if (ret)
1454 goto out;
1455 ctx.password = buf;
1456 break;
1457 default:
1458 goto out;
1459 }
1460 }
1461
1462 if (prompter)
1463 print_expire (context,
1464 krb5_principal_get_realm (context, ctx.cred.client),
1465 &kdc_reply,
1466 prompter,
1467 data);
1468
1469 out:
1470 memset (buf, 0, sizeof(buf));
1471 free_init_creds_ctx(context, &ctx);
1472 krb5_free_kdc_rep (context, &kdc_reply);
1473 if (ret == 0)
1474 *creds = ctx.cred;
1475 else
1476 krb5_free_cred_contents (context, &ctx.cred);
1477
1478 return ret;
1479 }
1480
1481 krb5_error_code KRB5_LIB_FUNCTION
1482 krb5_get_init_creds_password(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1483 krb5_creds *creds,
1484 krb5_principal client,
1485 const char *password,
1486 krb5_prompter_fct prompter,
1487 void *data,
1488 krb5_deltat start_time,
1489 const char *in_tkt_service,
1490 krb5_get_init_creds_opt *in_options)
1491 {
1492 krb5_get_init_creds_opt *options;
1493 char buf[BUFSIZ];
1494 krb5_error_code ret;
1495
1496 if (in_options == NULL) {
1497 const char *realm = krb5_principal_get_realm(context, client);
1498 ret = krb5_get_init_creds_opt_alloc(context, &options);
1499 if (ret == 0)
1500 krb5_get_init_creds_opt_set_default_flags(context,
1501 NULL,
1502 realm,
1503 options);
1504 } else
1505 ret = _krb5_get_init_creds_opt_copy(context, in_options, &options);
1506 if (ret)
1507 return ret;
1508
1509 if (password == NULL &&
1510 options->opt_private->password == NULL &&
1511 options->opt_private->pk_init_ctx == NULL)
1512 {
1513 krb5_prompt prompt;
1514 krb5_data password_data;
1515 char *p, *q;
1516
1517 krb5_unparse_name (context, client, &p);
1518 asprintf (&q, "%s's Password: ", p);
1519 free (p);
1520 prompt.prompt = q;
1521 password_data.data = buf;
1522 password_data.length = sizeof(buf);
1523 prompt.hidden = 1;
1524 prompt.reply = &password_data;
1525 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1526
1527 ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
1528 free (q);
1529 if (ret) {
1530 memset (buf, 0, sizeof(buf));
1531 krb5_get_init_creds_opt_free(context, options);
1532 ret = KRB5_LIBOS_PWDINTR;
1533 krb5_clear_error_message (context);
1534 return ret;
1535 }
1536 password = password_data.data;
1537 }
1538
1539 if (options->opt_private->password == NULL) {
1540 ret = krb5_get_init_creds_opt_set_pa_password(context, options,
1541 password, NULL);
1542 if (ret) {
1543 krb5_get_init_creds_opt_free(context, options);
1544 memset(buf, 0, sizeof(buf));
1545 return ret;
1546 }
1547 }
1548
1549 ret = krb5_get_init_creds(context, creds, client, prompter,
1550 data, start_time, in_tkt_service, options);
1551 krb5_get_init_creds_opt_free(context, options);
1552 memset(buf, 0, sizeof(buf));
1553 return ret;
1554 }
1555
1556 static krb5_error_code
1557 init_creds_keyblock_key_proc (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1558 krb5_enctype type,
1559 krb5_salt salt,
1560 krb5_const_pointer keyseed,
1561 krb5_keyblock **key)
1562 {
1563 return krb5_copy_keyblock (context, keyseed, key);
1564 }
1565
1566 krb5_error_code KRB5_LIB_FUNCTION
1567 krb5_get_init_creds_keyblock(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1568 krb5_creds *creds,
1569 krb5_principal client,
1570 krb5_keyblock *keyblock,
1571 krb5_deltat start_time,
1572 const char *in_tkt_service,
1573 krb5_get_init_creds_opt *options)
1574 {
1575 struct krb5_get_init_creds_ctx ctx;
1576 krb5_error_code ret;
1577
1578 ret = get_init_creds_common(context, client, start_time,
1579 in_tkt_service, options, &ctx);
1580 if (ret)
1581 goto out;
1582
1583 ret = krb5_get_in_cred (context,
1584 KDCOptions2int(ctx.flags),
1585 ctx.addrs,
1586 ctx.etypes,
1587 ctx.pre_auth_types,
1588 NULL,
1589 init_creds_keyblock_key_proc,
1590 keyblock,
1591 NULL,
1592 NULL,
1593 &ctx.cred,
1594 NULL);
1595
1596 if (ret == 0 && creds)
1597 *creds = ctx.cred;
1598 else
1599 krb5_free_cred_contents (context, &ctx.cred);
1600
1601 out:
1602 free_init_creds_ctx(context, &ctx);
1603 return ret;
1604 }