1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/get_in_tkt.c */
4 * Copyright 1990,1991, 2003, 2008 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
30 #include "int-proto.h"
33 #include "init_creds_ctx.h"
36 #define IN_TKT_DEBUG 0
38 #define inTktDebug(args...) printf(args)
40 #define inTktDebug(args...)
42 #endif /* APPLE_PKINIT */
44 /* some typedef's for the function args to make things look a bit cleaner */
46 static krb5_error_code make_preauth_list (krb5_context,
48 int, krb5_pa_data ***);
49 static krb5_error_code sort_krb5_padata_sequence(krb5_context context,
51 krb5_pa_data **padata);
54 * This function performs 32 bit bounded addition so we can generate
55 * lifetimes without overflowing krb5_int32
58 krb5int_addint32 (krb5_int32 x, krb5_int32 y)
60 if ((x > 0) && (y > (KRB5_INT32_MAX - x))) {
61 /* sum will be be greater than KRB5_INT32_MAX */
62 return KRB5_INT32_MAX;
63 } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) {
64 /* sum will be less than KRB5_INT32_MIN */
65 return KRB5_INT32_MIN;
71 static krb5_error_code
72 decrypt_as_reply(krb5_context context, krb5_kdc_req *request,
73 krb5_kdc_rep *as_reply, krb5_keyblock *key)
75 if (as_reply->enc_part2)
78 return krb5_kdc_rep_decrypt_proc(context, key, NULL, as_reply);
82 * Fully anonymous replies include a pa_pkinit_kx padata type including the KDC
83 * contribution key. This routine confirms that the session key is of the
84 * right form for fully anonymous requests. It is here rather than in the
85 * preauth code because the session key cannot be verified until the AS reply
86 * is decrypted and the preauth code all runs before the AS reply is decrypted.
88 static krb5_error_code
89 verify_anonymous( krb5_context context, krb5_kdc_req *request,
90 krb5_kdc_rep *reply, krb5_keyblock *as_key)
92 krb5_error_code ret = 0;
95 krb5_keyblock *kdc_key = NULL, *expected = NULL;
96 krb5_enc_data *enc = NULL;
97 krb5_keyblock *session = reply->enc_part2->session;
99 if (!krb5_principal_compare_any_realm(context, request->client,
100 krb5_anonymous_principal()))
101 return 0; /* Only applies to fully anonymous */
102 pa = krb5int_find_pa_data(context, reply->padata, KRB5_PADATA_PKINIT_KX);
104 goto verification_error;
105 scratch.length = pa->length;
106 scratch.data = (char *) pa->contents;
107 ret = decode_krb5_enc_data( &scratch, &enc);
110 scratch.data = k5alloc(enc->ciphertext.length, &ret);
113 scratch.length = enc->ciphertext.length;
114 ret = krb5_c_decrypt(context, as_key, KRB5_KEYUSAGE_PA_PKINIT_KX,
115 NULL /*cipherstate*/, enc, &scratch);
120 ret = decode_krb5_encryption_key( &scratch, &kdc_key);
121 zap(scratch.data, scratch.length);
125 ret = krb5_c_fx_cf2_simple(context, kdc_key, "PKINIT",
126 as_key, "KEYEXCHANGE", &expected);
129 if ((expected->enctype != session->enctype) ||
130 (expected->length != session->length) ||
131 (memcmp(expected->contents, session->contents, expected->length) != 0))
132 goto verification_error;
135 krb5_free_keyblock(context, kdc_key);
137 krb5_free_keyblock(context, expected);
139 krb5_free_enc_data(context, enc);
142 ret = KRB5_KDCREP_MODIFIED;
143 krb5_set_error_message(context, ret, _("Reply has wrong form of session "
144 "key for anonymous request"));
148 static krb5_error_code
149 verify_as_reply(krb5_context context,
150 krb5_timestamp time_now,
151 krb5_kdc_req *request,
152 krb5_kdc_rep *as_reply)
154 krb5_error_code retval;
157 krb5_timestamp time_offset;
159 /* check the contents for sanity: */
160 if (!as_reply->enc_part2->times.starttime)
161 as_reply->enc_part2->times.starttime =
162 as_reply->enc_part2->times.authtime;
165 * We only allow the AS-REP server name to be changed if the
166 * caller set the canonicalize flag (or requested an enterprise
167 * principal) and we requested (and received) a TGT.
169 canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
170 (krb5_princ_type(context, request->client) ==
171 KRB5_NT_ENTERPRISE_PRINCIPAL) ||
172 (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS);
174 canon_ok = IS_TGS_PRINC(context, request->server) &&
175 IS_TGS_PRINC(context, as_reply->enc_part2->server);
176 if (!canon_ok && (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS)) {
177 canon_ok = krb5_principal_compare_any_realm(context,
179 krb5_anonymous_principal());
185 (!krb5_principal_compare(context, as_reply->client, request->client) ||
186 !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)))
187 || !krb5_principal_compare(context, as_reply->enc_part2->server, as_reply->ticket->server)
188 || (request->nonce != as_reply->enc_part2->nonce)
189 /* XXX check for extraneous flags */
190 /* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
191 || ((request->kdc_options & KDC_OPT_POSTDATED) &&
192 (request->from != 0) &&
193 (request->from != as_reply->enc_part2->times.starttime))
194 || ((request->till != 0) &&
195 (as_reply->enc_part2->times.endtime > request->till))
196 || ((request->kdc_options & KDC_OPT_RENEWABLE) &&
197 (request->rtime != 0) &&
198 (as_reply->enc_part2->times.renew_till > request->rtime))
199 || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
200 !(request->kdc_options & KDC_OPT_RENEWABLE) &&
201 (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
202 (request->till != 0) &&
203 (as_reply->enc_part2->times.renew_till > request->till))
206 inTktDebug("verify_as_reply: KDCREP_MODIFIED\n");
208 if(request->client->realm.length && request->client->data->length)
209 inTktDebug("request: name %s realm %s\n",
210 request->client->realm.data, request->client->data->data);
211 if(as_reply->client->realm.length && as_reply->client->data->length)
212 inTktDebug("reply : name %s realm %s\n",
213 as_reply->client->realm.data, as_reply->client->data->data);
215 #endif /* APPLE_PKINIT */
216 return KRB5_KDCREP_MODIFIED;
219 if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
220 time_offset = as_reply->enc_part2->times.authtime - time_now;
221 retval = krb5_set_time_offsets(context, time_offset, 0);
225 if ((request->from == 0) &&
226 (labs(as_reply->enc_part2->times.starttime - time_now)
227 > context->clockskew))
228 return (KRB5_KDCREP_SKEW);
233 static krb5_error_code
234 stash_as_reply(krb5_context context,
235 krb5_timestamp time_now,
236 krb5_kdc_req *request,
237 krb5_kdc_rep *as_reply,
241 krb5_error_code retval;
243 krb5_principal client;
244 krb5_principal server;
250 if ((retval = krb5_copy_principal(context, as_reply->client, &client)))
254 if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server,
258 /* fill in the credentials */
259 if ((retval = krb5_copy_keyblock_contents(context,
260 as_reply->enc_part2->session,
264 creds->times = as_reply->enc_part2->times;
265 creds->is_skey = FALSE; /* this is an AS_REQ, so cannot
266 be encrypted in skey */
267 creds->ticket_flags = as_reply->enc_part2->flags;
268 if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
272 creds->second_ticket.length = 0;
273 creds->second_ticket.data = 0;
275 if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
278 creds->ticket = *packet;
281 /* store it in the ccache! */
283 if ((retval = krb5_cc_store_cred(context, ccache, creds)))
287 creds->client = client;
289 creds->server = server;
294 krb5_free_principal(context, client);
296 krb5_free_principal(context, server);
297 if (creds->keyblock.contents) {
298 memset(creds->keyblock.contents, 0,
299 creds->keyblock.length);
300 free(creds->keyblock.contents);
301 creds->keyblock.contents = 0;
302 creds->keyblock.length = 0;
304 if (creds->ticket.data) {
305 free(creds->ticket.data);
306 creds->ticket.data = 0;
308 if (creds->addresses) {
309 krb5_free_addresses(context, creds->addresses);
310 creds->addresses = 0;
316 static krb5_error_code
317 make_preauth_list(krb5_context context,
318 krb5_preauthtype * ptypes,
320 krb5_pa_data *** ret_list)
322 krb5_preauthtype * ptypep;
323 krb5_pa_data ** preauthp;
327 for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
331 /* allocate space for a NULL to terminate the list */
334 (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
337 for (i=0; i<nptypes; i++) {
339 (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
345 preauthp[i]->magic = KV5M_PA_DATA;
346 preauthp[i]->pa_type = ptypes[i];
347 preauthp[i]->length = 0;
348 preauthp[i]->contents = 0;
351 /* fill in the terminating NULL */
353 preauthp[nptypes] = NULL;
355 *ret_list = preauthp;
359 #define MAX_IN_TKT_LOOPS 16
361 static krb5_error_code
362 request_enc_pa_rep(krb5_pa_data ***padptr)
365 krb5_pa_data **pad = *padptr;
366 krb5_pa_data *pa= NULL;
368 for (size=0; pad[size]; size++);
369 pad = realloc(pad, sizeof(*pad)*(size+2));
374 pa = malloc(sizeof(krb5_pa_data));
379 pa->pa_type = KRB5_ENCPADATA_REQ_ENC_PA_REP;
385 /* Sort a pa_data sequence so that types named in the "preferred_preauth_types"
386 * libdefaults entry are listed before any others. */
387 static krb5_error_code
388 sort_krb5_padata_sequence(krb5_context context, krb5_data *realm,
389 krb5_pa_data **padata)
395 char *q, *preauth_types = NULL;
397 int need_free_string = 1;
399 if ((padata == NULL) || (padata[0] == NULL)) {
403 ret = krb5int_libdefault_string(context, realm, KRB5_CONF_PREFERRED_PREAUTH_TYPES,
405 if ((ret != 0) || (preauth_types == NULL)) {
406 /* Try to use PKINIT first. */
407 preauth_types = "17, 16, 15, 14";
408 need_free_string = 0;
412 fprintf (stderr, "preauth data types before sorting:");
413 for (i = 0; padata[i]; i++) {
414 fprintf (stderr, " %d", padata[i]->pa_type);
416 fprintf (stderr, "\n");
420 for (p = preauth_types; *p != '\0';) {
421 /* skip whitespace to find an entry */
422 p += strspn(p, ", ");
424 /* see if we can extract a number */
425 l = strtol(p, &q, 10);
426 if ((q != NULL) && (q > p)) {
427 /* got a valid number; search for a matchin entry */
428 for (i = base; padata[i] != NULL; i++) {
429 /* bubble the matching entry to the front of the list */
430 if (padata[i]->pa_type == l) {
432 for (j = i; j > base; j--)
433 padata[j] = padata[j - 1];
445 if (need_free_string)
449 fprintf (stderr, "preauth data types after sorting:");
450 for (i = 0; padata[i]; i++)
451 fprintf (stderr, " %d", padata[i]->pa_type);
452 fprintf (stderr, "\n");
458 static krb5_error_code
459 build_in_tkt_name(krb5_context context,
460 char *in_tkt_service,
461 krb5_const_principal client,
462 krb5_principal *server)
468 if (in_tkt_service) {
469 /* this is ugly, because so are the data structures involved. I'm
470 in the library, so I'm going to manipulate the data structures
471 directly, otherwise, it will be worse. */
473 if ((ret = krb5_parse_name(context, in_tkt_service, server)))
476 /* stuff the client realm into the server principal.
477 realloc if necessary */
478 if ((*server)->realm.length < client->realm.length) {
479 char *p = realloc((*server)->realm.data,
480 client->realm.length);
482 krb5_free_principal(context, *server);
486 (*server)->realm.data = p;
489 (*server)->realm.length = client->realm.length;
490 memcpy((*server)->realm.data, client->realm.data, client->realm.length);
492 ret = krb5_build_principal_ext(context, server,
493 client->realm.length,
497 client->realm.length,
504 * Windows Server 2008 R2 RODC insists on TGS principal names having the
507 if (krb5_princ_size(context, *server) == 2 &&
508 data_eq_string(*krb5_princ_component(context, *server, 0),
510 krb5_princ_type(context, *server) = KRB5_NT_SRV_INST;
516 krb5_init_creds_free(krb5_context context,
517 krb5_init_creds_context ctx)
522 if (ctx->opte != NULL && krb5_gic_opt_is_shadowed(ctx->opte)) {
523 krb5_get_init_creds_opt_free(context,
524 (krb5_get_init_creds_opt *)ctx->opte);
526 free(ctx->in_tkt_service);
527 zap(ctx->password.data, ctx->password.length);
528 krb5_free_data_contents(context, &ctx->password);
529 krb5_free_error(context, ctx->err_reply);
530 krb5_free_pa_data(context, ctx->err_padata);
531 krb5_free_cred_contents(context, &ctx->cred);
532 krb5_free_kdc_req(context, ctx->request);
533 krb5_free_kdc_rep(context, ctx->reply);
534 krb5_free_data(context, ctx->outer_request_body);
535 krb5_free_data(context, ctx->inner_request_body);
536 krb5_free_data(context, ctx->encoded_previous_request);
537 krb5int_fast_free_state(context, ctx->fast_state);
538 krb5_free_pa_data(context, ctx->preauth_to_use);
539 krb5_free_data_contents(context, &ctx->salt);
540 krb5_free_data_contents(context, &ctx->s2kparams);
541 krb5_free_keyblock_contents(context, &ctx->as_key);
546 k5_init_creds_get(krb5_context context, krb5_init_creds_context ctx,
549 krb5_error_code code;
553 unsigned int flags = 0;
564 code = krb5_init_creds_step(context,
570 if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !tcp_only) {
571 TRACE_INIT_CREDS_RETRY_TCP(context);
573 } else if (code != 0 || !(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE))
576 krb5_free_data_contents(context, &reply);
578 code = krb5_sendto_kdc(context, &request, &realm,
579 &reply, use_master, tcp_only);
583 krb5_free_data_contents(context, &request);
584 krb5_free_data_contents(context, &realm);
587 krb5_free_data_contents(context, &request);
588 krb5_free_data_contents(context, &reply);
589 krb5_free_data_contents(context, &realm);
595 krb5_error_code KRB5_CALLCONV
596 krb5_init_creds_get(krb5_context context,
597 krb5_init_creds_context ctx)
601 return k5_init_creds_get(context, ctx, &use_master);
604 krb5_error_code KRB5_CALLCONV
605 krb5_init_creds_get_creds(krb5_context context,
606 krb5_init_creds_context ctx,
610 return KRB5_NO_TKT_SUPPLIED;
612 return krb5int_copy_creds_contents(context, &ctx->cred, creds);
615 krb5_error_code KRB5_CALLCONV
616 krb5_init_creds_get_times(krb5_context context,
617 krb5_init_creds_context ctx,
618 krb5_ticket_times *times)
621 return KRB5_NO_TKT_SUPPLIED;
623 *times = ctx->cred.times;
628 krb5_error_code KRB5_CALLCONV
629 krb5_init_creds_get_error(krb5_context context,
630 krb5_init_creds_context ctx,
633 krb5_error_code code;
634 krb5_error *ret = NULL;
638 if (ctx->err_reply == NULL)
641 ret = k5alloc(sizeof(*ret), &code);
645 ret->magic = KV5M_ERROR;
646 ret->ctime = ctx->err_reply->ctime;
647 ret->cusec = ctx->err_reply->cusec;
648 ret->susec = ctx->err_reply->susec;
649 ret->stime = ctx->err_reply->stime;
650 ret->error = ctx->err_reply->error;
652 if (ctx->err_reply->client != NULL) {
653 code = krb5_copy_principal(context, ctx->err_reply->client,
659 code = krb5_copy_principal(context, ctx->err_reply->server, &ret->server);
663 code = krb5int_copy_data_contents(context, &ctx->err_reply->text,
668 code = krb5int_copy_data_contents(context, &ctx->err_reply->e_data,
677 krb5_free_error(context, ret);
683 * Throw away any state related to specific realm either at the beginning of a
684 * request, or when a realm changes, or when we start to use FAST after
685 * assuming we would not do so.
687 * @param padata padata from an error if an error from the realm we now expect
688 * to talk to caused the restart. Used to infer negotiation characteristics
689 * such as whether FAST is used.
691 static krb5_error_code
692 restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx,
693 krb5_pa_data **padata)
695 krb5_error_code code = 0;
696 unsigned char random_buf[4];
697 krb5_data random_data;
698 if (ctx->preauth_to_use) {
699 krb5_free_pa_data(context, ctx->preauth_to_use);
700 ctx->preauth_to_use = NULL;
703 if (ctx->fast_state) {
704 krb5int_fast_free_state(context, ctx->fast_state);
705 ctx->fast_state = NULL;
707 code = krb5int_fast_make_state(context, &ctx->fast_state);
710 ctx->preauth_rock.fast_state = ctx->fast_state;
711 krb5_preauth_request_context_init(context);
712 if (ctx->outer_request_body) {
713 krb5_free_data(context, ctx->outer_request_body);
714 ctx->outer_request_body = NULL;
717 (ctx->opte->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
718 if ((code = make_preauth_list(context, ctx->opte->preauth_list,
719 ctx->opte->preauth_list_length,
720 &ctx->preauth_to_use)))
724 /* Set the request nonce. */
725 random_data.length = 4;
726 random_data.data = (char *)random_buf;
727 code = krb5_c_random_make_octets(context, &random_data);
731 * See RT ticket 3196 at MIT. If we set the high bit, we may have
732 * compatibility problems with Heimdal, because we (incorrectly) encode
733 * this value as signed.
735 ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
736 krb5_free_principal(context, ctx->request->server);
737 ctx->request->server = NULL;
739 code = build_in_tkt_name(context, ctx->in_tkt_service,
740 ctx->request->client,
741 &ctx->request->server);
745 ctx->request_time = time(NULL);
747 code = krb5int_fast_as_armor(context, ctx->fast_state,
748 ctx->opte, ctx->request);
751 if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
752 code = krb5int_fast_as_armor(context, ctx->fast_state,
753 ctx->opte, ctx->request);
757 /* give the preauth plugins a chance to prep the request body */
758 krb5_preauth_prepare_request(context, ctx->opte, ctx->request);
760 ctx->request->from = krb5int_addint32(ctx->request_time,
762 ctx->request->till = krb5int_addint32(ctx->request->from,
765 if (ctx->renew_life > 0) {
766 ctx->request->rtime =
767 krb5int_addint32(ctx->request->from, ctx->renew_life);
768 if (ctx->request->rtime < ctx->request->till) {
769 /* don't ask for a smaller renewable time than the lifetime */
770 ctx->request->rtime = ctx->request->till;
772 ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
774 ctx->request->rtime = 0;
775 code = krb5int_fast_prep_req_body(context, ctx->fast_state,
777 &ctx->outer_request_body);
784 krb5_error_code KRB5_CALLCONV
785 krb5_init_creds_init(krb5_context context,
786 krb5_principal client,
787 krb5_prompter_fct prompter,
789 krb5_deltat start_time,
790 krb5_get_init_creds_opt *options,
791 krb5_init_creds_context *pctx)
793 krb5_error_code code;
794 krb5_init_creds_context ctx;
797 krb5_gic_opt_ext *opte;
798 krb5_get_init_creds_opt local_opts;
800 TRACE_INIT_CREDS(context, client);
802 ctx = k5alloc(sizeof(*ctx), &code);
806 ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
809 ctx->enc_pa_rep_permitted = 1;
810 code = krb5_copy_principal(context, client, &ctx->request->client);
814 ctx->prompter = prompter;
815 ctx->prompter_data = data;
816 ctx->gak_fct = krb5_get_as_key_password;
817 ctx->gak_data = &ctx->password;
819 ctx->request_time = 0; /* filled in later */
820 ctx->start_time = start_time;
822 if (options == NULL) {
824 * We initialize a non-extended options because that way the shadowed
825 * flag will be sent and they will be freed when the init_creds context
826 * is freed. The options will be extended and copied off the stack into
827 * storage by opt_to_opte.
829 krb5_get_init_creds_opt_init(&local_opts);
830 options = &local_opts;
833 code = krb5int_gic_opt_to_opte(context, options,
834 &ctx->opte, 1, "krb5_init_creds_init");
840 ctx->preauth_rock.magic = CLIENT_ROCK_MAGIC;
841 ctx->preauth_rock.etype = &ctx->etype;
842 ctx->preauth_rock.as_key = &ctx->as_key;
843 ctx->preauth_rock.gak_fct = &ctx->gak_fct;
844 ctx->preauth_rock.gak_data = &ctx->gak_data;
845 ctx->preauth_rock.salt = &ctx->salt;
846 ctx->preauth_rock.s2kparams = &ctx->s2kparams;
847 ctx->preauth_rock.client = client;
848 ctx->preauth_rock.prompter = prompter;
849 ctx->preauth_rock.prompter_data = data;
851 /* Initialise request parameters as per krb5_get_init_creds() */
852 ctx->request->kdc_options = context->kdc_default_options;
855 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
856 tmp = opte->forwardable;
857 else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
858 KRB5_CONF_FORWARDABLE, &tmp) == 0)
863 ctx->request->kdc_options |= KDC_OPT_FORWARDABLE;
866 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
867 tmp = opte->proxiable;
868 else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
869 KRB5_CONF_PROXIABLE, &tmp) == 0)
874 ctx->request->kdc_options |= KDC_OPT_PROXIABLE;
877 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_CANONICALIZE)
879 else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
880 KRB5_CONF_CANONICALIZE, &tmp) == 0)
885 ctx->request->kdc_options |= KDC_OPT_CANONICALIZE;
888 if (ctx->start_time > 0)
889 ctx->request->kdc_options |= KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED;
891 /* ticket lifetime */
892 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
893 ctx->tkt_life = options->tkt_life;
894 else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
895 KRB5_CONF_TICKET_LIFETIME, &str) == 0) {
896 code = krb5_string_to_deltat(str, &ctx->tkt_life);
902 ctx->tkt_life = 24 * 60 * 60; /* previously hardcoded in kinit */
904 /* renewable lifetime */
905 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)
906 ctx->renew_life = options->renew_life;
907 else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
908 KRB5_CONF_RENEW_LIFETIME, &str) == 0) {
909 code = krb5_string_to_deltat(str, &ctx->renew_life);
917 if (ctx->renew_life > 0)
918 ctx->request->kdc_options |= KDC_OPT_RENEWABLE;
921 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
922 ctx->request->ktype =
923 k5alloc((opte->etype_list_length * sizeof(krb5_enctype)),
927 ctx->request->nktypes = opte->etype_list_length;
928 memcpy(ctx->request->ktype, opte->etype_list,
929 ctx->request->nktypes * sizeof(krb5_enctype));
930 } else if (krb5_get_default_in_tkt_ktypes(context,
931 &ctx->request->ktype) == 0) {
932 ctx->request->nktypes = krb5int_count_etypes(ctx->request->ktype);
934 /* there isn't any useful default here. */
935 code = KRB5_CONFIG_ETYPE_NOSUPP;
940 * Set a default enctype for optimistic preauth. If we're not doing
941 * optimistic preauth, this should ordinarily get overwritten when we
942 * process the etype-info2 of the preauth-required error.
944 if (ctx->request->nktypes > 0)
945 ctx->etype = ctx->request->ktype[0];
948 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
949 code = krb5_copy_addresses(context, opte->address_list,
950 &ctx->request->addresses);
953 } else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
954 KRB5_CONF_NOADDRESSES, &tmp) != 0
956 ctx->request->addresses = NULL;
958 code = krb5_os_localaddr(context, &ctx->request->addresses);
963 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_SALT) {
964 code = krb5int_copy_data_contents(context, opte->salt, &ctx->salt);
968 ctx->salt.length = SALT_TYPE_AFS_LENGTH;
969 ctx->salt.data = NULL;
973 if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
974 ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
975 /* Remap @REALM to WELLKNOWN/ANONYMOUS@REALM. */
976 if (client->length == 1 && client->data[0].length ==0) {
977 krb5_principal new_client;
978 code = krb5_build_principal_ext(context, &new_client,
979 client->realm.length,
981 strlen(KRB5_WELLKNOWN_NAMESTR),
982 KRB5_WELLKNOWN_NAMESTR,
983 strlen(KRB5_ANONYMOUS_PRINCSTR),
984 KRB5_ANONYMOUS_PRINCSTR,
988 krb5_free_principal(context, ctx->request->client);
989 ctx->request->client = new_client;
990 krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
993 /* We will also handle anonymous if the input principal is the anonymous
995 if (krb5_principal_compare_any_realm(context, ctx->request->client,
996 krb5_anonymous_principal())) {
997 ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
998 krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
1000 code = restart_init_creds_loop(context, ctx, NULL);
1008 krb5_init_creds_free(context, ctx);
1014 krb5_error_code KRB5_CALLCONV
1015 krb5_init_creds_set_service(krb5_context context,
1016 krb5_init_creds_context ctx,
1017 const char *service)
1021 TRACE_INIT_CREDS_SERVICE(context, service);
1023 s = strdup(service);
1027 free(ctx->in_tkt_service);
1028 ctx->in_tkt_service = s;
1030 krb5_preauth_request_context_fini(context);
1031 return restart_init_creds_loop(context, ctx, NULL);
1034 static krb5_error_code
1035 init_creds_validate_reply(krb5_context context,
1036 krb5_init_creds_context ctx,
1039 krb5_error_code code;
1040 krb5_error *error = NULL;
1041 krb5_kdc_rep *as_reply = NULL;
1043 krb5_free_error(context, ctx->err_reply);
1044 ctx->err_reply = NULL;
1046 krb5_free_kdc_rep(context, ctx->reply);
1049 if (krb5_is_krb_error(reply)) {
1050 code = decode_krb5_error(reply, &error);
1054 assert(error != NULL);
1056 TRACE_INIT_CREDS_ERROR_REPLY(context,
1057 error->error + ERROR_TABLE_BASE_krb5);
1058 if (error->error == KRB_ERR_RESPONSE_TOO_BIG) {
1059 krb5_free_error(context, error);
1060 return KRB5KRB_ERR_RESPONSE_TOO_BIG;
1062 ctx->err_reply = error;
1068 * Check to make sure it isn't a V4 reply.
1070 if (reply->length != 0 && !krb5_is_as_rep(reply)) {
1071 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1072 #define V4_KRB_PROT_VERSION 4
1073 #define V4_AUTH_MSG_ERR_REPLY (5<<1)
1074 /* check here for V4 reply */
1075 unsigned int t_switch;
1077 /* From v4 g_in_tkt.c: This used to be
1078 switch (pkt_msg_type(rpkt) & ~1) {
1079 but SCO 3.2v4 cc compiled that incorrectly. */
1080 t_switch = reply->data[1];
1083 if (t_switch == V4_AUTH_MSG_ERR_REPLY
1084 && reply->data[0] == V4_KRB_PROT_VERSION) {
1085 code = KRB5KRB_AP_ERR_V4_REPLY;
1087 code = KRB5KRB_AP_ERR_MSG_TYPE;
1092 /* It must be a KRB_AS_REP message, or an bad returned packet */
1093 code = decode_krb5_as_rep(reply, &as_reply);
1097 if (as_reply->msg_type != KRB5_AS_REP) {
1098 krb5_free_kdc_rep(context, as_reply);
1099 return KRB5KRB_AP_ERR_MSG_TYPE;
1102 ctx->reply = as_reply;
1107 static krb5_error_code
1108 init_creds_step_request(krb5_context context,
1109 krb5_init_creds_context ctx,
1112 krb5_error_code code;
1113 krb5_boolean got_real;
1115 krb5_data random_data;
1117 if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
1118 code = KRB5_GET_IN_TKT_LOOP;
1122 * RFC 6113 requires a new nonce for the inner request on each try. It's
1123 * permitted to change the nonce even for non-FAST so we do here.
1125 random_data.length = 4;
1126 random_data.data = (char *)random_buf;
1127 code = krb5_c_random_make_octets(context, &random_data);
1131 * See RT ticket 3196 at MIT. If we set the high bit, we may have
1132 * compatibility problems with Heimdal, because we (incorrectly) encode
1133 * this value as signed.
1135 ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
1136 krb5_free_data(context, ctx->inner_request_body);
1137 ctx->inner_request_body = NULL;
1138 code = encode_krb5_kdc_req_body(ctx->request, &ctx->inner_request_body);
1142 if (ctx->err_reply == NULL) {
1143 /* either our first attempt, or retrying after PREAUTH_NEEDED */
1144 code = krb5_do_preauth(context,
1146 ctx->inner_request_body,
1147 ctx->encoded_previous_request,
1148 ctx->preauth_to_use,
1149 &ctx->request->padata,
1155 if (code == 0 && !got_real && ctx->preauth_required)
1156 code = KRB5_PREAUTH_FAILED;
1160 if (ctx->preauth_to_use != NULL) {
1162 * Retry after an error other than PREAUTH_NEEDED,
1163 * using ctx->err_padata to figure out what to change.
1165 code = krb5_do_preauth_tryagain(context,
1167 ctx->inner_request_body,
1168 ctx->encoded_previous_request,
1169 ctx->preauth_to_use,
1170 &ctx->request->padata,
1178 /* No preauth supplied, so can't query the plugins. */
1179 code = KRB5KRB_ERR_GENERIC;
1182 /* couldn't come up with anything better */
1183 code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
1188 if (ctx->encoded_previous_request != NULL) {
1189 krb5_free_data(context, ctx->encoded_previous_request);
1190 ctx->encoded_previous_request = NULL;
1192 if (ctx->request->padata)
1193 ctx->sent_nontrivial_preauth = 1;
1194 if (ctx->enc_pa_rep_permitted)
1195 code = request_enc_pa_rep(&ctx->request->padata);
1198 code = krb5int_fast_prep_req(context, ctx->fast_state,
1199 ctx->request, ctx->outer_request_body,
1201 &ctx->encoded_previous_request);
1205 code = krb5int_copy_data_contents(context,
1206 ctx->encoded_previous_request,
1212 krb5_free_pa_data(context, ctx->request->padata);
1213 ctx->request->padata = NULL;
1218 * The control flow is complicated. In order to switch from non-FAST mode to
1219 * FAST mode, we need to reset our pre-authentication state. FAST negotiation
1220 * attempts to make sure we rarely have to do this. When FAST negotiation is
1221 * working, we record whether FAST is available when we obtain an armor ticket;
1222 * if so, we start out with FAST enabled . There are two complicated
1225 * First, if we get a PREAUTH_REQUIRED error including PADATA_FX_FAST back from
1226 * a KDC in a case where we were not expecting to use FAST, and we have an
1227 * armor ticket available, then we want to use FAST. That involves clearing
1228 * out the pre-auth state, reinitializing the plugins and trying again with an
1231 * Secondly, using the negotiation can cause problems with some older KDCs.
1232 * Negotiation involves including a special padata item. Some KDCs, including
1233 * MIT prior to 1.7, will return PREAUTH_FAILED rather than PREAUTH_REQUIRED in
1234 * pre-authentication is required and unknown padata are included in the
1235 * request. To make matters worse, these KDCs typically do not include a list
1236 * of padata in PREAUTH_FAILED errors. So, if we get PREAUTH_FAILED and we
1237 * generated no pre-authentication other than the negotiation then we want to
1238 * retry without negotiation. In this case it is probably also desirable to
1239 * retry with the preauth plugin state cleared.
1241 * In all these cases we should not start over more than once. Control flow is
1242 * managed by several variables.
1244 * sent_nontrivial_preauth: if true, we sent preauth other than negotiation;
1245 * no restart on PREAUTH_FAILED
1247 * KRB5INT_FAST_ARMOR_AVAIL: fast_state_flag if desired we could generate
1248 * armor; if not set, then we can't use FAST even if the KDC wants to.
1250 * have_restarted: true if we've already restarted
1253 negotiation_requests_restart(krb5_context context, krb5_init_creds_context ctx,
1254 krb5_pa_data **padata)
1256 if (ctx->have_restarted)
1258 if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
1259 TRACE_INIT_CREDS_RESTART_FAST(context);
1262 if (ctx->err_reply->error == KDC_ERR_PREAUTH_FAILED &&
1263 !ctx->sent_nontrivial_preauth) {
1264 TRACE_INIT_CREDS_RESTART_PREAUTH_FAILED(context);
1270 /* Ensure that the reply enctype was among the requested enctypes. */
1271 static krb5_error_code
1272 check_reply_enctype(krb5_init_creds_context ctx)
1276 for (i = 0; i < ctx->request->nktypes; i++) {
1277 if (ctx->request->ktype[i] == ctx->reply->enc_part.enctype)
1280 return KRB5_CONFIG_ETYPE_NOSUPP;
1283 /* Note the difference between the KDC's time, as reported to us in a
1284 * preauth-required error, and the current time. */
1286 note_req_timestamp(krb5_context kcontext, krb5_clpreauth_rock rock,
1287 krb5_timestamp kdc_time, krb5_int32 kdc_usec)
1292 if (k5_time_with_offset(0, 0, &now, &usec) != 0)
1294 rock->pa_offset = kdc_time - now;
1295 rock->pa_offset_usec = kdc_usec - usec;
1296 rock->pa_offset_state = (rock->fast_state->armor_key != NULL) ?
1297 AUTH_OFFSET : UNAUTH_OFFSET;
1300 static krb5_error_code
1301 init_creds_step_reply(krb5_context context,
1302 krb5_init_creds_context ctx,
1305 krb5_error_code code;
1306 krb5_pa_data **kdc_padata = NULL;
1307 krb5_boolean retry = FALSE;
1309 krb5_keyblock *strengthen_key = NULL;
1310 krb5_keyblock encrypting_key;
1311 krb5_boolean fast_avail, got_real;
1313 encrypting_key.length = 0;
1314 encrypting_key.contents = NULL;
1316 /* process previous KDC response */
1317 code = init_creds_validate_reply(context, ctx, in);
1321 /* per referrals draft, enterprise principals imply canonicalization */
1322 canon_flag = ((ctx->request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
1323 ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
1325 if (ctx->err_reply != NULL) {
1326 code = krb5int_fast_process_error(context, ctx->fast_state,
1327 &ctx->err_reply, &ctx->err_padata,
1331 if (negotiation_requests_restart(context, ctx, ctx->err_padata)) {
1332 ctx->have_restarted = 1;
1333 krb5_preauth_request_context_fini(context);
1334 if ((ctx->fast_state->fast_state_flags & KRB5INT_FAST_DO_FAST) ==0)
1335 ctx->enc_pa_rep_permitted = 0;
1336 code = restart_init_creds_loop(context, ctx, ctx->err_padata);
1337 krb5_free_error(context, ctx->err_reply);
1338 ctx->err_reply = NULL;
1339 krb5_free_pa_data(context, ctx->err_padata);
1340 ctx->err_padata = NULL;
1341 } else if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
1343 /* reset the list of preauth types to try */
1344 krb5_free_pa_data(context, ctx->preauth_to_use);
1345 ctx->preauth_to_use = ctx->err_padata;
1346 ctx->err_padata = NULL;
1347 note_req_timestamp(context, &ctx->preauth_rock,
1348 ctx->err_reply->stime, ctx->err_reply->susec);
1349 /* this will trigger a new call to krb5_do_preauth() */
1350 krb5_free_error(context, ctx->err_reply);
1351 ctx->err_reply = NULL;
1352 code = sort_krb5_padata_sequence(context,
1353 &ctx->request->client->realm,
1354 ctx->preauth_to_use);
1355 ctx->preauth_required = TRUE;
1357 } else if (canon_flag && ctx->err_reply->error == KDC_ERR_WRONG_REALM) {
1358 if (ctx->err_reply->client == NULL ||
1359 !krb5_princ_realm(context, ctx->err_reply->client)->length) {
1360 code = KRB5KDC_ERR_WRONG_REALM;
1363 TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm);
1364 /* Rewrite request.client with realm from error reply */
1365 krb5_free_data_contents(context, &ctx->request->client->realm);
1366 code = krb5int_copy_data_contents(context,
1367 &ctx->err_reply->client->realm,
1368 &ctx->request->client->realm);
1369 /* this will trigger a new call to krb5_do_preauth() */
1370 krb5_free_error(context, ctx->err_reply);
1371 ctx->err_reply = NULL;
1372 krb5_preauth_request_context_fini(context);
1373 /* Permit another negotiation based restart. */
1374 ctx->have_restarted = 0;
1375 ctx->sent_nontrivial_preauth = 0;
1376 code = restart_init_creds_loop(context, ctx, NULL);
1383 /* error + no hints = give up */
1384 code = (krb5_error_code)ctx->err_reply->error +
1385 ERROR_TABLE_BASE_krb5;
1389 /* Return error code, or continue with next iteration */
1393 /* We have a response. Process it. */
1394 assert(ctx->reply != NULL);
1396 /* Check for replies (likely forged) with unasked-for enctypes. */
1397 code = check_reply_enctype(ctx);
1401 /* process any preauth data in the as_reply */
1402 krb5_clear_preauth_context_use_counts(context);
1403 code = krb5int_fast_process_response(context, ctx->fast_state,
1404 ctx->reply, &strengthen_key);
1408 code = sort_krb5_padata_sequence(context, &ctx->request->client->realm,
1409 ctx->reply->padata);
1413 ctx->etype = ctx->reply->enc_part.enctype;
1415 code = krb5_do_preauth(context,
1417 ctx->inner_request_body,
1418 ctx->encoded_previous_request,
1430 * If we haven't gotten a salt from another source yet, set up one
1431 * corresponding to the client principal returned by the KDC. We
1432 * could get the same effect by passing local_as_reply->client to
1433 * gak_fct below, but that would put the canonicalized client name
1434 * in the prompt, which raises issues of needing to sanitize
1435 * unprintable characters. So for now we just let it affect the
1436 * salt. local_as_reply->client will be checked later on in
1439 if (ctx->salt.length == SALT_TYPE_AFS_LENGTH && ctx->salt.data == NULL) {
1440 code = krb5_principal2salt(context, ctx->reply->client, &ctx->salt);
1441 TRACE_INIT_CREDS_SALT_PRINC(context, &ctx->salt);
1446 /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
1447 the AS_REP comes back encrypted in the user's longterm key
1448 instead of in the SAD. If there was a SAM preauth, there
1449 will be an as_key here which will be the SAD. If that fails,
1450 use the gak_fct to get the password, and try again. */
1452 /* XXX because etypes are handled poorly (particularly wrt SAM,
1453 where the etype is fixed by the kdc), we may want to try
1454 decrypt_as_reply twice. If there's an as_key available, try
1455 it. If decrypting the as_rep fails, or if there isn't an
1456 as_key at all yet, then use the gak_fct to get one, and try
1458 if (ctx->as_key.length) {
1459 TRACE_INIT_CREDS_AS_KEY_PREAUTH(context, &ctx->as_key);
1460 code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1464 code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1466 TRACE_INIT_CREDS_PREAUTH_DECRYPT_FAIL(context, code);
1471 /* if we haven't get gotten a key, get it now */
1472 TRACE_INIT_CREDS_GAK(context, &ctx->salt, &ctx->s2kparams);
1473 code = (*ctx->gak_fct)(context, ctx->request->client,
1474 ctx->reply->enc_part.enctype,
1475 ctx->prompter, ctx->prompter_data,
1476 &ctx->salt, &ctx->s2kparams,
1477 &ctx->as_key, ctx->gak_data);
1480 TRACE_INIT_CREDS_AS_KEY_GAK(context, &ctx->as_key);
1482 code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1487 code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1492 TRACE_INIT_CREDS_DECRYPTED_REPLY(context, ctx->reply->enc_part2->session);
1494 code = krb5int_fast_verify_nego(context, ctx->fast_state,
1495 ctx->reply, ctx->encoded_previous_request,
1496 &encrypting_key, &fast_avail);
1499 code = verify_as_reply(context, ctx->request_time,
1500 ctx->request, ctx->reply);
1503 code = verify_anonymous(context, ctx->request, ctx->reply,
1508 code = stash_as_reply(context, ctx->request_time, ctx->request,
1509 ctx->reply, &ctx->cred, NULL);
1512 if (ctx->opte && ctx->opte->opt_private->out_ccache) {
1513 krb5_ccache out_ccache = ctx->opte->opt_private->out_ccache;
1514 krb5_data config_data;
1515 code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
1518 code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
1522 config_data.data = "yes";
1523 config_data.length = strlen(config_data.data);
1524 code = krb5_cc_set_config(context, out_ccache, ctx->cred.server,
1525 KRB5_CONF_FAST_AVAIL, &config_data);
1530 msg = krb5_get_error_message(context, code);
1531 krb5_set_error_message(context, code,
1532 _("%s while storing credentials"), msg);
1533 krb5_free_error_message(context, msg);
1537 krb5_preauth_request_context_fini(context);
1541 ctx->complete = TRUE;
1544 krb5_free_pa_data(context, kdc_padata);
1545 krb5_free_keyblock(context, strengthen_key);
1546 krb5_free_keyblock_contents(context, &encrypting_key);
1552 * Do next step of credentials acquisition.
1554 * On success returns 0 or KRB5KRB_ERR_RESPONSE_TOO_BIG if the request
1555 * should be sent with TCP.
1557 krb5_error_code KRB5_CALLCONV
1558 krb5_init_creds_step(krb5_context context,
1559 krb5_init_creds_context ctx,
1563 unsigned int *flags)
1565 krb5_error_code code = 0, code2;
1578 if (in->length != 0) {
1579 code = init_creds_step_reply(context, ctx, in);
1580 if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
1581 code2 = krb5int_copy_data_contents(context,
1582 ctx->encoded_previous_request,
1590 if (code != 0 || ctx->complete)
1594 code = init_creds_step_request(context, ctx, out);
1598 /* Only a new request increments the loop count, not a TCP retry */
1602 assert(ctx->request->server != NULL);
1604 code2 = krb5int_copy_data_contents(context,
1605 &ctx->request->server->realm,
1613 if (code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN) {
1616 /* See if we can produce a more detailed error message */
1617 code2 = krb5_unparse_name(context, ctx->request->client, &client_name);
1619 krb5_set_error_message(context, code,
1620 _("Client '%s' not found in Kerberos "
1621 "database"), client_name);
1622 krb5_free_unparsed_name(context, client_name);
1626 *flags = ctx->complete ? 0 : KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
1630 krb5_error_code KRB5_CALLCONV
1631 krb5int_get_init_creds(krb5_context context,
1633 krb5_principal client,
1634 krb5_prompter_fct prompter,
1635 void *prompter_data,
1636 krb5_deltat start_time,
1637 char *in_tkt_service,
1638 krb5_get_init_creds_opt *options,
1639 krb5_gic_get_as_key_fct gak_fct,
1642 krb5_kdc_rep **as_reply)
1644 krb5_error_code code;
1645 krb5_init_creds_context ctx = NULL;
1647 code = krb5_init_creds_init(context,
1657 ctx->gak_fct = gak_fct;
1658 ctx->gak_data = gak_data;
1660 if (in_tkt_service) {
1661 code = krb5_init_creds_set_service(context, ctx, in_tkt_service);
1666 code = k5_init_creds_get(context, ctx, use_master);
1670 code = krb5_init_creds_get_creds(context, ctx, creds);
1674 if (as_reply != NULL) {
1675 *as_reply = ctx->reply;
1680 krb5_init_creds_free(context, ctx);
1686 krb5int_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
1687 krb5_flags options, krb5_address *const *addrs,
1688 krb5_enctype *ktypes,
1689 krb5_preauthtype *pre_auth_types, krb5_creds *creds)
1692 krb5_int32 starttime;
1693 krb5_get_init_creds_opt *opt;
1694 krb5_error_code retval;
1697 retval = krb5_get_init_creds_opt_alloc(context, &opt);
1702 krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
1704 i = krb5int_count_etypes(ktypes);
1706 krb5_get_init_creds_opt_set_etype_list(opt, ktypes, i);
1708 if (pre_auth_types) {
1709 for (i=0; pre_auth_types[i]; i++);
1711 krb5_get_init_creds_opt_set_preauth_list(opt, pre_auth_types, i);
1713 if (options&KDC_OPT_FORWARDABLE)
1714 krb5_get_init_creds_opt_set_forwardable(opt, 1);
1715 else krb5_get_init_creds_opt_set_forwardable(opt, 0);
1716 if (options&KDC_OPT_PROXIABLE)
1717 krb5_get_init_creds_opt_set_proxiable(opt, 1);
1718 else krb5_get_init_creds_opt_set_proxiable(opt, 0);
1719 if (creds && creds->times.endtime) {
1720 retval = krb5_timeofday(context, &starttime);
1723 if (creds->times.starttime) starttime = creds->times.starttime;
1724 krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
1730 krb5_get_init_creds_opt_free(context, opt);