2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 #include "krb5_locl.h"
36 RCSID("$Id: init_creds_pw.c,v 1.101 2006/10/02 12:00:59 lha Exp $");
38 typedef struct krb5_get_init_creds_ctx {
41 krb5_addresses *addrs;
43 krb5_preauthtype *pre_auth_types;
44 const char *in_tkt_service;
53 krb5_s2k_proc key_proc;
55 krb5_get_init_creds_tristate req_pac;
57 krb5_pk_init_ctx pk_init_ctx;
58 } krb5_get_init_creds_ctx;
60 static krb5_error_code
61 default_s2k_func(krb5_context context, krb5_enctype type,
62 krb5_const_pointer keyseed,
63 krb5_salt salt, krb5_data *s2kparms,
70 password.data = rk_UNCONST(keyseed);
71 password.length = strlen(keyseed);
75 krb5_data_zero(&opaque);
77 *key = malloc(sizeof(**key));
80 ret = krb5_string_to_key_data_salt_opaque(context, type, password,
90 free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx)
94 if (ctx->pre_auth_types)
95 free (ctx->pre_auth_types);
96 free_AS_REQ(&ctx->as_req);
97 memset(&ctx->as_req, 0, sizeof(ctx->as_req));
101 get_config_time (krb5_context context,
108 ret = krb5_config_get_time (context, NULL,
115 ret = krb5_config_get_time (context, NULL,
124 static krb5_error_code
125 init_cred (krb5_context context,
127 krb5_principal client,
128 krb5_deltat start_time,
129 const char *in_tkt_service,
130 krb5_get_init_creds_opt *options)
133 krb5_const_realm client_realm;
137 krb5_timeofday (context, &now);
139 memset (cred, 0, sizeof(*cred));
142 krb5_copy_principal(context, client, &cred->client);
144 ret = krb5_get_default_principal (context,
150 client_realm = krb5_principal_get_realm (context, cred->client);
153 cred->times.starttime = now + start_time;
155 if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
156 tmp = options->tkt_life;
159 cred->times.endtime = now + tmp;
161 if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) &&
162 options->renew_life > 0) {
163 cred->times.renew_till = now + options->renew_life;
166 if (in_tkt_service) {
167 krb5_realm server_realm;
169 ret = krb5_parse_name (context, in_tkt_service, &cred->server);
172 server_realm = strdup (client_realm);
173 free (*krb5_princ_realm(context, cred->server));
174 krb5_princ_set_realm (context, cred->server, &server_realm);
176 ret = krb5_make_principal(context, &cred->server,
177 client_realm, KRB5_TGS_NAME, client_realm,
185 krb5_free_cred_contents (context, cred);
190 * Print a message (str) to the user about the expiration in `lr'
194 report_expiration (krb5_context context,
195 krb5_prompter_fct prompter,
202 asprintf (&p, "%s%s", str, ctime(&now));
203 (*prompter) (context, data, NULL, p, 0, NULL);
208 * Parse the last_req data and show it to the user if it's interesting
212 print_expire (krb5_context context,
213 krb5_const_realm realm,
215 krb5_prompter_fct prompter,
219 LastReq *lr = &rep->enc_part.last_req;
222 krb5_boolean reported = FALSE;
224 krb5_timeofday (context, &sec);
226 t = sec + get_config_time (context,
231 for (i = 0; i < lr->len; ++i) {
232 if (lr->val[i].lr_value <= t) {
233 switch (abs(lr->val[i].lr_type)) {
235 report_expiration(context, prompter, data,
236 "Your password will expire at ",
237 lr->val[i].lr_value);
240 case LR_ACCT_EXPTIME :
241 report_expiration(context, prompter, data,
242 "Your account will expire at ",
243 lr->val[i].lr_value);
251 && rep->enc_part.key_expiration
252 && *rep->enc_part.key_expiration <= t) {
253 report_expiration(context, prompter, data,
254 "Your password/account will expire at ",
255 *rep->enc_part.key_expiration);
259 static krb5_addresses no_addrs = { 0, NULL };
261 static krb5_error_code
262 get_init_creds_common(krb5_context context,
263 krb5_principal client,
264 krb5_deltat start_time,
265 const char *in_tkt_service,
266 krb5_get_init_creds_opt *options,
267 krb5_get_init_creds_ctx *ctx)
269 krb5_get_init_creds_opt default_opt;
271 krb5_enctype *etypes;
272 krb5_preauthtype *pre_auth_types;
274 memset(ctx, 0, sizeof(*ctx));
276 if (options == NULL) {
277 krb5_get_init_creds_opt_init (&default_opt);
278 options = &default_opt;
280 _krb5_get_init_creds_opt_free_krb5_error(options);
283 if (options->opt_private) {
284 ctx->password = options->opt_private->password;
285 ctx->key_proc = options->opt_private->key_proc;
286 ctx->req_pac = options->opt_private->req_pac;
287 ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
289 ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
291 if (ctx->key_proc == NULL)
292 ctx->key_proc = default_s2k_func;
294 ctx->pre_auth_types = NULL;
297 ctx->pre_auth_types = NULL;
298 ctx->in_tkt_service = in_tkt_service;
300 ret = init_cred (context, &ctx->cred, client, start_time,
301 in_tkt_service, options);
305 if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
306 ctx->flags.forwardable = options->forwardable;
308 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
309 ctx->flags.proxiable = options->proxiable;
312 ctx->flags.postdated = 1;
313 if (ctx->cred.times.renew_till)
314 ctx->flags.renewable = 1;
315 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
316 ctx->addrs = options->address_list;
317 } else if (options->opt_private) {
318 switch (options->opt_private->addressless) {
319 case KRB5_INIT_CREDS_TRISTATE_UNSET:
320 #if KRB5_ADDRESSLESS_DEFAULT == TRUE
321 ctx->addrs = &no_addrs;
326 case KRB5_INIT_CREDS_TRISTATE_FALSE:
329 case KRB5_INIT_CREDS_TRISTATE_TRUE:
330 ctx->addrs = &no_addrs;
334 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
335 etypes = malloc((options->etype_list_length + 1)
336 * sizeof(krb5_enctype));
337 if (etypes == NULL) {
338 krb5_set_error_string(context, "malloc: out of memory");
341 memcpy (etypes, options->etype_list,
342 options->etype_list_length * sizeof(krb5_enctype));
343 etypes[options->etype_list_length] = ETYPE_NULL;
344 ctx->etypes = etypes;
346 if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
347 pre_auth_types = malloc((options->preauth_list_length + 1)
348 * sizeof(krb5_preauthtype));
349 if (pre_auth_types == NULL) {
350 krb5_set_error_string(context, "malloc: out of memory");
353 memcpy (pre_auth_types, options->preauth_list,
354 options->preauth_list_length * sizeof(krb5_preauthtype));
355 pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
356 ctx->pre_auth_types = pre_auth_types;
358 if (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)
360 if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
361 ctx->flags.request_anonymous = options->anonymous;
365 static krb5_error_code
366 change_password (krb5_context context,
367 krb5_principal client,
368 const char *password,
371 krb5_prompter_fct prompter,
373 krb5_get_init_creds_opt *old_options)
375 krb5_prompt prompts[2];
378 char buf1[BUFSIZ], buf2[BUFSIZ];
379 krb5_data password_data[2];
381 krb5_data result_code_string;
382 krb5_data result_string;
384 krb5_get_init_creds_opt options;
386 memset (&cpw_cred, 0, sizeof(cpw_cred));
388 krb5_get_init_creds_opt_init (&options);
389 krb5_get_init_creds_opt_set_tkt_life (&options, 60);
390 krb5_get_init_creds_opt_set_forwardable (&options, FALSE);
391 krb5_get_init_creds_opt_set_proxiable (&options, FALSE);
392 if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
393 krb5_get_init_creds_opt_set_preauth_list (&options,
394 old_options->preauth_list,
395 old_options->preauth_list_length);
397 krb5_data_zero (&result_code_string);
398 krb5_data_zero (&result_string);
400 ret = krb5_get_init_creds_password (context,
413 password_data[0].data = buf1;
414 password_data[0].length = sizeof(buf1);
416 prompts[0].hidden = 1;
417 prompts[0].prompt = "New password: ";
418 prompts[0].reply = &password_data[0];
419 prompts[0].type = KRB5_PROMPT_TYPE_NEW_PASSWORD;
421 password_data[1].data = buf2;
422 password_data[1].length = sizeof(buf2);
424 prompts[1].hidden = 1;
425 prompts[1].prompt = "Repeat new password: ";
426 prompts[1].reply = &password_data[1];
427 prompts[1].type = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
429 ret = (*prompter) (context, data, NULL, "Changing password",
432 memset (buf1, 0, sizeof(buf1));
433 memset (buf2, 0, sizeof(buf2));
437 if (strcmp (buf1, buf2) == 0)
439 memset (buf1, 0, sizeof(buf1));
440 memset (buf2, 0, sizeof(buf2));
443 ret = krb5_change_password (context,
451 asprintf (&p, "%s: %.*s\n",
452 result_code ? "Error" : "Success",
453 (int)result_string.length,
454 result_string.length > 0 ? (char*)result_string.data : "");
456 ret = (*prompter) (context, data, NULL, p, 0, NULL);
458 if (result_code == 0) {
459 strlcpy (newpw, buf1, newpw_sz);
462 krb5_set_error_string (context, "failed changing password");
467 memset (buf1, 0, sizeof(buf1));
468 memset (buf2, 0, sizeof(buf2));
469 krb5_data_free (&result_string);
470 krb5_data_free (&result_code_string);
471 krb5_free_cred_contents (context, &cpw_cred);
475 krb5_error_code KRB5_LIB_FUNCTION
476 krb5_keyblock_key_proc (krb5_context context,
479 krb5_const_pointer keyseed,
482 return krb5_copy_keyblock (context, keyseed, key);
485 krb5_error_code KRB5_LIB_FUNCTION
486 krb5_get_init_creds_keytab(krb5_context context,
488 krb5_principal client,
490 krb5_deltat start_time,
491 const char *in_tkt_service,
492 krb5_get_init_creds_opt *options)
494 krb5_get_init_creds_ctx ctx;
496 krb5_keytab_key_proc_args *a;
498 ret = get_init_creds_common(context, client, start_time,
499 in_tkt_service, options, &ctx);
503 a = malloc (sizeof(*a));
505 krb5_set_error_string(context, "malloc: out of memory");
509 a->principal = ctx.cred.client;
512 ret = krb5_get_in_cred (context,
513 KDCOptions2int(ctx.flags),
518 krb5_keytab_key_proc,
526 if (ret == 0 && creds)
529 krb5_free_cred_contents (context, &ctx.cred);
532 free_init_creds_ctx(context, &ctx);
540 static krb5_error_code
541 init_creds_init_as_req (krb5_context context,
543 const krb5_creds *creds,
544 const krb5_addresses *addrs,
545 const krb5_enctype *etypes,
550 memset(a, 0, sizeof(*a));
553 a->msg_type = krb_as_req;
554 a->req_body.kdc_options = opts;
555 a->req_body.cname = malloc(sizeof(*a->req_body.cname));
556 if (a->req_body.cname == NULL) {
558 krb5_set_error_string(context, "malloc: out of memory");
561 a->req_body.sname = malloc(sizeof(*a->req_body.sname));
562 if (a->req_body.sname == NULL) {
564 krb5_set_error_string(context, "malloc: out of memory");
568 ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
571 ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
575 ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
579 if(creds->times.starttime) {
580 a->req_body.from = malloc(sizeof(*a->req_body.from));
581 if (a->req_body.from == NULL) {
583 krb5_set_error_string(context, "malloc: out of memory");
586 *a->req_body.from = creds->times.starttime;
588 if(creds->times.endtime){
589 ALLOC(a->req_body.till, 1);
590 *a->req_body.till = creds->times.endtime;
592 if(creds->times.renew_till){
593 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
594 if (a->req_body.rtime == NULL) {
596 krb5_set_error_string(context, "malloc: out of memory");
599 *a->req_body.rtime = creds->times.renew_till;
601 a->req_body.nonce = 0;
602 ret = krb5_init_etype (context,
603 &a->req_body.etype.len,
604 &a->req_body.etype.val,
610 * This means no addresses
613 if (addrs && addrs->len == 0) {
614 a->req_body.addresses = NULL;
616 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
617 if (a->req_body.addresses == NULL) {
619 krb5_set_error_string(context, "malloc: out of memory");
624 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
626 ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
627 if(ret == 0 && a->req_body.addresses->len == 0) {
628 free(a->req_body.addresses);
629 a->req_body.addresses = NULL;
636 a->req_body.enc_authorization_data = NULL;
637 a->req_body.additional_tickets = NULL;
644 memset(a, 0, sizeof(*a));
648 struct pa_info_data {
651 krb5_data *s2kparams;
655 free_paid(krb5_context context, struct pa_info_data *ppaid)
657 krb5_free_salt(context, ppaid->salt);
658 if (ppaid->s2kparams)
659 krb5_data_free(ppaid->s2kparams);
663 static krb5_error_code
664 set_paid(struct pa_info_data *paid, krb5_context context,
666 krb5_salttype salttype, void *salt_string, size_t salt_len,
667 krb5_data *s2kparams)
670 paid->salt.salttype = salttype;
671 paid->salt.saltvalue.data = malloc(salt_len + 1);
672 if (paid->salt.saltvalue.data == NULL) {
673 krb5_clear_error_string(context);
676 memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
677 ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
678 paid->salt.saltvalue.length = salt_len;
682 ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
684 krb5_clear_error_string(context);
685 krb5_free_salt(context, paid->salt);
689 paid->s2kparams = NULL;
694 static struct pa_info_data *
695 pa_etype_info2(krb5_context context,
696 const krb5_principal client,
698 struct pa_info_data *paid,
699 heim_octet_string *data)
706 memset(&e, 0, sizeof(e));
707 ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
712 for (j = 0; j < asreq->req_body.etype.len; j++) {
713 for (i = 0; i < e.len; i++) {
714 if (asreq->req_body.etype.val[j] == e.val[i].etype) {
716 if (e.val[i].salt == NULL)
717 ret = krb5_get_pw_salt(context, client, &salt);
719 salt.saltvalue.data = *e.val[i].salt;
720 salt.saltvalue.length = strlen(*e.val[i].salt);
724 ret = set_paid(paid, context, e.val[i].etype,
727 salt.saltvalue.length,
729 if (e.val[i].salt == NULL)
730 krb5_free_salt(context, salt);
732 free_ETYPE_INFO2(&e);
739 free_ETYPE_INFO2(&e);
743 static struct pa_info_data *
744 pa_etype_info(krb5_context context,
745 const krb5_principal client,
747 struct pa_info_data *paid,
748 heim_octet_string *data)
755 memset(&e, 0, sizeof(e));
756 ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
761 for (j = 0; j < asreq->req_body.etype.len; j++) {
762 for (i = 0; i < e.len; i++) {
763 if (asreq->req_body.etype.val[j] == e.val[i].etype) {
765 salt.salttype = KRB5_PW_SALT;
766 if (e.val[i].salt == NULL)
767 ret = krb5_get_pw_salt(context, client, &salt);
769 salt.saltvalue = *e.val[i].salt;
772 if (e.val[i].salttype)
773 salt.salttype = *e.val[i].salttype;
775 ret = set_paid(paid, context, e.val[i].etype,
778 salt.saltvalue.length,
780 if (e.val[i].salt == NULL)
781 krb5_free_salt(context, salt);
795 static struct pa_info_data *
796 pa_pw_or_afs3_salt(krb5_context context,
797 const krb5_principal client,
799 struct pa_info_data *paid,
800 heim_octet_string *data)
803 if (paid->etype == ENCTYPE_NULL)
805 ret = set_paid(paid, context,
818 krb5_preauthtype type;
819 struct pa_info_data *(*salt_info)(krb5_context,
820 const krb5_principal,
822 struct pa_info_data *,
823 heim_octet_string *);
826 static struct pa_info pa_prefs[] = {
827 { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 },
828 { KRB5_PADATA_ETYPE_INFO, pa_etype_info },
829 { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt },
830 { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt }
834 find_pa_data(const METHOD_DATA *md, int type)
837 for (i = 0; i < md->len; i++)
838 if (md->val[i].padata_type == type)
843 static struct pa_info_data *
844 process_pa_info(krb5_context context,
845 const krb5_principal client,
847 struct pa_info_data *paid,
850 struct pa_info_data *p = NULL;
853 for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) {
854 PA_DATA *pa = find_pa_data(md, pa_prefs[i].type);
857 paid->salt.salttype = pa_prefs[i].type;
858 p = (*pa_prefs[i].salt_info)(context, client, asreq,
859 paid, &pa->padata_value);
864 static krb5_error_code
865 make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
866 krb5_enctype etype, krb5_keyblock *key)
872 EncryptedData encdata;
878 krb5_us_timeofday (context, &p.patimestamp, &usec);
882 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
886 krb5_abortx(context, "internal error in ASN.1 encoder");
888 ret = krb5_crypto_init(context, key, 0, &crypto);
893 ret = krb5_encrypt_EncryptedData(context,
895 KRB5_KU_PA_ENC_TIMESTAMP,
901 krb5_crypto_destroy(context, crypto);
905 ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
906 free_EncryptedData(&encdata);
910 krb5_abortx(context, "internal error in ASN.1 encoder");
912 ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
918 static krb5_error_code
919 add_enc_ts_padata(krb5_context context,
921 krb5_principal client,
922 krb5_s2k_proc key_proc,
923 krb5_const_pointer keyseed,
924 krb5_enctype *enctypes,
927 krb5_data *s2kparams)
935 /* default to standard salt */
936 ret = krb5_get_pw_salt (context, client, &salt2);
940 enctypes = context->etypes;
942 for (ep = enctypes; *ep != ETYPE_NULL; ep++)
946 for (i = 0; i < netypes; ++i) {
949 ret = (*key_proc)(context, enctypes[i], keyseed,
950 *salt, s2kparams, &key);
953 ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
954 krb5_free_keyblock (context, key);
959 krb5_free_salt(context, salt2);
963 static krb5_error_code
964 pa_data_to_md_ts_enc(krb5_context context,
966 const krb5_principal client,
967 krb5_get_init_creds_ctx *ctx,
968 struct pa_info_data *ppaid,
971 if (ctx->key_proc == NULL || ctx->password == NULL)
975 add_enc_ts_padata(context, md, client,
976 ctx->key_proc, ctx->password,
978 &ppaid->salt, ppaid->s2kparams);
982 /* make a v5 salted pa-data */
983 add_enc_ts_padata(context, md, client,
984 ctx->key_proc, ctx->password,
985 a->req_body.etype.val, a->req_body.etype.len,
988 /* make a v4 salted pa-data */
989 salt.salttype = KRB5_PW_SALT;
990 krb5_data_zero(&salt.saltvalue);
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,
999 static krb5_error_code
1000 pa_data_to_key_plain(krb5_context context,
1001 const krb5_principal client,
1002 krb5_get_init_creds_ctx *ctx,
1004 krb5_data *s2kparams,
1006 krb5_keyblock **key)
1008 krb5_error_code ret;
1010 ret = (*ctx->key_proc)(context, etype, ctx->password,
1011 salt, s2kparams, key);
1016 static krb5_error_code
1017 pa_data_to_md_pkinit(krb5_context context,
1019 const krb5_principal client,
1020 krb5_get_init_creds_ctx *ctx,
1023 if (ctx->pk_init_ctx == NULL)
1026 return _krb5_pk_mk_padata(context,
1032 krb5_set_error_string(context, "no support for PKINIT compiled in");
1037 static krb5_error_code
1038 pa_data_add_pac_request(krb5_context context,
1039 krb5_get_init_creds_ctx *ctx,
1043 krb5_error_code ret;
1047 switch (ctx->req_pac) {
1048 case KRB5_INIT_CREDS_TRISTATE_UNSET:
1049 return 0; /* don't bother */
1050 case KRB5_INIT_CREDS_TRISTATE_TRUE:
1051 req.include_pac = 1;
1053 case KRB5_INIT_CREDS_TRISTATE_FALSE:
1054 req.include_pac = 0;
1057 ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
1062 krb5_abortx(context, "internal error in ASN.1 encoder");
1064 ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
1072 * Assumes caller always will free `out_md', even on error.
1075 static krb5_error_code
1076 process_pa_data_to_md(krb5_context context,
1077 const krb5_creds *creds,
1079 krb5_get_init_creds_ctx *ctx,
1081 METHOD_DATA **out_md,
1082 krb5_prompter_fct prompter,
1083 void *prompter_data)
1085 krb5_error_code ret;
1088 if (*out_md == NULL) {
1089 krb5_set_error_string(context, "malloc: out of memory");
1093 (*out_md)->val = NULL;
1095 if (in_md->len != 0) {
1096 struct pa_info_data paid, *ppaid;
1098 memset(&paid, 0, sizeof(paid));
1100 paid.etype = ENCTYPE_NULL;
1101 ppaid = process_pa_info(context, creds->client, a, &paid, in_md);
1103 pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
1105 free_paid(context, ppaid);
1108 pa_data_add_pac_request(context, ctx, *out_md);
1109 ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md);
1113 if ((*out_md)->len == 0) {
1121 static krb5_error_code
1122 process_pa_data_to_key(krb5_context context,
1123 krb5_get_init_creds_ctx *ctx,
1127 const krb5_krbhst_info *hi,
1128 krb5_keyblock **key)
1130 struct pa_info_data paid, *ppaid = NULL;
1131 krb5_error_code ret;
1135 memset(&paid, 0, sizeof(paid));
1137 etype = rep->kdc_rep.enc_part.etype;
1139 if (rep->kdc_rep.padata) {
1141 ppaid = process_pa_info(context, creds->client, a, &paid,
1142 rep->kdc_rep.padata);
1144 if (ppaid == NULL) {
1145 ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
1149 paid.s2kparams = NULL;
1153 if (rep->kdc_rep.padata) {
1155 pa = krb5_find_padata(rep->kdc_rep.padata->val,
1156 rep->kdc_rep.padata->len,
1157 KRB5_PADATA_PK_AS_REP,
1161 pa = krb5_find_padata(rep->kdc_rep.padata->val,
1162 rep->kdc_rep.padata->len,
1163 KRB5_PADATA_PK_AS_REP_19,
1167 if (pa && ctx->pk_init_ctx) {
1169 ret = _krb5_pk_rd_pa_reply(context,
1179 krb5_set_error_string(context, "no support for PKINIT compiled in");
1182 } else if (ctx->password)
1183 ret = pa_data_to_key_plain(context, creds->client, ctx,
1184 paid.salt, paid.s2kparams, etype, key);
1186 krb5_set_error_string(context, "No usable pa data type");
1190 free_paid(context, &paid);
1194 static krb5_error_code
1195 init_cred_loop(krb5_context context,
1196 krb5_get_init_creds_opt *init_cred_opts,
1197 const krb5_prompter_fct prompter,
1198 void *prompter_data,
1199 krb5_get_init_creds_ctx *ctx,
1201 krb5_kdc_rep *ret_as_reply)
1203 krb5_error_code ret;
1209 int send_to_kdc_flags = 0;
1210 krb5_krbhst_info *hi = NULL;
1213 memset(&md, 0, sizeof(md));
1214 memset(&rep, 0, sizeof(rep));
1216 _krb5_get_init_creds_opt_free_krb5_error(init_cred_opts);
1219 memset(ret_as_reply, 0, sizeof(*ret_as_reply));
1221 ret = init_creds_init_as_req(context, ctx->flags, creds,
1222 ctx->addrs, ctx->etypes, &ctx->as_req);
1226 /* Set a new nonce. */
1227 krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
1228 ctx->nonce &= 0xffffffff;
1229 /* XXX these just needs to be the same when using Windows PK-INIT */
1230 ctx->pk_nonce = ctx->nonce;
1233 * Increase counter when we want other pre-auth types then
1234 * KRB5_PA_ENC_TIMESTAMP.
1236 #define MAX_PA_COUNTER 3
1238 ctx->pa_counter = 0;
1239 while (ctx->pa_counter < MAX_PA_COUNTER) {
1243 if (ctx->as_req.padata) {
1244 free_METHOD_DATA(ctx->as_req.padata);
1245 free(ctx->as_req.padata);
1246 ctx->as_req.padata = NULL;
1249 /* Set a new nonce. */
1250 ctx->as_req.req_body.nonce = ctx->nonce;
1252 /* fill_in_md_data */
1253 ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx,
1254 &md, &ctx->as_req.padata,
1255 prompter, prompter_data);
1259 krb5_data_free(&ctx->req_buffer);
1261 ASN1_MALLOC_ENCODE(AS_REQ,
1262 ctx->req_buffer.data, ctx->req_buffer.length,
1263 &ctx->as_req, &len, ret);
1266 if(len != ctx->req_buffer.length)
1267 krb5_abortx(context, "internal error in ASN.1 encoder");
1269 ret = krb5_sendto_kdc_flags (context, &ctx->req_buffer,
1270 &creds->client->realm, &resp,
1275 memset (&rep, 0, sizeof(rep));
1276 ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
1278 krb5_data_free(&resp);
1279 krb5_clear_error_string(context);
1282 /* let's try to parse it as a KRB-ERROR */
1285 ret = krb5_rd_error(context, &resp, &error);
1286 if(ret && resp.data && ((char*)resp.data)[0] == 4)
1287 ret = KRB5KRB_AP_ERR_V4_REPLY;
1288 krb5_data_free(&resp);
1292 ret = krb5_error_from_rd_error(context, &error, creds);
1295 * If no preauth was set and KDC requires it, give it one
1299 if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
1300 free_METHOD_DATA(&md);
1301 memset(&md, 0, sizeof(md));
1304 ret = decode_METHOD_DATA(error.e_data->data,
1305 error.e_data->length,
1309 krb5_set_error_string(context,
1310 "failed to decode METHOD DATA");
1312 /* XXX guess what the server want here add add md */
1314 krb5_free_error_contents(context, &error);
1317 } else if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
1318 if (send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG) {
1322 krb5_free_error_contents(context, &error);
1325 krb5_free_error_contents(context, &error);
1326 send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG;
1328 _krb5_get_init_creds_opt_set_krb5_error(context,
1334 krb5_free_error_contents(context, &error);
1341 krb5_keyblock *key = NULL;
1343 ret = process_pa_data_to_key(context, ctx, creds,
1344 &ctx->as_req, &rep, hi, &key);
1348 ret = _krb5_extract_ticket(context,
1353 KRB5_KU_AS_REP_ENC_PART,
1357 ctx->flags.request_anonymous,
1360 krb5_free_keyblock(context, key);
1363 krb5_data_free(&ctx->req_buffer);
1364 free_METHOD_DATA(&md);
1365 memset(&md, 0, sizeof(md));
1367 if (ret == 0 && ret_as_reply)
1368 *ret_as_reply = rep;
1370 krb5_free_kdc_rep (context, &rep);
1374 krb5_error_code KRB5_LIB_FUNCTION
1375 krb5_get_init_creds(krb5_context context,
1377 krb5_principal client,
1378 krb5_prompter_fct prompter,
1380 krb5_deltat start_time,
1381 const char *in_tkt_service,
1382 krb5_get_init_creds_opt *options)
1384 krb5_get_init_creds_ctx ctx;
1385 krb5_kdc_rep kdc_reply;
1386 krb5_error_code ret;
1390 memset(&kdc_reply, 0, sizeof(kdc_reply));
1392 ret = get_init_creds_common(context, client, start_time,
1393 in_tkt_service, options, &ctx);
1399 memset(&kdc_reply, 0, sizeof(kdc_reply));
1401 ret = init_cred_loop(context,
1413 case KRB5KDC_ERR_KEY_EXPIRED :
1414 /* try to avoid recursion */
1416 /* don't try to change password where then where none */
1417 if (prompter == NULL || ctx.password == NULL)
1420 krb5_clear_error_string (context);
1422 if (ctx.in_tkt_service != NULL
1423 && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0)
1426 ret = change_password (context,
1444 print_expire (context,
1445 krb5_principal_get_realm (context, ctx.cred.client),
1451 memset (buf, 0, sizeof(buf));
1452 free_init_creds_ctx(context, &ctx);
1453 krb5_free_kdc_rep (context, &kdc_reply);
1457 krb5_free_cred_contents (context, &ctx.cred);
1462 krb5_error_code KRB5_LIB_FUNCTION
1463 krb5_get_init_creds_password(krb5_context context,
1465 krb5_principal client,
1466 const char *password,
1467 krb5_prompter_fct prompter,
1469 krb5_deltat start_time,
1470 const char *in_tkt_service,
1471 krb5_get_init_creds_opt *in_options)
1473 krb5_get_init_creds_opt *options;
1475 krb5_error_code ret;
1477 if (in_options == NULL)
1478 ret = krb5_get_init_creds_opt_alloc(context, &options);
1480 ret = _krb5_get_init_creds_opt_copy(context, in_options, &options);
1484 if (password == NULL &&
1485 options->opt_private->password == NULL &&
1486 options->opt_private->pk_init_ctx == NULL)
1489 krb5_data password_data;
1492 krb5_unparse_name (context, client, &p);
1493 asprintf (&q, "%s's Password: ", p);
1496 password_data.data = buf;
1497 password_data.length = sizeof(buf);
1499 prompt.reply = &password_data;
1500 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1502 ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
1505 memset (buf, 0, sizeof(buf));
1506 krb5_get_init_creds_opt_free(options);
1507 ret = KRB5_LIBOS_PWDINTR;
1508 krb5_clear_error_string (context);
1511 password = password_data.data;
1514 if (options->opt_private->password == NULL) {
1515 ret = krb5_get_init_creds_opt_set_pa_password(context, options,
1518 krb5_get_init_creds_opt_free(options);
1519 memset(buf, 0, sizeof(buf));
1524 ret = krb5_get_init_creds(context, creds, client, prompter,
1525 data, start_time, in_tkt_service, options);
1526 krb5_get_init_creds_opt_free(options);
1527 memset(buf, 0, sizeof(buf));
1531 static krb5_error_code
1532 init_creds_keyblock_key_proc (krb5_context context,
1535 krb5_const_pointer keyseed,
1536 krb5_keyblock **key)
1538 return krb5_copy_keyblock (context, keyseed, key);
1541 krb5_error_code KRB5_LIB_FUNCTION
1542 krb5_get_init_creds_keyblock(krb5_context context,
1544 krb5_principal client,
1545 krb5_keyblock *keyblock,
1546 krb5_deltat start_time,
1547 const char *in_tkt_service,
1548 krb5_get_init_creds_opt *options)
1550 struct krb5_get_init_creds_ctx ctx;
1551 krb5_error_code ret;
1553 ret = get_init_creds_common(context, client, start_time,
1554 in_tkt_service, options, &ctx);
1558 ret = krb5_get_in_cred (context,
1559 KDCOptions2int(ctx.flags),
1564 init_creds_keyblock_key_proc,
1571 if (ret == 0 && creds)
1574 krb5_free_cred_contents (context, &ctx.cred);
1577 free_init_creds_ctx(context, &ctx);