No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / init_creds_pw.c
blobb2715c16ed291a986880b624366c5d55df5f45a1
1 /*
2 * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "krb5_locl.h"
36 __RCSID("$Heimdal: init_creds_pw.c 21931 2007-08-27 14:11:55Z lha $"
37 "$NetBSD$");
39 typedef struct krb5_get_init_creds_ctx {
40 KDCOptions flags;
41 krb5_creds cred;
42 krb5_addresses *addrs;
43 krb5_enctype *etypes;
44 krb5_preauthtype *pre_auth_types;
45 const char *in_tkt_service;
46 unsigned nonce;
47 unsigned pk_nonce;
49 krb5_data req_buffer;
50 AS_REQ as_req;
51 int pa_counter;
53 const char *password;
54 krb5_s2k_proc key_proc;
56 krb5_get_init_creds_tristate req_pac;
58 krb5_pk_init_ctx pk_init_ctx;
59 int ic_flags;
60 } krb5_get_init_creds_ctx;
62 static krb5_error_code
63 default_s2k_func(krb5_context context, krb5_enctype type,
64 krb5_const_pointer keyseed,
65 krb5_salt salt, krb5_data *s2kparms,
66 krb5_keyblock **key)
68 krb5_error_code ret;
69 krb5_data password;
70 krb5_data opaque;
72 password.data = rk_UNCONST(keyseed);
73 password.length = strlen(keyseed);
74 if (s2kparms)
75 opaque = *s2kparms;
76 else
77 krb5_data_zero(&opaque);
79 *key = malloc(sizeof(**key));
80 if (*key == NULL)
81 return ENOMEM;
82 ret = krb5_string_to_key_data_salt_opaque(context, type, password,
83 salt, opaque, *key);
84 if (ret) {
85 free(*key);
86 *key = NULL;
88 return ret;
91 static void
92 free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx)
94 if (ctx->etypes)
95 free(ctx->etypes);
96 if (ctx->pre_auth_types)
97 free (ctx->pre_auth_types);
98 free_AS_REQ(&ctx->as_req);
99 memset(&ctx->as_req, 0, sizeof(ctx->as_req));
102 static int
103 get_config_time (krb5_context context,
104 const char *realm,
105 const char *name,
106 int def)
108 int ret;
110 ret = krb5_config_get_time (context, NULL,
111 "realms",
112 realm,
113 name,
114 NULL);
115 if (ret >= 0)
116 return ret;
117 ret = krb5_config_get_time (context, NULL,
118 "libdefaults",
119 name,
120 NULL);
121 if (ret >= 0)
122 return ret;
123 return def;
126 static krb5_error_code
127 init_cred (krb5_context context,
128 krb5_creds *cred,
129 krb5_principal client,
130 krb5_deltat start_time,
131 const char *in_tkt_service,
132 krb5_get_init_creds_opt *options)
134 krb5_error_code ret;
135 krb5_const_realm client_realm;
136 int tmp;
137 krb5_timestamp now;
139 krb5_timeofday (context, &now);
141 memset (cred, 0, sizeof(*cred));
143 if (client)
144 krb5_copy_principal(context, client, &cred->client);
145 else {
146 ret = krb5_get_default_principal (context,
147 &cred->client);
148 if (ret)
149 goto out;
152 client_realm = krb5_principal_get_realm (context, cred->client);
154 if (start_time)
155 cred->times.starttime = now + start_time;
157 if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
158 tmp = options->tkt_life;
159 else
160 tmp = 10 * 60 * 60;
161 cred->times.endtime = now + tmp;
163 if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) &&
164 options->renew_life > 0) {
165 cred->times.renew_till = now + options->renew_life;
168 if (in_tkt_service) {
169 krb5_realm server_realm;
171 ret = krb5_parse_name (context, in_tkt_service, &cred->server);
172 if (ret)
173 goto out;
174 server_realm = strdup (client_realm);
175 free (*krb5_princ_realm(context, cred->server));
176 krb5_princ_set_realm (context, cred->server, &server_realm);
177 } else {
178 ret = krb5_make_principal(context, &cred->server,
179 client_realm, KRB5_TGS_NAME, client_realm,
180 NULL);
181 if (ret)
182 goto out;
184 return 0;
186 out:
187 krb5_free_cred_contents (context, cred);
188 return ret;
192 * Print a message (str) to the user about the expiration in `lr'
195 static void
196 report_expiration (krb5_context context,
197 krb5_prompter_fct prompter,
198 krb5_data *data,
199 const char *str,
200 time_t now)
202 char *p;
204 asprintf (&p, "%s%s", str, ctime(&now));
205 (*prompter) (context, data, NULL, p, 0, NULL);
206 free (p);
210 * Parse the last_req data and show it to the user if it's interesting
213 static void
214 print_expire (krb5_context context,
215 krb5_const_realm realm,
216 krb5_kdc_rep *rep,
217 krb5_prompter_fct prompter,
218 krb5_data *data)
220 int i;
221 LastReq *lr = &rep->enc_part.last_req;
222 krb5_timestamp sec;
223 time_t t;
224 krb5_boolean reported = FALSE;
226 krb5_timeofday (context, &sec);
228 t = sec + get_config_time (context,
229 realm,
230 "warn_pwexpire",
231 7 * 24 * 60 * 60);
233 for (i = 0; i < lr->len; ++i) {
234 if (lr->val[i].lr_value <= t) {
235 switch (abs(lr->val[i].lr_type)) {
236 case LR_PW_EXPTIME :
237 report_expiration(context, prompter, data,
238 "Your password will expire at ",
239 lr->val[i].lr_value);
240 reported = TRUE;
241 break;
242 case LR_ACCT_EXPTIME :
243 report_expiration(context, prompter, data,
244 "Your account will expire at ",
245 lr->val[i].lr_value);
246 reported = TRUE;
247 break;
252 if (!reported
253 && rep->enc_part.key_expiration
254 && *rep->enc_part.key_expiration <= t) {
255 report_expiration(context, prompter, data,
256 "Your password/account will expire at ",
257 *rep->enc_part.key_expiration);
261 static krb5_addresses no_addrs = { 0, NULL };
263 static krb5_error_code
264 get_init_creds_common(krb5_context context,
265 krb5_principal client,
266 krb5_deltat start_time,
267 const char *in_tkt_service,
268 krb5_get_init_creds_opt *options,
269 krb5_get_init_creds_ctx *ctx)
271 krb5_get_init_creds_opt default_opt;
272 krb5_error_code ret;
273 krb5_enctype *etypes;
274 krb5_preauthtype *pre_auth_types;
276 memset(ctx, 0, sizeof(*ctx));
278 if (options == NULL) {
279 krb5_get_init_creds_opt_init (&default_opt);
280 options = &default_opt;
281 } else {
282 _krb5_get_init_creds_opt_free_krb5_error(options);
285 if (options->opt_private) {
286 ctx->password = options->opt_private->password;
287 ctx->key_proc = options->opt_private->key_proc;
288 ctx->req_pac = options->opt_private->req_pac;
289 ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
290 ctx->ic_flags = options->opt_private->flags;
291 } else
292 ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
294 if (ctx->key_proc == NULL)
295 ctx->key_proc = default_s2k_func;
297 if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE)
298 ctx->flags.canonicalize = 1;
300 ctx->pre_auth_types = NULL;
301 ctx->addrs = NULL;
302 ctx->etypes = NULL;
303 ctx->pre_auth_types = NULL;
304 ctx->in_tkt_service = in_tkt_service;
306 ret = init_cred (context, &ctx->cred, client, start_time,
307 in_tkt_service, options);
308 if (ret)
309 return ret;
311 if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
312 ctx->flags.forwardable = options->forwardable;
314 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
315 ctx->flags.proxiable = options->proxiable;
317 if (start_time)
318 ctx->flags.postdated = 1;
319 if (ctx->cred.times.renew_till)
320 ctx->flags.renewable = 1;
321 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
322 ctx->addrs = options->address_list;
323 } else if (options->opt_private) {
324 switch (options->opt_private->addressless) {
325 case KRB5_INIT_CREDS_TRISTATE_UNSET:
326 #if KRB5_ADDRESSLESS_DEFAULT == TRUE
327 ctx->addrs = &no_addrs;
328 #else
329 ctx->addrs = NULL;
330 #endif
331 break;
332 case KRB5_INIT_CREDS_TRISTATE_FALSE:
333 ctx->addrs = NULL;
334 break;
335 case KRB5_INIT_CREDS_TRISTATE_TRUE:
336 ctx->addrs = &no_addrs;
337 break;
340 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
341 etypes = malloc((options->etype_list_length + 1)
342 * sizeof(krb5_enctype));
343 if (etypes == NULL) {
344 krb5_set_error_string(context, "malloc: out of memory");
345 return ENOMEM;
347 memcpy (etypes, options->etype_list,
348 options->etype_list_length * sizeof(krb5_enctype));
349 etypes[options->etype_list_length] = ETYPE_NULL;
350 ctx->etypes = etypes;
352 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
353 pre_auth_types = malloc((options->preauth_list_length + 1)
354 * sizeof(krb5_preauthtype));
355 if (pre_auth_types == NULL) {
356 krb5_set_error_string(context, "malloc: out of memory");
357 return ENOMEM;
359 memcpy (pre_auth_types, options->preauth_list,
360 options->preauth_list_length * sizeof(krb5_preauthtype));
361 pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
362 ctx->pre_auth_types = pre_auth_types;
364 if (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)
365 ; /* XXX */
366 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
367 ctx->flags.request_anonymous = options->anonymous;
368 return 0;
371 static krb5_error_code
372 change_password (krb5_context context,
373 krb5_principal client,
374 const char *password,
375 char *newpw,
376 size_t newpw_sz,
377 krb5_prompter_fct prompter,
378 void *data,
379 krb5_get_init_creds_opt *old_options)
381 krb5_prompt prompts[2];
382 krb5_error_code ret;
383 krb5_creds cpw_cred;
384 char buf1[BUFSIZ], buf2[BUFSIZ];
385 krb5_data password_data[2];
386 int result_code;
387 krb5_data result_code_string;
388 krb5_data result_string;
389 char *p;
390 krb5_get_init_creds_opt options;
392 memset (&cpw_cred, 0, sizeof(cpw_cred));
394 krb5_get_init_creds_opt_init (&options);
395 krb5_get_init_creds_opt_set_tkt_life (&options, 60);
396 krb5_get_init_creds_opt_set_forwardable (&options, FALSE);
397 krb5_get_init_creds_opt_set_proxiable (&options, FALSE);
398 if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
399 krb5_get_init_creds_opt_set_preauth_list (&options,
400 old_options->preauth_list,
401 old_options->preauth_list_length);
403 krb5_data_zero (&result_code_string);
404 krb5_data_zero (&result_string);
406 ret = krb5_get_init_creds_password (context,
407 &cpw_cred,
408 client,
409 password,
410 prompter,
411 data,
413 "kadmin/changepw",
414 &options);
415 if (ret)
416 goto out;
418 for(;;) {
419 password_data[0].data = buf1;
420 password_data[0].length = sizeof(buf1);
422 prompts[0].hidden = 1;
423 prompts[0].prompt = "New password: ";
424 prompts[0].reply = &password_data[0];
425 prompts[0].type = KRB5_PROMPT_TYPE_NEW_PASSWORD;
427 password_data[1].data = buf2;
428 password_data[1].length = sizeof(buf2);
430 prompts[1].hidden = 1;
431 prompts[1].prompt = "Repeat new password: ";
432 prompts[1].reply = &password_data[1];
433 prompts[1].type = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
435 ret = (*prompter) (context, data, NULL, "Changing password",
436 2, prompts);
437 if (ret) {
438 memset (buf1, 0, sizeof(buf1));
439 memset (buf2, 0, sizeof(buf2));
440 goto out;
443 if (strcmp (buf1, buf2) == 0)
444 break;
445 memset (buf1, 0, sizeof(buf1));
446 memset (buf2, 0, sizeof(buf2));
449 ret = krb5_change_password (context,
450 &cpw_cred,
451 buf1,
452 &result_code,
453 &result_code_string,
454 &result_string);
455 if (ret)
456 goto out;
457 asprintf (&p, "%s: %.*s\n",
458 result_code ? "Error" : "Success",
459 (int)result_string.length,
460 result_string.length > 0 ? (char*)result_string.data : "");
462 ret = (*prompter) (context, data, NULL, p, 0, NULL);
463 free (p);
464 if (result_code == 0) {
465 strlcpy (newpw, buf1, newpw_sz);
466 ret = 0;
467 } else {
468 krb5_set_error_string (context, "failed changing password");
469 ret = ENOTTY;
472 out:
473 memset (buf1, 0, sizeof(buf1));
474 memset (buf2, 0, sizeof(buf2));
475 krb5_data_free (&result_string);
476 krb5_data_free (&result_code_string);
477 krb5_free_cred_contents (context, &cpw_cred);
478 return ret;
481 krb5_error_code KRB5_LIB_FUNCTION
482 krb5_keyblock_key_proc (krb5_context context,
483 krb5_keytype type,
484 krb5_data *salt,
485 krb5_const_pointer keyseed,
486 krb5_keyblock **key)
488 return krb5_copy_keyblock (context, keyseed, key);
491 krb5_error_code KRB5_LIB_FUNCTION
492 krb5_get_init_creds_keytab(krb5_context context,
493 krb5_creds *creds,
494 krb5_principal client,
495 krb5_keytab keytab,
496 krb5_deltat start_time,
497 const char *in_tkt_service,
498 krb5_get_init_creds_opt *options)
500 krb5_get_init_creds_ctx ctx;
501 krb5_error_code ret;
502 krb5_keytab_key_proc_args *a;
504 ret = get_init_creds_common(context, client, start_time,
505 in_tkt_service, options, &ctx);
506 if (ret)
507 goto out;
509 a = malloc (sizeof(*a));
510 if (a == NULL) {
511 krb5_set_error_string(context, "malloc: out of memory");
512 ret = ENOMEM;
513 goto out;
515 a->principal = ctx.cred.client;
516 a->keytab = keytab;
518 ret = krb5_get_in_cred (context,
519 KDCOptions2int(ctx.flags),
520 ctx.addrs,
521 ctx.etypes,
522 ctx.pre_auth_types,
523 NULL,
524 krb5_keytab_key_proc,
526 NULL,
527 NULL,
528 &ctx.cred,
529 NULL);
530 free (a);
532 if (ret == 0 && creds)
533 *creds = ctx.cred;
534 else
535 krb5_free_cred_contents (context, &ctx.cred);
537 out:
538 free_init_creds_ctx(context, &ctx);
539 return ret;
546 static krb5_error_code
547 init_creds_init_as_req (krb5_context context,
548 KDCOptions opts,
549 const krb5_creds *creds,
550 const krb5_addresses *addrs,
551 const krb5_enctype *etypes,
552 AS_REQ *a)
554 krb5_error_code ret;
556 memset(a, 0, sizeof(*a));
558 a->pvno = 5;
559 a->msg_type = krb_as_req;
560 a->req_body.kdc_options = opts;
561 a->req_body.cname = malloc(sizeof(*a->req_body.cname));
562 if (a->req_body.cname == NULL) {
563 ret = ENOMEM;
564 krb5_set_error_string(context, "malloc: out of memory");
565 goto fail;
567 a->req_body.sname = malloc(sizeof(*a->req_body.sname));
568 if (a->req_body.sname == NULL) {
569 ret = ENOMEM;
570 krb5_set_error_string(context, "malloc: out of memory");
571 goto fail;
574 ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
575 if (ret)
576 goto fail;
577 ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
578 if (ret)
579 goto fail;
581 ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
582 if (ret)
583 goto fail;
585 if(creds->times.starttime) {
586 a->req_body.from = malloc(sizeof(*a->req_body.from));
587 if (a->req_body.from == NULL) {
588 ret = ENOMEM;
589 krb5_set_error_string(context, "malloc: out of memory");
590 goto fail;
592 *a->req_body.from = creds->times.starttime;
594 if(creds->times.endtime){
595 ALLOC(a->req_body.till, 1);
596 *a->req_body.till = creds->times.endtime;
598 if(creds->times.renew_till){
599 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
600 if (a->req_body.rtime == NULL) {
601 ret = ENOMEM;
602 krb5_set_error_string(context, "malloc: out of memory");
603 goto fail;
605 *a->req_body.rtime = creds->times.renew_till;
607 a->req_body.nonce = 0;
608 ret = krb5_init_etype (context,
609 &a->req_body.etype.len,
610 &a->req_body.etype.val,
611 etypes);
612 if (ret)
613 goto fail;
616 * This means no addresses
619 if (addrs && addrs->len == 0) {
620 a->req_body.addresses = NULL;
621 } else {
622 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
623 if (a->req_body.addresses == NULL) {
624 ret = ENOMEM;
625 krb5_set_error_string(context, "malloc: out of memory");
626 goto fail;
629 if (addrs)
630 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
631 else {
632 ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
633 if(ret == 0 && a->req_body.addresses->len == 0) {
634 free(a->req_body.addresses);
635 a->req_body.addresses = NULL;
638 if (ret)
639 goto fail;
642 a->req_body.enc_authorization_data = NULL;
643 a->req_body.additional_tickets = NULL;
645 a->padata = NULL;
647 return 0;
648 fail:
649 free_AS_REQ(a);
650 memset(a, 0, sizeof(*a));
651 return ret;
654 struct pa_info_data {
655 krb5_enctype etype;
656 krb5_salt salt;
657 krb5_data *s2kparams;
660 static void
661 free_paid(krb5_context context, struct pa_info_data *ppaid)
663 krb5_free_salt(context, ppaid->salt);
664 if (ppaid->s2kparams)
665 krb5_free_data(context, ppaid->s2kparams);
669 static krb5_error_code
670 set_paid(struct pa_info_data *paid, krb5_context context,
671 krb5_enctype etype,
672 krb5_salttype salttype, void *salt_string, size_t salt_len,
673 krb5_data *s2kparams)
675 paid->etype = etype;
676 paid->salt.salttype = salttype;
677 paid->salt.saltvalue.data = malloc(salt_len + 1);
678 if (paid->salt.saltvalue.data == NULL) {
679 krb5_clear_error_string(context);
680 return ENOMEM;
682 memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
683 ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
684 paid->salt.saltvalue.length = salt_len;
685 if (s2kparams) {
686 krb5_error_code ret;
688 ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
689 if (ret) {
690 krb5_clear_error_string(context);
691 krb5_free_salt(context, paid->salt);
692 return ret;
694 } else
695 paid->s2kparams = NULL;
697 return 0;
700 static struct pa_info_data *
701 pa_etype_info2(krb5_context context,
702 const krb5_principal client,
703 const AS_REQ *asreq,
704 struct pa_info_data *paid,
705 heim_octet_string *data)
707 krb5_error_code ret;
708 ETYPE_INFO2 e;
709 size_t sz;
710 int i, j;
712 memset(&e, 0, sizeof(e));
713 ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
714 if (ret)
715 goto out;
716 if (e.len == 0)
717 goto out;
718 for (j = 0; j < asreq->req_body.etype.len; j++) {
719 for (i = 0; i < e.len; i++) {
720 if (asreq->req_body.etype.val[j] == e.val[i].etype) {
721 krb5_salt salt;
722 if (e.val[i].salt == NULL)
723 ret = krb5_get_pw_salt(context, client, &salt);
724 else {
725 salt.saltvalue.data = *e.val[i].salt;
726 salt.saltvalue.length = strlen(*e.val[i].salt);
727 ret = 0;
729 if (ret == 0)
730 ret = set_paid(paid, context, e.val[i].etype,
731 KRB5_PW_SALT,
732 salt.saltvalue.data,
733 salt.saltvalue.length,
734 e.val[i].s2kparams);
735 if (e.val[i].salt == NULL)
736 krb5_free_salt(context, salt);
737 if (ret == 0) {
738 free_ETYPE_INFO2(&e);
739 return paid;
744 out:
745 free_ETYPE_INFO2(&e);
746 return NULL;
749 static struct pa_info_data *
750 pa_etype_info(krb5_context context,
751 const krb5_principal client,
752 const AS_REQ *asreq,
753 struct pa_info_data *paid,
754 heim_octet_string *data)
756 krb5_error_code ret;
757 ETYPE_INFO e;
758 size_t sz;
759 int i, j;
761 memset(&e, 0, sizeof(e));
762 ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
763 if (ret)
764 goto out;
765 if (e.len == 0)
766 goto out;
767 for (j = 0; j < asreq->req_body.etype.len; j++) {
768 for (i = 0; i < e.len; i++) {
769 if (asreq->req_body.etype.val[j] == e.val[i].etype) {
770 krb5_salt salt;
771 salt.salttype = KRB5_PW_SALT;
772 if (e.val[i].salt == NULL)
773 ret = krb5_get_pw_salt(context, client, &salt);
774 else {
775 salt.saltvalue = *e.val[i].salt;
776 ret = 0;
778 if (e.val[i].salttype)
779 salt.salttype = *e.val[i].salttype;
780 if (ret == 0) {
781 ret = set_paid(paid, context, e.val[i].etype,
782 salt.salttype,
783 salt.saltvalue.data,
784 salt.saltvalue.length,
785 NULL);
786 if (e.val[i].salt == NULL)
787 krb5_free_salt(context, salt);
789 if (ret == 0) {
790 free_ETYPE_INFO(&e);
791 return paid;
796 out:
797 free_ETYPE_INFO(&e);
798 return NULL;
801 static struct pa_info_data *
802 pa_pw_or_afs3_salt(krb5_context context,
803 const krb5_principal client,
804 const AS_REQ *asreq,
805 struct pa_info_data *paid,
806 heim_octet_string *data)
808 krb5_error_code ret;
809 if (paid->etype == ENCTYPE_NULL)
810 return NULL;
811 ret = set_paid(paid, context,
812 paid->etype,
813 paid->salt.salttype,
814 data->data,
815 data->length,
816 NULL);
817 if (ret)
818 return NULL;
819 return paid;
823 struct pa_info {
824 krb5_preauthtype type;
825 struct pa_info_data *(*salt_info)(krb5_context,
826 const krb5_principal,
827 const AS_REQ *,
828 struct pa_info_data *,
829 heim_octet_string *);
832 static struct pa_info pa_prefs[] = {
833 { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 },
834 { KRB5_PADATA_ETYPE_INFO, pa_etype_info },
835 { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt },
836 { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt }
839 static PA_DATA *
840 find_pa_data(const METHOD_DATA *md, int type)
842 int i;
843 if (md == NULL)
844 return NULL;
845 for (i = 0; i < md->len; i++)
846 if (md->val[i].padata_type == type)
847 return &md->val[i];
848 return NULL;
851 static struct pa_info_data *
852 process_pa_info(krb5_context context,
853 const krb5_principal client,
854 const AS_REQ *asreq,
855 struct pa_info_data *paid,
856 METHOD_DATA *md)
858 struct pa_info_data *p = NULL;
859 int i;
861 for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) {
862 PA_DATA *pa = find_pa_data(md, pa_prefs[i].type);
863 if (pa == NULL)
864 continue;
865 paid->salt.salttype = pa_prefs[i].type;
866 p = (*pa_prefs[i].salt_info)(context, client, asreq,
867 paid, &pa->padata_value);
869 return p;
872 static krb5_error_code
873 make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
874 krb5_enctype etype, krb5_keyblock *key)
876 PA_ENC_TS_ENC p;
877 unsigned char *buf;
878 size_t buf_size;
879 size_t len;
880 EncryptedData encdata;
881 krb5_error_code ret;
882 int32_t usec;
883 int usec2;
884 krb5_crypto crypto;
886 krb5_us_timeofday (context, &p.patimestamp, &usec);
887 usec2 = usec;
888 p.pausec = &usec2;
890 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
891 if (ret)
892 return ret;
893 if(buf_size != len)
894 krb5_abortx(context, "internal error in ASN.1 encoder");
896 ret = krb5_crypto_init(context, key, 0, &crypto);
897 if (ret) {
898 free(buf);
899 return ret;
901 ret = krb5_encrypt_EncryptedData(context,
902 crypto,
903 KRB5_KU_PA_ENC_TIMESTAMP,
904 buf,
905 len,
907 &encdata);
908 free(buf);
909 krb5_crypto_destroy(context, crypto);
910 if (ret)
911 return ret;
913 ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
914 free_EncryptedData(&encdata);
915 if (ret)
916 return ret;
917 if(buf_size != len)
918 krb5_abortx(context, "internal error in ASN.1 encoder");
920 ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
921 if (ret)
922 free(buf);
923 return ret;
926 static krb5_error_code
927 add_enc_ts_padata(krb5_context context,
928 METHOD_DATA *md,
929 krb5_principal client,
930 krb5_s2k_proc key_proc,
931 krb5_const_pointer keyseed,
932 krb5_enctype *enctypes,
933 unsigned netypes,
934 krb5_salt *salt,
935 krb5_data *s2kparams)
937 krb5_error_code ret;
938 krb5_salt salt2;
939 krb5_enctype *ep;
940 int i;
942 if(salt == NULL) {
943 /* default to standard salt */
944 ret = krb5_get_pw_salt (context, client, &salt2);
945 salt = &salt2;
947 if (!enctypes) {
948 enctypes = context->etypes;
949 netypes = 0;
950 for (ep = enctypes; *ep != ETYPE_NULL; ep++)
951 netypes++;
954 for (i = 0; i < netypes; ++i) {
955 krb5_keyblock *key;
957 ret = (*key_proc)(context, enctypes[i], keyseed,
958 *salt, s2kparams, &key);
959 if (ret)
960 continue;
961 ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
962 krb5_free_keyblock (context, key);
963 if (ret)
964 return ret;
966 if(salt == &salt2)
967 krb5_free_salt(context, salt2);
968 return 0;
971 static krb5_error_code
972 pa_data_to_md_ts_enc(krb5_context context,
973 const AS_REQ *a,
974 const krb5_principal client,
975 krb5_get_init_creds_ctx *ctx,
976 struct pa_info_data *ppaid,
977 METHOD_DATA *md)
979 if (ctx->key_proc == NULL || ctx->password == NULL)
980 return 0;
982 if (ppaid) {
983 add_enc_ts_padata(context, md, client,
984 ctx->key_proc, ctx->password,
985 &ppaid->etype, 1,
986 &ppaid->salt, ppaid->s2kparams);
987 } else {
988 krb5_salt salt;
990 /* make a v5 salted pa-data */
991 add_enc_ts_padata(context, md, client,
992 ctx->key_proc, ctx->password,
993 a->req_body.etype.val, a->req_body.etype.len,
994 NULL, NULL);
996 /* make a v4 salted pa-data */
997 salt.salttype = KRB5_PW_SALT;
998 krb5_data_zero(&salt.saltvalue);
999 add_enc_ts_padata(context, md, client,
1000 ctx->key_proc, ctx->password,
1001 a->req_body.etype.val, a->req_body.etype.len,
1002 &salt, NULL);
1004 return 0;
1007 static krb5_error_code
1008 pa_data_to_key_plain(krb5_context context,
1009 const krb5_principal client,
1010 krb5_get_init_creds_ctx *ctx,
1011 krb5_salt salt,
1012 krb5_data *s2kparams,
1013 krb5_enctype etype,
1014 krb5_keyblock **key)
1016 krb5_error_code ret;
1018 ret = (*ctx->key_proc)(context, etype, ctx->password,
1019 salt, s2kparams, key);
1020 return ret;
1024 static krb5_error_code
1025 pa_data_to_md_pkinit(krb5_context context,
1026 const AS_REQ *a,
1027 const krb5_principal client,
1028 krb5_get_init_creds_ctx *ctx,
1029 METHOD_DATA *md)
1031 if (ctx->pk_init_ctx == NULL)
1032 return 0;
1033 #ifdef PKINIT
1034 return _krb5_pk_mk_padata(context,
1035 ctx->pk_init_ctx,
1036 &a->req_body,
1037 ctx->pk_nonce,
1038 md);
1039 #else
1040 krb5_set_error_string(context, "no support for PKINIT compiled in");
1041 return EINVAL;
1042 #endif
1045 static krb5_error_code
1046 pa_data_add_pac_request(krb5_context context,
1047 krb5_get_init_creds_ctx *ctx,
1048 METHOD_DATA *md)
1050 size_t len, length;
1051 krb5_error_code ret;
1052 PA_PAC_REQUEST req;
1053 void *buf;
1055 switch (ctx->req_pac) {
1056 case KRB5_INIT_CREDS_TRISTATE_UNSET:
1057 return 0; /* don't bother */
1058 case KRB5_INIT_CREDS_TRISTATE_TRUE:
1059 req.include_pac = 1;
1060 break;
1061 case KRB5_INIT_CREDS_TRISTATE_FALSE:
1062 req.include_pac = 0;
1065 ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
1066 &req, &len, ret);
1067 if (ret)
1068 return ret;
1069 if(len != length)
1070 krb5_abortx(context, "internal error in ASN.1 encoder");
1072 ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
1073 if (ret)
1074 free(buf);
1076 return 0;
1080 * Assumes caller always will free `out_md', even on error.
1083 static krb5_error_code
1084 process_pa_data_to_md(krb5_context context,
1085 const krb5_creds *creds,
1086 const AS_REQ *a,
1087 krb5_get_init_creds_ctx *ctx,
1088 METHOD_DATA *in_md,
1089 METHOD_DATA **out_md,
1090 krb5_prompter_fct prompter,
1091 void *prompter_data)
1093 krb5_error_code ret;
1095 ALLOC(*out_md, 1);
1096 if (*out_md == NULL) {
1097 krb5_set_error_string(context, "malloc: out of memory");
1098 return ENOMEM;
1100 (*out_md)->len = 0;
1101 (*out_md)->val = NULL;
1104 * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
1105 * need to expose our password protecting our PKCS12 key.
1108 if (ctx->pk_init_ctx) {
1110 ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md);
1111 if (ret)
1112 return ret;
1114 } else if (in_md->len != 0) {
1115 struct pa_info_data paid, *ppaid;
1117 memset(&paid, 0, sizeof(paid));
1119 paid.etype = ENCTYPE_NULL;
1120 ppaid = process_pa_info(context, creds->client, a, &paid, in_md);
1122 pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
1123 if (ppaid)
1124 free_paid(context, ppaid);
1127 pa_data_add_pac_request(context, ctx, *out_md);
1129 if ((*out_md)->len == 0) {
1130 free(*out_md);
1131 *out_md = NULL;
1134 return 0;
1137 static krb5_error_code
1138 process_pa_data_to_key(krb5_context context,
1139 krb5_get_init_creds_ctx *ctx,
1140 krb5_creds *creds,
1141 AS_REQ *a,
1142 krb5_kdc_rep *rep,
1143 const krb5_krbhst_info *hi,
1144 krb5_keyblock **key)
1146 struct pa_info_data paid, *ppaid = NULL;
1147 krb5_error_code ret;
1148 krb5_enctype etype;
1149 PA_DATA *pa;
1151 memset(&paid, 0, sizeof(paid));
1153 etype = rep->kdc_rep.enc_part.etype;
1155 if (rep->kdc_rep.padata) {
1156 paid.etype = etype;
1157 ppaid = process_pa_info(context, creds->client, a, &paid,
1158 rep->kdc_rep.padata);
1160 if (ppaid == NULL) {
1161 ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
1162 if (ret)
1163 return ret;
1164 paid.etype = etype;
1165 paid.s2kparams = NULL;
1168 pa = NULL;
1169 if (rep->kdc_rep.padata) {
1170 int idx = 0;
1171 pa = krb5_find_padata(rep->kdc_rep.padata->val,
1172 rep->kdc_rep.padata->len,
1173 KRB5_PADATA_PK_AS_REP,
1174 &idx);
1175 if (pa == NULL) {
1176 idx = 0;
1177 pa = krb5_find_padata(rep->kdc_rep.padata->val,
1178 rep->kdc_rep.padata->len,
1179 KRB5_PADATA_PK_AS_REP_19,
1180 &idx);
1183 if (pa && ctx->pk_init_ctx) {
1184 #ifdef PKINIT
1185 ret = _krb5_pk_rd_pa_reply(context,
1186 a->req_body.realm,
1187 ctx->pk_init_ctx,
1188 etype,
1190 ctx->pk_nonce,
1191 &ctx->req_buffer,
1193 key);
1194 #else
1195 krb5_set_error_string(context, "no support for PKINIT compiled in");
1196 ret = EINVAL;
1197 #endif
1198 } else if (ctx->password)
1199 ret = pa_data_to_key_plain(context, creds->client, ctx,
1200 paid.salt, paid.s2kparams, etype, key);
1201 else {
1202 krb5_set_error_string(context, "No usable pa data type");
1203 ret = EINVAL;
1206 free_paid(context, &paid);
1207 return ret;
1210 static krb5_error_code
1211 init_cred_loop(krb5_context context,
1212 krb5_get_init_creds_opt *init_cred_opts,
1213 const krb5_prompter_fct prompter,
1214 void *prompter_data,
1215 krb5_get_init_creds_ctx *ctx,
1216 krb5_creds *creds,
1217 krb5_kdc_rep *ret_as_reply)
1219 krb5_error_code ret;
1220 krb5_kdc_rep rep;
1221 METHOD_DATA md;
1222 krb5_data resp;
1223 size_t len;
1224 size_t size;
1225 krb5_krbhst_info *hi = NULL;
1226 krb5_sendto_ctx stctx = NULL;
1229 memset(&md, 0, sizeof(md));
1230 memset(&rep, 0, sizeof(rep));
1232 _krb5_get_init_creds_opt_free_krb5_error(init_cred_opts);
1234 if (ret_as_reply)
1235 memset(ret_as_reply, 0, sizeof(*ret_as_reply));
1237 ret = init_creds_init_as_req(context, ctx->flags, creds,
1238 ctx->addrs, ctx->etypes, &ctx->as_req);
1239 if (ret)
1240 return ret;
1242 ret = krb5_sendto_ctx_alloc(context, &stctx);
1243 if (ret)
1244 goto out;
1245 krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
1247 /* Set a new nonce. */
1248 krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
1249 ctx->nonce &= 0xffffffff;
1250 /* XXX these just needs to be the same when using Windows PK-INIT */
1251 ctx->pk_nonce = ctx->nonce;
1254 * Increase counter when we want other pre-auth types then
1255 * KRB5_PA_ENC_TIMESTAMP.
1257 #define MAX_PA_COUNTER 3
1259 ctx->pa_counter = 0;
1260 while (ctx->pa_counter < MAX_PA_COUNTER) {
1262 ctx->pa_counter++;
1264 if (ctx->as_req.padata) {
1265 free_METHOD_DATA(ctx->as_req.padata);
1266 free(ctx->as_req.padata);
1267 ctx->as_req.padata = NULL;
1270 /* Set a new nonce. */
1271 ctx->as_req.req_body.nonce = ctx->nonce;
1273 /* fill_in_md_data */
1274 ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx,
1275 &md, &ctx->as_req.padata,
1276 prompter, prompter_data);
1277 if (ret)
1278 goto out;
1280 krb5_data_free(&ctx->req_buffer);
1282 ASN1_MALLOC_ENCODE(AS_REQ,
1283 ctx->req_buffer.data, ctx->req_buffer.length,
1284 &ctx->as_req, &len, ret);
1285 if (ret)
1286 goto out;
1287 if(len != ctx->req_buffer.length)
1288 krb5_abortx(context, "internal error in ASN.1 encoder");
1290 ret = krb5_sendto_context (context, stctx, &ctx->req_buffer,
1291 creds->client->realm, &resp);
1292 if (ret)
1293 goto out;
1295 memset (&rep, 0, sizeof(rep));
1296 ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
1297 if (ret == 0) {
1298 krb5_data_free(&resp);
1299 krb5_clear_error_string(context);
1300 break;
1301 } else {
1302 /* let's try to parse it as a KRB-ERROR */
1303 KRB_ERROR error;
1305 ret = krb5_rd_error(context, &resp, &error);
1306 if(ret && resp.data && ((char*)resp.data)[0] == 4)
1307 ret = KRB5KRB_AP_ERR_V4_REPLY;
1308 krb5_data_free(&resp);
1309 if (ret)
1310 goto out;
1312 ret = krb5_error_from_rd_error(context, &error, creds);
1315 * If no preauth was set and KDC requires it, give it one
1316 * more try.
1319 if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
1320 free_METHOD_DATA(&md);
1321 memset(&md, 0, sizeof(md));
1323 if (error.e_data) {
1324 ret = decode_METHOD_DATA(error.e_data->data,
1325 error.e_data->length,
1326 &md,
1327 NULL);
1328 if (ret)
1329 krb5_set_error_string(context,
1330 "failed to decode METHOD DATA");
1331 } else {
1332 /* XXX guess what the server want here add add md */
1334 krb5_free_error_contents(context, &error);
1335 if (ret)
1336 goto out;
1337 } else {
1338 _krb5_get_init_creds_opt_set_krb5_error(context,
1339 init_cred_opts,
1340 &error);
1341 if (ret_as_reply)
1342 rep.error = error;
1343 else
1344 krb5_free_error_contents(context, &error);
1345 goto out;
1351 krb5_keyblock *key = NULL;
1352 unsigned flags = 0;
1354 if (ctx->flags.request_anonymous)
1355 flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1356 if (ctx->flags.canonicalize) {
1357 flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
1358 flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1359 flags |= EXTRACT_TICKET_MATCH_REALM;
1362 ret = process_pa_data_to_key(context, ctx, creds,
1363 &ctx->as_req, &rep, hi, &key);
1364 if (ret)
1365 goto out;
1367 ret = _krb5_extract_ticket(context,
1368 &rep,
1369 creds,
1370 key,
1371 NULL,
1372 KRB5_KU_AS_REP_ENC_PART,
1373 NULL,
1374 ctx->nonce,
1375 flags,
1376 NULL,
1377 NULL);
1378 krb5_free_keyblock(context, key);
1381 * Verify referral data
1383 if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) &&
1384 (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) == 0)
1386 PA_ClientCanonicalized canon;
1387 krb5_crypto crypto;
1388 krb5_data data;
1389 PA_DATA *pa;
1390 size_t len;
1392 pa = find_pa_data(rep.kdc_rep.padata, KRB5_PADATA_CLIENT_CANONICALIZED);
1393 if (pa == NULL) {
1394 ret = EINVAL;
1395 krb5_set_error_string(context, "Client canonicalizion not signed");
1396 goto out;
1399 ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
1400 pa->padata_value.length,
1401 &canon, &len);
1402 if (ret) {
1403 krb5_set_error_string(context, "Failed to decode "
1404 "PA_ClientCanonicalized");
1405 goto out;
1408 ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
1409 &canon.names, &len, ret);
1410 if (ret)
1411 goto out;
1412 if (data.length != len)
1413 krb5_abortx(context, "internal asn.1 error");
1415 ret = krb5_crypto_init(context, &creds->session, 0, &crypto);
1416 if (ret) {
1417 free(data.data);
1418 free_PA_ClientCanonicalized(&canon);
1419 goto out;
1422 ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
1423 data.data, data.length,
1424 &canon.canon_checksum);
1425 krb5_crypto_destroy(context, crypto);
1426 free(data.data);
1427 free_PA_ClientCanonicalized(&canon);
1428 if (ret) {
1429 krb5_set_error_string(context, "Failed to verify "
1430 "client canonicalized data");
1431 goto out;
1434 out:
1435 if (stctx)
1436 krb5_sendto_ctx_free(context, stctx);
1437 krb5_data_free(&ctx->req_buffer);
1438 free_METHOD_DATA(&md);
1439 memset(&md, 0, sizeof(md));
1441 if (ret == 0 && ret_as_reply)
1442 *ret_as_reply = rep;
1443 else
1444 krb5_free_kdc_rep (context, &rep);
1445 return ret;
1448 krb5_error_code KRB5_LIB_FUNCTION
1449 krb5_get_init_creds(krb5_context context,
1450 krb5_creds *creds,
1451 krb5_principal client,
1452 krb5_prompter_fct prompter,
1453 void *data,
1454 krb5_deltat start_time,
1455 const char *in_tkt_service,
1456 krb5_get_init_creds_opt *options)
1458 krb5_get_init_creds_ctx ctx;
1459 krb5_kdc_rep kdc_reply;
1460 krb5_error_code ret;
1461 char buf[BUFSIZ];
1462 int done;
1464 memset(&kdc_reply, 0, sizeof(kdc_reply));
1466 ret = get_init_creds_common(context, client, start_time,
1467 in_tkt_service, options, &ctx);
1468 if (ret)
1469 goto out;
1471 done = 0;
1472 while(!done) {
1473 memset(&kdc_reply, 0, sizeof(kdc_reply));
1475 ret = init_cred_loop(context,
1476 options,
1477 prompter,
1478 data,
1479 &ctx,
1480 &ctx.cred,
1481 &kdc_reply);
1483 switch (ret) {
1484 case 0 :
1485 done = 1;
1486 break;
1487 case KRB5KDC_ERR_KEY_EXPIRED :
1488 /* try to avoid recursion */
1490 /* don't try to change password where then where none */
1491 if (prompter == NULL || ctx.password == NULL)
1492 goto out;
1494 krb5_clear_error_string (context);
1496 if (ctx.in_tkt_service != NULL
1497 && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0)
1498 goto out;
1500 ret = change_password (context,
1501 client,
1502 ctx.password,
1503 buf,
1504 sizeof(buf),
1505 prompter,
1506 data,
1507 options);
1508 if (ret)
1509 goto out;
1510 ctx.password = buf;
1511 break;
1512 default:
1513 goto out;
1517 if (prompter)
1518 print_expire (context,
1519 krb5_principal_get_realm (context, ctx.cred.client),
1520 &kdc_reply,
1521 prompter,
1522 data);
1524 out:
1525 memset (buf, 0, sizeof(buf));
1526 free_init_creds_ctx(context, &ctx);
1527 krb5_free_kdc_rep (context, &kdc_reply);
1528 if (ret == 0)
1529 *creds = ctx.cred;
1530 else
1531 krb5_free_cred_contents (context, &ctx.cred);
1533 return ret;
1536 krb5_error_code KRB5_LIB_FUNCTION
1537 krb5_get_init_creds_password(krb5_context context,
1538 krb5_creds *creds,
1539 krb5_principal client,
1540 const char *password,
1541 krb5_prompter_fct prompter,
1542 void *data,
1543 krb5_deltat start_time,
1544 const char *in_tkt_service,
1545 krb5_get_init_creds_opt *in_options)
1547 krb5_get_init_creds_opt *options;
1548 char buf[BUFSIZ];
1549 krb5_error_code ret;
1551 if (in_options == NULL) {
1552 const char *realm = krb5_principal_get_realm(context, client);
1553 ret = krb5_get_init_creds_opt_alloc(context, &options);
1554 if (ret == 0)
1555 krb5_get_init_creds_opt_set_default_flags(context,
1556 NULL,
1557 realm,
1558 options);
1559 } else
1560 ret = _krb5_get_init_creds_opt_copy(context, in_options, &options);
1561 if (ret)
1562 return ret;
1564 if (password == NULL &&
1565 options->opt_private->password == NULL &&
1566 options->opt_private->pk_init_ctx == NULL)
1568 krb5_prompt prompt;
1569 krb5_data password_data;
1570 char *p, *q;
1572 krb5_unparse_name (context, client, &p);
1573 asprintf (&q, "%s's Password: ", p);
1574 free (p);
1575 prompt.prompt = q;
1576 password_data.data = buf;
1577 password_data.length = sizeof(buf);
1578 prompt.hidden = 1;
1579 prompt.reply = &password_data;
1580 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1582 ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
1583 free (q);
1584 if (ret) {
1585 memset (buf, 0, sizeof(buf));
1586 krb5_get_init_creds_opt_free(context, options);
1587 ret = KRB5_LIBOS_PWDINTR;
1588 krb5_clear_error_string (context);
1589 return ret;
1591 password = password_data.data;
1594 if (options->opt_private->password == NULL) {
1595 ret = krb5_get_init_creds_opt_set_pa_password(context, options,
1596 password, NULL);
1597 if (ret) {
1598 krb5_get_init_creds_opt_free(context, options);
1599 memset(buf, 0, sizeof(buf));
1600 return ret;
1604 ret = krb5_get_init_creds(context, creds, client, prompter,
1605 data, start_time, in_tkt_service, options);
1606 krb5_get_init_creds_opt_free(context, options);
1607 memset(buf, 0, sizeof(buf));
1608 return ret;
1611 static krb5_error_code
1612 init_creds_keyblock_key_proc (krb5_context context,
1613 krb5_enctype type,
1614 krb5_salt salt,
1615 krb5_const_pointer keyseed,
1616 krb5_keyblock **key)
1618 return krb5_copy_keyblock (context, keyseed, key);
1621 krb5_error_code KRB5_LIB_FUNCTION
1622 krb5_get_init_creds_keyblock(krb5_context context,
1623 krb5_creds *creds,
1624 krb5_principal client,
1625 krb5_keyblock *keyblock,
1626 krb5_deltat start_time,
1627 const char *in_tkt_service,
1628 krb5_get_init_creds_opt *options)
1630 struct krb5_get_init_creds_ctx ctx;
1631 krb5_error_code ret;
1633 ret = get_init_creds_common(context, client, start_time,
1634 in_tkt_service, options, &ctx);
1635 if (ret)
1636 goto out;
1638 ret = krb5_get_in_cred (context,
1639 KDCOptions2int(ctx.flags),
1640 ctx.addrs,
1641 ctx.etypes,
1642 ctx.pre_auth_types,
1643 NULL,
1644 init_creds_keyblock_key_proc,
1645 keyblock,
1646 NULL,
1647 NULL,
1648 &ctx.cred,
1649 NULL);
1651 if (ret == 0 && creds)
1652 *creds = ctx.cred;
1653 else
1654 krb5_free_cred_contents (context, &ctx.cred);
1656 out:
1657 free_init_creds_ctx(context, &ctx);
1658 return ret;