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);
545 static krb5_error_code
546 init_creds_get(krb5_context context,
547 krb5_init_creds_context ctx,
550 krb5_error_code code;
554 unsigned int flags = 0;
565 code = krb5_init_creds_step(context,
571 if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !tcp_only) {
572 TRACE_INIT_CREDS_RETRY_TCP(context);
574 } else if (code != 0 || !(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE))
577 krb5_free_data_contents(context, &reply);
579 code = krb5_sendto_kdc(context, &request, &realm,
580 &reply, use_master, tcp_only);
584 krb5_free_data_contents(context, &request);
585 krb5_free_data_contents(context, &realm);
588 krb5_free_data_contents(context, &request);
589 krb5_free_data_contents(context, &reply);
590 krb5_free_data_contents(context, &realm);
596 krb5_error_code KRB5_CALLCONV
597 krb5_init_creds_get(krb5_context context,
598 krb5_init_creds_context ctx)
602 return init_creds_get(context, ctx, &use_master);
605 krb5_error_code KRB5_CALLCONV
606 krb5_init_creds_get_creds(krb5_context context,
607 krb5_init_creds_context ctx,
611 return KRB5_NO_TKT_SUPPLIED;
613 return krb5int_copy_creds_contents(context, &ctx->cred, creds);
616 krb5_error_code KRB5_CALLCONV
617 krb5_init_creds_get_times(krb5_context context,
618 krb5_init_creds_context ctx,
619 krb5_ticket_times *times)
622 return KRB5_NO_TKT_SUPPLIED;
624 *times = ctx->cred.times;
629 krb5_error_code KRB5_CALLCONV
630 krb5_init_creds_get_error(krb5_context context,
631 krb5_init_creds_context ctx,
634 krb5_error_code code;
635 krb5_error *ret = NULL;
639 if (ctx->err_reply == NULL)
642 ret = k5alloc(sizeof(*ret), &code);
646 ret->magic = KV5M_ERROR;
647 ret->ctime = ctx->err_reply->ctime;
648 ret->cusec = ctx->err_reply->cusec;
649 ret->susec = ctx->err_reply->susec;
650 ret->stime = ctx->err_reply->stime;
651 ret->error = ctx->err_reply->error;
653 if (ctx->err_reply->client != NULL) {
654 code = krb5_copy_principal(context, ctx->err_reply->client,
660 code = krb5_copy_principal(context, ctx->err_reply->server, &ret->server);
664 code = krb5int_copy_data_contents(context, &ctx->err_reply->text,
669 code = krb5int_copy_data_contents(context, &ctx->err_reply->e_data,
678 krb5_free_error(context, ret);
684 * Throw away any state related to specific realm either at the beginning of a
685 * request, or when a realm changes, or when we start to use FAST after
686 * assuming we would not do so.
688 * @param padata padata from an error if an error from the realm we now expect
689 * to talk to caused the restart. Used to infer negotiation characteristics
690 * such as whether FAST is used.
692 static krb5_error_code
693 restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx,
694 krb5_pa_data **padata)
696 krb5_error_code code = 0;
697 unsigned char random_buf[4];
698 krb5_data random_data;
699 if (ctx->preauth_to_use) {
700 krb5_free_pa_data(context, ctx->preauth_to_use);
701 ctx->preauth_to_use = NULL;
704 if (ctx->fast_state) {
705 krb5int_fast_free_state(context, ctx->fast_state);
706 ctx->fast_state = NULL;
708 code = krb5int_fast_make_state(context, &ctx->fast_state);
711 ctx->preauth_rock.fast_state = ctx->fast_state;
712 krb5_preauth_request_context_init(context);
713 if (ctx->outer_request_body) {
714 krb5_free_data(context, ctx->outer_request_body);
715 ctx->outer_request_body = NULL;
718 (ctx->opte->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
719 if ((code = make_preauth_list(context, ctx->opte->preauth_list,
720 ctx->opte->preauth_list_length,
721 &ctx->preauth_to_use)))
725 /* Set the request nonce. */
726 random_data.length = 4;
727 random_data.data = (char *)random_buf;
728 code = krb5_c_random_make_octets(context, &random_data);
732 * See RT ticket 3196 at MIT. If we set the high bit, we may have
733 * compatibility problems with Heimdal, because we (incorrectly) encode
734 * this value as signed.
736 ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
737 krb5_free_principal(context, ctx->request->server);
738 ctx->request->server = NULL;
740 code = build_in_tkt_name(context, ctx->in_tkt_service,
741 ctx->request->client,
742 &ctx->request->server);
746 ctx->request_time = time(NULL);
748 code = krb5int_fast_as_armor(context, ctx->fast_state,
749 ctx->opte, ctx->request);
752 if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
753 code = krb5int_fast_as_armor(context, ctx->fast_state,
754 ctx->opte, ctx->request);
758 /* give the preauth plugins a chance to prep the request body */
759 krb5_preauth_prepare_request(context, ctx->opte, ctx->request);
761 ctx->request->from = krb5int_addint32(ctx->request_time,
763 ctx->request->till = krb5int_addint32(ctx->request->from,
766 if (ctx->renew_life > 0) {
767 ctx->request->rtime =
768 krb5int_addint32(ctx->request->from, ctx->renew_life);
769 if (ctx->request->rtime < ctx->request->till) {
770 /* don't ask for a smaller renewable time than the lifetime */
771 ctx->request->rtime = ctx->request->till;
773 ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
775 ctx->request->rtime = 0;
776 code = krb5int_fast_prep_req_body(context, ctx->fast_state,
778 &ctx->outer_request_body);
785 krb5_error_code KRB5_CALLCONV
786 krb5_init_creds_init(krb5_context context,
787 krb5_principal client,
788 krb5_prompter_fct prompter,
790 krb5_deltat start_time,
791 krb5_get_init_creds_opt *options,
792 krb5_init_creds_context *pctx)
794 krb5_error_code code;
795 krb5_init_creds_context ctx;
798 krb5_gic_opt_ext *opte;
799 krb5_get_init_creds_opt local_opts;
801 TRACE_INIT_CREDS(context, client);
803 ctx = k5alloc(sizeof(*ctx), &code);
807 ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
810 ctx->enc_pa_rep_permitted = 1;
811 code = krb5_copy_principal(context, client, &ctx->request->client);
815 ctx->prompter = prompter;
816 ctx->prompter_data = data;
817 ctx->gak_fct = krb5_get_as_key_password;
818 ctx->gak_data = &ctx->password;
820 ctx->request_time = 0; /* filled in later */
821 ctx->start_time = start_time;
823 if (options == NULL) {
825 * We initialize a non-extended options because that way the shadowed
826 * flag will be sent and they will be freed when the init_creds context
827 * is freed. The options will be extended and copied off the stack into
828 * storage by opt_to_opte.
830 krb5_get_init_creds_opt_init(&local_opts);
831 options = &local_opts;
834 code = krb5int_gic_opt_to_opte(context, options,
835 &ctx->opte, 1, "krb5_init_creds_init");
841 ctx->preauth_rock.magic = CLIENT_ROCK_MAGIC;
842 ctx->preauth_rock.etype = &ctx->etype;
843 ctx->preauth_rock.as_key = &ctx->as_key;
844 ctx->preauth_rock.gak_fct = &ctx->gak_fct;
845 ctx->preauth_rock.gak_data = &ctx->gak_data;
846 ctx->preauth_rock.salt = &ctx->salt;
847 ctx->preauth_rock.s2kparams = &ctx->s2kparams;
848 ctx->preauth_rock.client = client;
849 ctx->preauth_rock.prompter = prompter;
850 ctx->preauth_rock.prompter_data = data;
852 /* Initialise request parameters as per krb5_get_init_creds() */
853 ctx->request->kdc_options = context->kdc_default_options;
856 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
857 tmp = opte->forwardable;
858 else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
859 KRB5_CONF_FORWARDABLE, &tmp) == 0)
864 ctx->request->kdc_options |= KDC_OPT_FORWARDABLE;
867 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
868 tmp = opte->proxiable;
869 else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
870 KRB5_CONF_PROXIABLE, &tmp) == 0)
875 ctx->request->kdc_options |= KDC_OPT_PROXIABLE;
878 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_CANONICALIZE)
880 else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
881 KRB5_CONF_CANONICALIZE, &tmp) == 0)
886 ctx->request->kdc_options |= KDC_OPT_CANONICALIZE;
889 if (ctx->start_time > 0)
890 ctx->request->kdc_options |= KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED;
892 /* ticket lifetime */
893 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
894 ctx->tkt_life = options->tkt_life;
895 else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
896 KRB5_CONF_TICKET_LIFETIME, &str) == 0) {
897 code = krb5_string_to_deltat(str, &ctx->tkt_life);
903 ctx->tkt_life = 24 * 60 * 60; /* previously hardcoded in kinit */
905 /* renewable lifetime */
906 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)
907 ctx->renew_life = options->renew_life;
908 else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
909 KRB5_CONF_RENEW_LIFETIME, &str) == 0) {
910 code = krb5_string_to_deltat(str, &ctx->renew_life);
918 if (ctx->renew_life > 0)
919 ctx->request->kdc_options |= KDC_OPT_RENEWABLE;
922 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
923 ctx->request->ktype =
924 k5alloc((opte->etype_list_length * sizeof(krb5_enctype)),
928 ctx->request->nktypes = opte->etype_list_length;
929 memcpy(ctx->request->ktype, opte->etype_list,
930 ctx->request->nktypes * sizeof(krb5_enctype));
931 } else if (krb5_get_default_in_tkt_ktypes(context,
932 &ctx->request->ktype) == 0) {
933 ctx->request->nktypes = krb5int_count_etypes(ctx->request->ktype);
935 /* there isn't any useful default here. */
936 code = KRB5_CONFIG_ETYPE_NOSUPP;
941 * Set a default enctype for optimistic preauth. If we're not doing
942 * optimistic preauth, this should ordinarily get overwritten when we
943 * process the etype-info2 of the preauth-required error.
945 if (ctx->request->nktypes > 0)
946 ctx->etype = ctx->request->ktype[0];
949 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
950 code = krb5_copy_addresses(context, opte->address_list,
951 &ctx->request->addresses);
954 } else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
955 KRB5_CONF_NOADDRESSES, &tmp) != 0
957 ctx->request->addresses = NULL;
959 code = krb5_os_localaddr(context, &ctx->request->addresses);
964 if (opte->flags & KRB5_GET_INIT_CREDS_OPT_SALT) {
965 code = krb5int_copy_data_contents(context, opte->salt, &ctx->salt);
969 ctx->salt.length = SALT_TYPE_AFS_LENGTH;
970 ctx->salt.data = NULL;
974 if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
975 ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
976 /* Remap @REALM to WELLKNOWN/ANONYMOUS@REALM. */
977 if (client->length == 1 && client->data[0].length ==0) {
978 krb5_principal new_client;
979 code = krb5_build_principal_ext(context, &new_client,
980 client->realm.length,
982 strlen(KRB5_WELLKNOWN_NAMESTR),
983 KRB5_WELLKNOWN_NAMESTR,
984 strlen(KRB5_ANONYMOUS_PRINCSTR),
985 KRB5_ANONYMOUS_PRINCSTR,
989 krb5_free_principal(context, ctx->request->client);
990 ctx->request->client = new_client;
991 krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
994 /* We will also handle anonymous if the input principal is the anonymous
996 if (krb5_principal_compare_any_realm(context, ctx->request->client,
997 krb5_anonymous_principal())) {
998 ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
999 krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
1001 code = restart_init_creds_loop(context, ctx, NULL);
1009 krb5_init_creds_free(context, ctx);
1015 krb5_error_code KRB5_CALLCONV
1016 krb5_init_creds_set_service(krb5_context context,
1017 krb5_init_creds_context ctx,
1018 const char *service)
1022 TRACE_INIT_CREDS_SERVICE(context, service);
1024 s = strdup(service);
1028 free(ctx->in_tkt_service);
1029 ctx->in_tkt_service = s;
1031 krb5_preauth_request_context_fini(context);
1032 return restart_init_creds_loop(context, ctx, NULL);
1035 static krb5_error_code
1036 init_creds_validate_reply(krb5_context context,
1037 krb5_init_creds_context ctx,
1040 krb5_error_code code;
1041 krb5_error *error = NULL;
1042 krb5_kdc_rep *as_reply = NULL;
1044 krb5_free_error(context, ctx->err_reply);
1045 ctx->err_reply = NULL;
1047 krb5_free_kdc_rep(context, ctx->reply);
1050 if (krb5_is_krb_error(reply)) {
1051 code = decode_krb5_error(reply, &error);
1055 assert(error != NULL);
1057 TRACE_INIT_CREDS_ERROR_REPLY(context,
1058 error->error + ERROR_TABLE_BASE_krb5);
1059 if (error->error == KRB_ERR_RESPONSE_TOO_BIG) {
1060 krb5_free_error(context, error);
1061 return KRB5KRB_ERR_RESPONSE_TOO_BIG;
1063 ctx->err_reply = error;
1069 * Check to make sure it isn't a V4 reply.
1071 if (reply->length != 0 && !krb5_is_as_rep(reply)) {
1072 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1073 #define V4_KRB_PROT_VERSION 4
1074 #define V4_AUTH_MSG_ERR_REPLY (5<<1)
1075 /* check here for V4 reply */
1076 unsigned int t_switch;
1078 /* From v4 g_in_tkt.c: This used to be
1079 switch (pkt_msg_type(rpkt) & ~1) {
1080 but SCO 3.2v4 cc compiled that incorrectly. */
1081 t_switch = reply->data[1];
1084 if (t_switch == V4_AUTH_MSG_ERR_REPLY
1085 && reply->data[0] == V4_KRB_PROT_VERSION) {
1086 code = KRB5KRB_AP_ERR_V4_REPLY;
1088 code = KRB5KRB_AP_ERR_MSG_TYPE;
1093 /* It must be a KRB_AS_REP message, or an bad returned packet */
1094 code = decode_krb5_as_rep(reply, &as_reply);
1098 if (as_reply->msg_type != KRB5_AS_REP) {
1099 krb5_free_kdc_rep(context, as_reply);
1100 return KRB5KRB_AP_ERR_MSG_TYPE;
1103 ctx->reply = as_reply;
1108 static krb5_error_code
1109 init_creds_step_request(krb5_context context,
1110 krb5_init_creds_context ctx,
1113 krb5_error_code code;
1114 krb5_boolean got_real;
1116 krb5_data random_data;
1118 if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
1119 code = KRB5_GET_IN_TKT_LOOP;
1123 * RFC 6113 requires a new nonce for the inner request on each try. It's
1124 * permitted to change the nonce even for non-FAST so we do here.
1126 random_data.length = 4;
1127 random_data.data = (char *)random_buf;
1128 code = krb5_c_random_make_octets(context, &random_data);
1132 * See RT ticket 3196 at MIT. If we set the high bit, we may have
1133 * compatibility problems with Heimdal, because we (incorrectly) encode
1134 * this value as signed.
1136 ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
1137 krb5_free_data(context, ctx->inner_request_body);
1138 ctx->inner_request_body = NULL;
1139 code = encode_krb5_kdc_req_body(ctx->request, &ctx->inner_request_body);
1143 if (ctx->err_reply == NULL) {
1144 /* either our first attempt, or retrying after PREAUTH_NEEDED */
1145 code = krb5_do_preauth(context,
1147 ctx->inner_request_body,
1148 ctx->encoded_previous_request,
1149 ctx->preauth_to_use,
1150 &ctx->request->padata,
1156 if (code == 0 && !got_real && ctx->preauth_required)
1157 code = KRB5_PREAUTH_FAILED;
1161 if (ctx->preauth_to_use != NULL) {
1163 * Retry after an error other than PREAUTH_NEEDED,
1164 * using ctx->err_padata to figure out what to change.
1166 code = krb5_do_preauth_tryagain(context,
1168 ctx->inner_request_body,
1169 ctx->encoded_previous_request,
1170 ctx->preauth_to_use,
1171 &ctx->request->padata,
1179 /* No preauth supplied, so can't query the plugins. */
1180 code = KRB5KRB_ERR_GENERIC;
1183 /* couldn't come up with anything better */
1184 code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
1189 if (ctx->encoded_previous_request != NULL) {
1190 krb5_free_data(context, ctx->encoded_previous_request);
1191 ctx->encoded_previous_request = NULL;
1193 if (ctx->request->padata)
1194 ctx->sent_nontrivial_preauth = 1;
1195 if (ctx->enc_pa_rep_permitted)
1196 code = request_enc_pa_rep(&ctx->request->padata);
1199 code = krb5int_fast_prep_req(context, ctx->fast_state,
1200 ctx->request, ctx->outer_request_body,
1202 &ctx->encoded_previous_request);
1206 code = krb5int_copy_data_contents(context,
1207 ctx->encoded_previous_request,
1213 krb5_free_pa_data(context, ctx->request->padata);
1214 ctx->request->padata = NULL;
1219 * The control flow is complicated. In order to switch from non-FAST mode to
1220 * FAST mode, we need to reset our pre-authentication state. FAST negotiation
1221 * attempts to make sure we rarely have to do this. When FAST negotiation is
1222 * working, we record whether FAST is available when we obtain an armor ticket;
1223 * if so, we start out with FAST enabled . There are two complicated
1226 * First, if we get a PREAUTH_REQUIRED error including PADATA_FX_FAST back from
1227 * a KDC in a case where we were not expecting to use FAST, and we have an
1228 * armor ticket available, then we want to use FAST. That involves clearing
1229 * out the pre-auth state, reinitializing the plugins and trying again with an
1232 * Secondly, using the negotiation can cause problems with some older KDCs.
1233 * Negotiation involves including a special padata item. Some KDCs, including
1234 * MIT prior to 1.7, will return PREAUTH_FAILED rather than PREAUTH_REQUIRED in
1235 * pre-authentication is required and unknown padata are included in the
1236 * request. To make matters worse, these KDCs typically do not include a list
1237 * of padata in PREAUTH_FAILED errors. So, if we get PREAUTH_FAILED and we
1238 * generated no pre-authentication other than the negotiation then we want to
1239 * retry without negotiation. In this case it is probably also desirable to
1240 * retry with the preauth plugin state cleared.
1242 * In all these cases we should not start over more than once. Control flow is
1243 * managed by several variables.
1245 * sent_nontrivial_preauth: if true, we sent preauth other than negotiation;
1246 * no restart on PREAUTH_FAILED
1248 * KRB5INT_FAST_ARMOR_AVAIL: fast_state_flag if desired we could generate
1249 * armor; if not set, then we can't use FAST even if the KDC wants to.
1251 * have_restarted: true if we've already restarted
1254 negotiation_requests_restart(krb5_context context, krb5_init_creds_context ctx,
1255 krb5_pa_data **padata)
1257 if (ctx->have_restarted)
1259 if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
1260 TRACE_INIT_CREDS_RESTART_FAST(context);
1263 if (ctx->err_reply->error == KDC_ERR_PREAUTH_FAILED &&
1264 !ctx->sent_nontrivial_preauth) {
1265 TRACE_INIT_CREDS_RESTART_PREAUTH_FAILED(context);
1271 /* Ensure that the reply enctype was among the requested enctypes. */
1272 static krb5_error_code
1273 check_reply_enctype(krb5_init_creds_context ctx)
1277 for (i = 0; i < ctx->request->nktypes; i++) {
1278 if (ctx->request->ktype[i] == ctx->reply->enc_part.enctype)
1281 return KRB5_CONFIG_ETYPE_NOSUPP;
1284 /* Note the difference between the KDC's time, as reported to us in a
1285 * preauth-required error, and the current time. */
1287 note_req_timestamp(krb5_context kcontext, krb5_clpreauth_rock rock,
1288 krb5_timestamp kdc_time, krb5_int32 kdc_usec)
1293 if (k5_time_with_offset(0, 0, &now, &usec) != 0)
1295 rock->pa_offset = kdc_time - now;
1296 rock->pa_offset_usec = kdc_usec - usec;
1297 rock->pa_offset_state = (rock->fast_state->armor_key != NULL) ?
1298 AUTH_OFFSET : UNAUTH_OFFSET;
1301 static krb5_error_code
1302 init_creds_step_reply(krb5_context context,
1303 krb5_init_creds_context ctx,
1306 krb5_error_code code;
1307 krb5_pa_data **kdc_padata = NULL;
1308 krb5_boolean retry = FALSE;
1310 krb5_keyblock *strengthen_key = NULL;
1311 krb5_keyblock encrypting_key;
1312 krb5_boolean fast_avail, got_real;
1314 encrypting_key.length = 0;
1315 encrypting_key.contents = NULL;
1317 /* process previous KDC response */
1318 code = init_creds_validate_reply(context, ctx, in);
1322 /* per referrals draft, enterprise principals imply canonicalization */
1323 canon_flag = ((ctx->request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
1324 ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
1326 if (ctx->err_reply != NULL) {
1327 code = krb5int_fast_process_error(context, ctx->fast_state,
1328 &ctx->err_reply, &ctx->err_padata,
1332 if (negotiation_requests_restart(context, ctx, ctx->err_padata)) {
1333 ctx->have_restarted = 1;
1334 krb5_preauth_request_context_fini(context);
1335 if ((ctx->fast_state->fast_state_flags & KRB5INT_FAST_DO_FAST) ==0)
1336 ctx->enc_pa_rep_permitted = 0;
1337 code = restart_init_creds_loop(context, ctx, ctx->err_padata);
1338 krb5_free_error(context, ctx->err_reply);
1339 ctx->err_reply = NULL;
1340 krb5_free_pa_data(context, ctx->err_padata);
1341 ctx->err_padata = NULL;
1342 } else if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
1344 /* reset the list of preauth types to try */
1345 krb5_free_pa_data(context, ctx->preauth_to_use);
1346 ctx->preauth_to_use = ctx->err_padata;
1347 ctx->err_padata = NULL;
1348 note_req_timestamp(context, &ctx->preauth_rock,
1349 ctx->err_reply->stime, ctx->err_reply->susec);
1350 /* this will trigger a new call to krb5_do_preauth() */
1351 krb5_free_error(context, ctx->err_reply);
1352 ctx->err_reply = NULL;
1353 code = sort_krb5_padata_sequence(context,
1354 &ctx->request->client->realm,
1355 ctx->preauth_to_use);
1356 ctx->preauth_required = TRUE;
1358 } else if (canon_flag && ctx->err_reply->error == KDC_ERR_WRONG_REALM) {
1359 if (ctx->err_reply->client == NULL ||
1360 !krb5_princ_realm(context, ctx->err_reply->client)->length) {
1361 code = KRB5KDC_ERR_WRONG_REALM;
1364 TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm);
1365 /* Rewrite request.client with realm from error reply */
1366 krb5_free_data_contents(context, &ctx->request->client->realm);
1367 code = krb5int_copy_data_contents(context,
1368 &ctx->err_reply->client->realm,
1369 &ctx->request->client->realm);
1370 /* this will trigger a new call to krb5_do_preauth() */
1371 krb5_free_error(context, ctx->err_reply);
1372 ctx->err_reply = NULL;
1373 krb5_preauth_request_context_fini(context);
1374 /* Permit another negotiation based restart. */
1375 ctx->have_restarted = 0;
1376 ctx->sent_nontrivial_preauth = 0;
1377 code = restart_init_creds_loop(context, ctx, NULL);
1384 /* error + no hints = give up */
1385 code = (krb5_error_code)ctx->err_reply->error +
1386 ERROR_TABLE_BASE_krb5;
1390 /* Return error code, or continue with next iteration */
1394 /* We have a response. Process it. */
1395 assert(ctx->reply != NULL);
1397 /* Check for replies (likely forged) with unasked-for enctypes. */
1398 code = check_reply_enctype(ctx);
1402 /* process any preauth data in the as_reply */
1403 krb5_clear_preauth_context_use_counts(context);
1404 code = krb5int_fast_process_response(context, ctx->fast_state,
1405 ctx->reply, &strengthen_key);
1409 code = sort_krb5_padata_sequence(context, &ctx->request->client->realm,
1410 ctx->reply->padata);
1414 ctx->etype = ctx->reply->enc_part.enctype;
1416 code = krb5_do_preauth(context,
1418 ctx->inner_request_body,
1419 ctx->encoded_previous_request,
1431 * If we haven't gotten a salt from another source yet, set up one
1432 * corresponding to the client principal returned by the KDC. We
1433 * could get the same effect by passing local_as_reply->client to
1434 * gak_fct below, but that would put the canonicalized client name
1435 * in the prompt, which raises issues of needing to sanitize
1436 * unprintable characters. So for now we just let it affect the
1437 * salt. local_as_reply->client will be checked later on in
1440 if (ctx->salt.length == SALT_TYPE_AFS_LENGTH && ctx->salt.data == NULL) {
1441 code = krb5_principal2salt(context, ctx->reply->client, &ctx->salt);
1442 TRACE_INIT_CREDS_SALT_PRINC(context, &ctx->salt);
1447 /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
1448 the AS_REP comes back encrypted in the user's longterm key
1449 instead of in the SAD. If there was a SAM preauth, there
1450 will be an as_key here which will be the SAD. If that fails,
1451 use the gak_fct to get the password, and try again. */
1453 /* XXX because etypes are handled poorly (particularly wrt SAM,
1454 where the etype is fixed by the kdc), we may want to try
1455 decrypt_as_reply twice. If there's an as_key available, try
1456 it. If decrypting the as_rep fails, or if there isn't an
1457 as_key at all yet, then use the gak_fct to get one, and try
1459 if (ctx->as_key.length) {
1460 TRACE_INIT_CREDS_AS_KEY_PREAUTH(context, &ctx->as_key);
1461 code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1465 code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1467 TRACE_INIT_CREDS_PREAUTH_DECRYPT_FAIL(context, code);
1472 /* if we haven't get gotten a key, get it now */
1473 TRACE_INIT_CREDS_GAK(context, &ctx->salt, &ctx->s2kparams);
1474 code = (*ctx->gak_fct)(context, ctx->request->client,
1475 ctx->reply->enc_part.enctype,
1476 ctx->prompter, ctx->prompter_data,
1477 &ctx->salt, &ctx->s2kparams,
1478 &ctx->as_key, ctx->gak_data);
1481 TRACE_INIT_CREDS_AS_KEY_GAK(context, &ctx->as_key);
1483 code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1488 code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1493 TRACE_INIT_CREDS_DECRYPTED_REPLY(context, ctx->reply->enc_part2->session);
1495 code = krb5int_fast_verify_nego(context, ctx->fast_state,
1496 ctx->reply, ctx->encoded_previous_request,
1497 &encrypting_key, &fast_avail);
1500 code = verify_as_reply(context, ctx->request_time,
1501 ctx->request, ctx->reply);
1504 code = verify_anonymous(context, ctx->request, ctx->reply,
1509 code = stash_as_reply(context, ctx->request_time, ctx->request,
1510 ctx->reply, &ctx->cred, NULL);
1513 if (ctx->opte && ctx->opte->opt_private->out_ccache) {
1514 krb5_ccache out_ccache = ctx->opte->opt_private->out_ccache;
1515 krb5_data config_data;
1516 code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
1519 code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
1523 config_data.data = "yes";
1524 config_data.length = strlen(config_data.data);
1525 code = krb5_cc_set_config(context, out_ccache, ctx->cred.server,
1526 KRB5_CONF_FAST_AVAIL, &config_data);
1531 msg = krb5_get_error_message(context, code);
1532 krb5_set_error_message(context, code,
1533 _("%s while storing credentials"), msg);
1534 krb5_free_error_message(context, msg);
1538 krb5_preauth_request_context_fini(context);
1542 ctx->complete = TRUE;
1545 krb5_free_pa_data(context, kdc_padata);
1546 krb5_free_keyblock(context, strengthen_key);
1547 krb5_free_keyblock_contents(context, &encrypting_key);
1553 * Do next step of credentials acquisition.
1555 * On success returns 0 or KRB5KRB_ERR_RESPONSE_TOO_BIG if the request
1556 * should be sent with TCP.
1558 krb5_error_code KRB5_CALLCONV
1559 krb5_init_creds_step(krb5_context context,
1560 krb5_init_creds_context ctx,
1564 unsigned int *flags)
1566 krb5_error_code code = 0, code2;
1579 if (in->length != 0) {
1580 code = init_creds_step_reply(context, ctx, in);
1581 if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
1582 code2 = krb5int_copy_data_contents(context,
1583 ctx->encoded_previous_request,
1591 if (code != 0 || ctx->complete)
1595 code = init_creds_step_request(context, ctx, out);
1599 /* Only a new request increments the loop count, not a TCP retry */
1603 assert(ctx->request->server != NULL);
1605 code2 = krb5int_copy_data_contents(context,
1606 &ctx->request->server->realm,
1614 if (code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN) {
1617 /* See if we can produce a more detailed error message */
1618 code2 = krb5_unparse_name(context, ctx->request->client, &client_name);
1620 krb5_set_error_message(context, code,
1621 _("Client '%s' not found in Kerberos "
1622 "database"), client_name);
1623 krb5_free_unparsed_name(context, client_name);
1627 *flags = ctx->complete ? 0 : KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
1631 krb5_error_code KRB5_CALLCONV
1632 krb5int_get_init_creds(krb5_context context,
1634 krb5_principal client,
1635 krb5_prompter_fct prompter,
1636 void *prompter_data,
1637 krb5_deltat start_time,
1638 char *in_tkt_service,
1639 krb5_get_init_creds_opt *options,
1640 krb5_gic_get_as_key_fct gak_fct,
1643 krb5_kdc_rep **as_reply)
1645 krb5_error_code code;
1646 krb5_init_creds_context ctx = NULL;
1648 code = krb5_init_creds_init(context,
1658 ctx->gak_fct = gak_fct;
1659 ctx->gak_data = gak_data;
1661 if (in_tkt_service) {
1662 code = krb5_init_creds_set_service(context, ctx, in_tkt_service);
1667 code = init_creds_get(context, ctx, use_master);
1671 code = krb5_init_creds_get_creds(context, ctx, creds);
1675 if (as_reply != NULL) {
1676 *as_reply = ctx->reply;
1681 krb5_init_creds_free(context, ctx);
1687 krb5int_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
1688 krb5_flags options, krb5_address *const *addrs,
1689 krb5_enctype *ktypes,
1690 krb5_preauthtype *pre_auth_types, krb5_creds *creds)
1693 krb5_int32 starttime;
1694 krb5_get_init_creds_opt *opt;
1695 krb5_error_code retval;
1698 retval = krb5_get_init_creds_opt_alloc(context, &opt);
1703 krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
1705 i = krb5int_count_etypes(ktypes);
1707 krb5_get_init_creds_opt_set_etype_list(opt, ktypes, i);
1709 if (pre_auth_types) {
1710 for (i=0; pre_auth_types[i]; i++);
1712 krb5_get_init_creds_opt_set_preauth_list(opt, pre_auth_types, i);
1714 if (options&KDC_OPT_FORWARDABLE)
1715 krb5_get_init_creds_opt_set_forwardable(opt, 1);
1716 else krb5_get_init_creds_opt_set_forwardable(opt, 0);
1717 if (options&KDC_OPT_PROXIABLE)
1718 krb5_get_init_creds_opt_set_proxiable(opt, 1);
1719 else krb5_get_init_creds_opt_set_proxiable(opt, 0);
1720 if (creds && creds->times.endtime) {
1721 retval = krb5_timeofday(context, &starttime);
1724 if (creds->times.starttime) starttime = creds->times.starttime;
1725 krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
1731 krb5_get_init_creds_opt_free(context, opt);