8af0f5c22f553fecdd6faf80d17dbeb0bcbc36af
[krb5.git] / src / lib / krb5 / krb / get_in_tkt.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/get_in_tkt.c */
3 /*
4  * Copyright 1990,1991, 2003, 2008 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
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.
11  *
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.
25  */
26
27 #include <string.h>
28
29 #include "k5-int.h"
30 #include "int-proto.h"
31 #include "os-proto.h"
32 #include "fast.h"
33 #include "init_creds_ctx.h"
34
35 /* some typedef's for the function args to make things look a bit cleaner */
36
37 static krb5_error_code make_preauth_list (krb5_context,
38                                           krb5_preauthtype *,
39                                           int, krb5_pa_data ***);
40 static krb5_error_code sort_krb5_padata_sequence(krb5_context context,
41                                                  krb5_data *realm,
42                                                  krb5_pa_data **padata);
43
44 /*
45  * This function performs 32 bit bounded addition so we can generate
46  * lifetimes without overflowing krb5_int32
47  */
48 static krb5_int32
49 krb5int_addint32 (krb5_int32 x, krb5_int32 y)
50 {
51     if ((x > 0) && (y > (KRB5_INT32_MAX - x))) {
52         /* sum will be be greater than KRB5_INT32_MAX */
53         return KRB5_INT32_MAX;
54     } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) {
55         /* sum will be less than KRB5_INT32_MIN */
56         return KRB5_INT32_MIN;
57     }
58
59     return x + y;
60 }
61
62 static krb5_error_code
63 decrypt_as_reply(krb5_context context, krb5_kdc_req *request,
64                  krb5_kdc_rep *as_reply, krb5_keyblock *key)
65 {
66     if (as_reply->enc_part2)
67         return 0;
68
69     return krb5_kdc_rep_decrypt_proc(context, key, NULL, as_reply);
70 }
71
72 /**
73  * Fully anonymous replies include a pa_pkinit_kx padata type including the KDC
74  * contribution key.  This routine confirms that the session key is of the
75  * right form for fully anonymous requests.  It is here rather than in the
76  * preauth code because the session key cannot be verified until the AS reply
77  * is decrypted and the preauth code all runs before the AS reply is decrypted.
78  */
79 static krb5_error_code
80 verify_anonymous( krb5_context context, krb5_kdc_req *request,
81                   krb5_kdc_rep *reply, krb5_keyblock *as_key)
82 {
83     krb5_error_code ret = 0;
84     krb5_pa_data *pa;
85     krb5_data scratch;
86     krb5_keyblock *kdc_key = NULL, *expected = NULL;
87     krb5_enc_data *enc = NULL;
88     krb5_keyblock *session = reply->enc_part2->session;
89
90     if (!krb5_principal_compare_any_realm(context, request->client,
91                                           krb5_anonymous_principal()))
92         return 0; /* Only applies to fully anonymous */
93     pa = krb5int_find_pa_data(context, reply->padata, KRB5_PADATA_PKINIT_KX);
94     if (pa == NULL)
95         goto verification_error;
96     scratch.length = pa->length;
97     scratch.data = (char *) pa->contents;
98     ret = decode_krb5_enc_data( &scratch, &enc);
99     if (ret)
100         goto cleanup;
101     scratch.data = k5alloc(enc->ciphertext.length, &ret);
102     if (ret)
103         goto cleanup;
104     scratch.length = enc->ciphertext.length;
105     ret = krb5_c_decrypt(context, as_key, KRB5_KEYUSAGE_PA_PKINIT_KX,
106                          NULL /*cipherstate*/, enc, &scratch);
107     if (ret) {
108         free(scratch.data);
109         goto cleanup;
110     }
111     ret = decode_krb5_encryption_key( &scratch, &kdc_key);
112     zap(scratch.data, scratch.length);
113     free(scratch.data);
114     if (ret)
115         goto cleanup;
116     ret = krb5_c_fx_cf2_simple(context, kdc_key, "PKINIT",
117                                as_key, "KEYEXCHANGE", &expected);
118     if (ret)
119         goto cleanup;
120     if ((expected->enctype != session->enctype) ||
121         (expected->length != session->length) ||
122         (memcmp(expected->contents, session->contents, expected->length) != 0))
123         goto verification_error;
124 cleanup:
125     if (kdc_key)
126         krb5_free_keyblock(context, kdc_key);
127     if (expected)
128         krb5_free_keyblock(context, expected);
129     if (enc)
130         krb5_free_enc_data(context, enc);
131     return ret;
132 verification_error:
133     ret = KRB5_KDCREP_MODIFIED;
134     krb5_set_error_message(context, ret, _("Reply has wrong form of session "
135                                            "key for anonymous request"));
136     goto cleanup;
137 }
138
139 static krb5_error_code
140 verify_as_reply(krb5_context            context,
141                 krb5_timestamp          time_now,
142                 krb5_kdc_req            *request,
143                 krb5_kdc_rep            *as_reply)
144 {
145     krb5_error_code             retval;
146     int                         canon_req;
147     int                         canon_ok;
148     krb5_timestamp              time_offset;
149
150     /* check the contents for sanity: */
151     if (!as_reply->enc_part2->times.starttime)
152         as_reply->enc_part2->times.starttime =
153             as_reply->enc_part2->times.authtime;
154
155     /*
156      * We only allow the AS-REP server name to be changed if the
157      * caller set the canonicalize flag (or requested an enterprise
158      * principal) and we requested (and received) a TGT.
159      */
160     canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
161         (krb5_princ_type(context, request->client) ==
162          KRB5_NT_ENTERPRISE_PRINCIPAL) ||
163         (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS);
164     if (canon_req) {
165         canon_ok = IS_TGS_PRINC(context, request->server) &&
166             IS_TGS_PRINC(context, as_reply->enc_part2->server);
167         if (!canon_ok && (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS)) {
168             canon_ok = krb5_principal_compare_any_realm(context,
169                                                         as_reply->client,
170                                                         krb5_anonymous_principal());
171         }
172     } else
173         canon_ok = 0;
174
175     if ((!canon_ok &&
176          (!krb5_principal_compare(context, as_reply->client, request->client) ||
177           !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)))
178         || !krb5_principal_compare(context, as_reply->enc_part2->server, as_reply->ticket->server)
179         || (request->nonce != as_reply->enc_part2->nonce)
180         /* XXX check for extraneous flags */
181         /* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
182         || ((request->kdc_options & KDC_OPT_POSTDATED) &&
183             (request->from != 0) &&
184             (request->from != as_reply->enc_part2->times.starttime))
185         || ((request->till != 0) &&
186             (as_reply->enc_part2->times.endtime > request->till))
187         || ((request->kdc_options & KDC_OPT_RENEWABLE) &&
188             (request->rtime != 0) &&
189             (as_reply->enc_part2->times.renew_till > request->rtime))
190         || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
191             !(request->kdc_options & KDC_OPT_RENEWABLE) &&
192             (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
193             (request->till != 0) &&
194             (as_reply->enc_part2->times.renew_till > request->till))
195     ) {
196         return KRB5_KDCREP_MODIFIED;
197     }
198
199     if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
200         time_offset = as_reply->enc_part2->times.authtime - time_now;
201         retval = krb5_set_time_offsets(context, time_offset, 0);
202         if (retval)
203             return retval;
204     } else {
205         if ((request->from == 0) &&
206             (labs(as_reply->enc_part2->times.starttime - time_now)
207              > context->clockskew))
208             return (KRB5_KDCREP_SKEW);
209     }
210     return 0;
211 }
212
213 static krb5_error_code
214 stash_as_reply(krb5_context             context,
215                krb5_timestamp           time_now,
216                krb5_kdc_req             *request,
217                krb5_kdc_rep             *as_reply,
218                krb5_creds *             creds,
219                krb5_ccache              ccache)
220 {
221     krb5_error_code             retval;
222     krb5_data *                 packet;
223     krb5_principal              client;
224     krb5_principal              server;
225
226     client = NULL;
227     server = NULL;
228
229     if (!creds->client)
230         if ((retval = krb5_copy_principal(context, as_reply->client, &client)))
231             goto cleanup;
232
233     if (!creds->server)
234         if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server,
235                                           &server)))
236             goto cleanup;
237
238     /* fill in the credentials */
239     if ((retval = krb5_copy_keyblock_contents(context,
240                                               as_reply->enc_part2->session,
241                                               &creds->keyblock)))
242         goto cleanup;
243
244     creds->times = as_reply->enc_part2->times;
245     creds->is_skey = FALSE;             /* this is an AS_REQ, so cannot
246                                            be encrypted in skey */
247     creds->ticket_flags = as_reply->enc_part2->flags;
248     if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
249                                       &creds->addresses)))
250         goto cleanup;
251
252     creds->second_ticket.length = 0;
253     creds->second_ticket.data = 0;
254
255     if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
256         goto cleanup;
257
258     creds->ticket = *packet;
259     free(packet);
260
261     /* store it in the ccache! */
262     if (ccache)
263         if ((retval = krb5_cc_store_cred(context, ccache, creds)))
264             goto cleanup;
265
266     if (!creds->client)
267         creds->client = client;
268     if (!creds->server)
269         creds->server = server;
270
271 cleanup:
272     if (retval) {
273         if (client)
274             krb5_free_principal(context, client);
275         if (server)
276             krb5_free_principal(context, server);
277         if (creds->keyblock.contents) {
278             memset(creds->keyblock.contents, 0,
279                    creds->keyblock.length);
280             free(creds->keyblock.contents);
281             creds->keyblock.contents = 0;
282             creds->keyblock.length = 0;
283         }
284         if (creds->ticket.data) {
285             free(creds->ticket.data);
286             creds->ticket.data = 0;
287         }
288         if (creds->addresses) {
289             krb5_free_addresses(context, creds->addresses);
290             creds->addresses = 0;
291         }
292     }
293     return (retval);
294 }
295
296 static krb5_error_code
297 make_preauth_list(krb5_context  context,
298                   krb5_preauthtype *    ptypes,
299                   int                   nptypes,
300                   krb5_pa_data ***      ret_list)
301 {
302     krb5_preauthtype *          ptypep;
303     krb5_pa_data **             preauthp;
304     int                         i;
305
306     if (nptypes < 0) {
307         for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
308             ;
309     }
310
311     /* allocate space for a NULL to terminate the list */
312
313     if ((preauthp =
314          (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
315         return(ENOMEM);
316
317     for (i=0; i<nptypes; i++) {
318         if ((preauthp[i] =
319              (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
320             for (; i>=0; i--)
321                 free(preauthp[i]);
322             free(preauthp);
323             return (ENOMEM);
324         }
325         preauthp[i]->magic = KV5M_PA_DATA;
326         preauthp[i]->pa_type = ptypes[i];
327         preauthp[i]->length = 0;
328         preauthp[i]->contents = 0;
329     }
330
331     /* fill in the terminating NULL */
332
333     preauthp[nptypes] = NULL;
334
335     *ret_list = preauthp;
336     return 0;
337 }
338
339 #define MAX_IN_TKT_LOOPS 16
340
341 static krb5_error_code
342 request_enc_pa_rep(krb5_pa_data ***padptr)
343 {
344     size_t size = 0;
345     krb5_pa_data **pad = *padptr;
346     krb5_pa_data *pa= NULL;
347     if (pad)
348         for (size=0; pad[size]; size++);
349     pad = realloc(pad, sizeof(*pad)*(size+2));
350
351     if (pad == NULL)
352         return ENOMEM;
353     pad[size+1] = NULL;
354     pa = malloc(sizeof(krb5_pa_data));
355     if (pa == NULL)
356         return ENOMEM;
357     pa->contents = NULL;
358     pa->length = 0;
359     pa->pa_type = KRB5_ENCPADATA_REQ_ENC_PA_REP;
360     pad[size] = pa;
361     *padptr = pad;
362     return 0;
363 }
364
365 /* Sort a pa_data sequence so that types named in the "preferred_preauth_types"
366  * libdefaults entry are listed before any others. */
367 static krb5_error_code
368 sort_krb5_padata_sequence(krb5_context context, krb5_data *realm,
369                           krb5_pa_data **padata)
370 {
371     int i, j, base;
372     krb5_error_code ret;
373     const char *p;
374     long l;
375     char *q, *preauth_types = NULL;
376     krb5_pa_data *tmp;
377     int need_free_string = 1;
378
379     if ((padata == NULL) || (padata[0] == NULL)) {
380         return 0;
381     }
382
383     ret = krb5int_libdefault_string(context, realm, KRB5_CONF_PREFERRED_PREAUTH_TYPES,
384                                     &preauth_types);
385     if ((ret != 0) || (preauth_types == NULL)) {
386         /* Try to use PKINIT first. */
387         preauth_types = "17, 16, 15, 14";
388         need_free_string = 0;
389     }
390
391 #ifdef DEBUG
392     fprintf (stderr, "preauth data types before sorting:");
393     for (i = 0; padata[i]; i++) {
394         fprintf (stderr, " %d", padata[i]->pa_type);
395     }
396     fprintf (stderr, "\n");
397 #endif
398
399     base = 0;
400     for (p = preauth_types; *p != '\0';) {
401         /* skip whitespace to find an entry */
402         p += strspn(p, ", ");
403         if (*p != '\0') {
404             /* see if we can extract a number */
405             l = strtol(p, &q, 10);
406             if ((q != NULL) && (q > p)) {
407                 /* got a valid number; search for a matchin entry */
408                 for (i = base; padata[i] != NULL; i++) {
409                     /* bubble the matching entry to the front of the list */
410                     if (padata[i]->pa_type == l) {
411                         tmp = padata[i];
412                         for (j = i; j > base; j--)
413                             padata[j] = padata[j - 1];
414                         padata[base] = tmp;
415                         base++;
416                         break;
417                     }
418                 }
419                 p = q;
420             } else {
421                 break;
422             }
423         }
424     }
425     if (need_free_string)
426         free(preauth_types);
427
428 #ifdef DEBUG
429     fprintf (stderr, "preauth data types after sorting:");
430     for (i = 0; padata[i]; i++)
431         fprintf (stderr, " %d", padata[i]->pa_type);
432     fprintf (stderr, "\n");
433 #endif
434
435     return 0;
436 }
437
438 static krb5_error_code
439 build_in_tkt_name(krb5_context context,
440                   const char *in_tkt_service,
441                   krb5_const_principal client,
442                   krb5_principal *server_out)
443 {
444     krb5_error_code ret;
445     krb5_principal server = NULL;
446
447     *server_out = NULL;
448
449     if (in_tkt_service) {
450         ret = krb5_parse_name_flags(context, in_tkt_service,
451                                     KRB5_PRINCIPAL_PARSE_IGNORE_REALM,
452                                     &server);
453         if (ret)
454             return ret;
455         krb5_free_data_contents(context, &server->realm);
456         ret = krb5int_copy_data_contents(context, &client->realm,
457                                          &server->realm);
458         if (ret) {
459             krb5_free_principal(context, server);
460             return ret;
461         }
462     } else {
463         ret = krb5_build_principal_ext(context, &server,
464                                        client->realm.length,
465                                        client->realm.data,
466                                        KRB5_TGS_NAME_SIZE,
467                                        KRB5_TGS_NAME,
468                                        client->realm.length,
469                                        client->realm.data,
470                                        0);
471         if (ret)
472             return ret;
473     }
474     /*
475      * Windows Server 2008 R2 RODC insists on TGS principal names having the
476      * right name type.
477      */
478     if (krb5_princ_size(context, server) == 2 &&
479         data_eq_string(*krb5_princ_component(context, server, 0),
480                        KRB5_TGS_NAME)) {
481         krb5_princ_type(context, server) = KRB5_NT_SRV_INST;
482     }
483     *server_out = server;
484     return 0;
485 }
486
487 void KRB5_CALLCONV
488 krb5_init_creds_free(krb5_context context,
489                      krb5_init_creds_context ctx)
490 {
491     if (ctx == NULL)
492         return;
493
494     if (ctx->opte != NULL && krb5_gic_opt_is_shadowed(ctx->opte)) {
495         krb5_get_init_creds_opt_free(context,
496                                      (krb5_get_init_creds_opt *)ctx->opte);
497     }
498     free(ctx->in_tkt_service);
499     zap(ctx->password.data, ctx->password.length);
500     krb5_free_data_contents(context, &ctx->password);
501     krb5_free_error(context, ctx->err_reply);
502     krb5_free_pa_data(context, ctx->err_padata);
503     krb5_free_cred_contents(context, &ctx->cred);
504     krb5_free_kdc_req(context, ctx->request);
505     krb5_free_kdc_rep(context, ctx->reply);
506     krb5_free_data(context, ctx->outer_request_body);
507     krb5_free_data(context, ctx->inner_request_body);
508     krb5_free_data(context, ctx->encoded_previous_request);
509     krb5int_fast_free_state(context, ctx->fast_state);
510     krb5_free_pa_data(context, ctx->preauth_to_use);
511     krb5_free_data_contents(context, &ctx->salt);
512     krb5_free_data_contents(context, &ctx->s2kparams);
513     krb5_free_keyblock_contents(context, &ctx->as_key);
514     free(ctx);
515 }
516
517 krb5_error_code
518 k5_init_creds_get(krb5_context context, krb5_init_creds_context ctx,
519                   int *use_master)
520 {
521     krb5_error_code code;
522     krb5_data request;
523     krb5_data reply;
524     krb5_data realm;
525     unsigned int flags = 0;
526     int tcp_only = 0;
527
528     request.length = 0;
529     request.data = NULL;
530     reply.length = 0;
531     reply.data = NULL;
532     realm.length = 0;
533     realm.data = NULL;
534
535     for (;;) {
536         code = krb5_init_creds_step(context,
537                                     ctx,
538                                     &reply,
539                                     &request,
540                                     &realm,
541                                     &flags);
542         if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !tcp_only) {
543             TRACE_INIT_CREDS_RETRY_TCP(context);
544             tcp_only = 1;
545         } else if (code != 0 || !(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE))
546             break;
547
548         krb5_free_data_contents(context, &reply);
549
550         code = krb5_sendto_kdc(context, &request, &realm,
551                                &reply, use_master, tcp_only);
552         if (code != 0)
553             break;
554
555         krb5_free_data_contents(context, &request);
556         krb5_free_data_contents(context, &realm);
557     }
558
559     krb5_free_data_contents(context, &request);
560     krb5_free_data_contents(context, &reply);
561     krb5_free_data_contents(context, &realm);
562
563     return code;
564 }
565
566 /* Heimdal API */
567 krb5_error_code KRB5_CALLCONV
568 krb5_init_creds_get(krb5_context context,
569                     krb5_init_creds_context ctx)
570 {
571     int use_master = 0;
572
573     return k5_init_creds_get(context, ctx, &use_master);
574 }
575
576 krb5_error_code KRB5_CALLCONV
577 krb5_init_creds_get_creds(krb5_context context,
578                           krb5_init_creds_context ctx,
579                           krb5_creds *creds)
580 {
581     if (!ctx->complete)
582         return KRB5_NO_TKT_SUPPLIED;
583
584     return krb5int_copy_creds_contents(context, &ctx->cred, creds);
585 }
586
587 krb5_error_code KRB5_CALLCONV
588 krb5_init_creds_get_times(krb5_context context,
589                           krb5_init_creds_context ctx,
590                           krb5_ticket_times *times)
591 {
592     if (!ctx->complete)
593         return KRB5_NO_TKT_SUPPLIED;
594
595     *times = ctx->cred.times;
596
597     return 0;
598 }
599
600 krb5_error_code KRB5_CALLCONV
601 krb5_init_creds_get_error(krb5_context context,
602                           krb5_init_creds_context ctx,
603                           krb5_error **error)
604 {
605     krb5_error_code code;
606     krb5_error *ret = NULL;
607
608     *error = NULL;
609
610     if (ctx->err_reply == NULL)
611         return 0;
612
613     ret = k5alloc(sizeof(*ret), &code);
614     if (code != 0)
615         goto cleanup;
616
617     ret->magic = KV5M_ERROR;
618     ret->ctime = ctx->err_reply->ctime;
619     ret->cusec = ctx->err_reply->cusec;
620     ret->susec = ctx->err_reply->susec;
621     ret->stime = ctx->err_reply->stime;
622     ret->error = ctx->err_reply->error;
623
624     if (ctx->err_reply->client != NULL) {
625         code = krb5_copy_principal(context, ctx->err_reply->client,
626                                    &ret->client);
627         if (code != 0)
628             goto cleanup;
629     }
630
631     code = krb5_copy_principal(context, ctx->err_reply->server, &ret->server);
632     if (code != 0)
633         goto cleanup;
634
635     code = krb5int_copy_data_contents(context, &ctx->err_reply->text,
636                                       &ret->text);
637     if (code != 0)
638         goto cleanup;
639
640     code = krb5int_copy_data_contents(context, &ctx->err_reply->e_data,
641                                       &ret->e_data);
642     if (code != 0)
643         goto cleanup;
644
645     *error = ret;
646
647 cleanup:
648     if (code != 0)
649         krb5_free_error(context, ret);
650
651     return code;
652 }
653
654 /**
655  * Throw away any state related to specific realm either at the beginning of a
656  * request, or when a realm changes, or when we start to use FAST after
657  * assuming we would not do so.
658  *
659  * @param padata padata from an error if an error from the realm we now expect
660  * to talk to caused the restart.  Used to infer negotiation characteristics
661  * such as whether FAST is used.
662  */
663 static krb5_error_code
664 restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx,
665                         krb5_pa_data **padata)
666 {
667     krb5_error_code code = 0;
668     unsigned char random_buf[4];
669     krb5_data random_data;
670     krb5_timestamp from;
671
672     if (ctx->preauth_to_use) {
673         krb5_free_pa_data(context, ctx->preauth_to_use);
674         ctx->preauth_to_use = NULL;
675     }
676
677     if (ctx->fast_state) {
678         krb5int_fast_free_state(context, ctx->fast_state);
679         ctx->fast_state = NULL;
680     }
681     code = krb5int_fast_make_state(context, &ctx->fast_state);
682     if (code != 0)
683         goto cleanup;
684     ctx->preauth_rock.fast_state = ctx->fast_state;
685     krb5_preauth_request_context_init(context);
686     if (ctx->outer_request_body) {
687         krb5_free_data(context, ctx->outer_request_body);
688         ctx->outer_request_body = NULL;
689     }
690     if (ctx->opte &&
691         (ctx->opte->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
692         if ((code = make_preauth_list(context, ctx->opte->preauth_list,
693                                       ctx->opte->preauth_list_length,
694                                       &ctx->preauth_to_use)))
695             goto cleanup;
696     }
697
698     /* Set the request nonce. */
699     random_data.length = 4;
700     random_data.data = (char *)random_buf;
701     code = krb5_c_random_make_octets(context, &random_data);
702     if (code !=0)
703         goto cleanup;
704     /*
705      * See RT ticket 3196 at MIT.  If we set the high bit, we may have
706      * compatibility problems with Heimdal, because we (incorrectly) encode
707      * this value as signed.
708      */
709     ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
710     krb5_free_principal(context, ctx->request->server);
711     ctx->request->server = NULL;
712
713     code = build_in_tkt_name(context, ctx->in_tkt_service,
714                              ctx->request->client,
715                              &ctx->request->server);
716     if (code != 0)
717         goto cleanup;
718
719     ctx->request_time = time(NULL);
720
721     code = krb5int_fast_as_armor(context, ctx->fast_state,
722                                  ctx->opte, ctx->request);
723     if (code != 0)
724         goto cleanup;
725     if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
726         code = krb5int_fast_as_armor(context, ctx->fast_state,
727                                      ctx->opte, ctx->request);
728         if (code != 0)
729             goto cleanup;
730     }
731     /* give the preauth plugins a chance to prep the request body */
732     krb5_preauth_prepare_request(context, ctx->opte, ctx->request);
733
734     /* Omit request start time in the common case.  MIT and Heimdal KDCs will
735      * ignore it for non-postdated tickets anyway. */
736     from = krb5int_addint32(ctx->request_time, ctx->start_time);
737     if (ctx->start_time != 0)
738         ctx->request->from = from;
739     ctx->request->till = krb5int_addint32(from, ctx->tkt_life);
740
741     if (ctx->renew_life > 0) {
742         ctx->request->rtime =
743             krb5int_addint32(from, ctx->renew_life);
744         if (ctx->request->rtime < ctx->request->till) {
745             /* don't ask for a smaller renewable time than the lifetime */
746             ctx->request->rtime = ctx->request->till;
747         }
748         ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
749     } else
750         ctx->request->rtime = 0;
751     code = krb5int_fast_prep_req_body(context, ctx->fast_state,
752                                       ctx->request,
753                                       &ctx->outer_request_body);
754     if (code != 0)
755         goto cleanup;
756 cleanup:
757     return code;
758 }
759
760 krb5_error_code KRB5_CALLCONV
761 krb5_init_creds_init(krb5_context context,
762                      krb5_principal client,
763                      krb5_prompter_fct prompter,
764                      void *data,
765                      krb5_deltat start_time,
766                      krb5_get_init_creds_opt *options,
767                      krb5_init_creds_context *pctx)
768 {
769     krb5_error_code code;
770     krb5_init_creds_context ctx;
771     int tmp;
772     char *str = NULL;
773     krb5_gic_opt_ext *opte;
774     krb5_get_init_creds_opt local_opts;
775
776     TRACE_INIT_CREDS(context, client);
777
778     ctx = k5alloc(sizeof(*ctx), &code);
779     if (code != 0)
780         goto cleanup;
781
782     ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
783     if (code != 0)
784         goto cleanup;
785     ctx->enc_pa_rep_permitted = 1;
786     code = krb5_copy_principal(context, client, &ctx->request->client);
787     if (code != 0)
788         goto cleanup;
789
790     ctx->prompter = prompter;
791     ctx->prompter_data = data;
792     ctx->gak_fct = krb5_get_as_key_password;
793     ctx->gak_data = &ctx->password;
794
795     ctx->request_time = 0; /* filled in later */
796     ctx->start_time = start_time;
797
798     if (options == NULL) {
799         /*
800          * We initialize a non-extended options because that way the shadowed
801          * flag will be sent and they will be freed when the init_creds context
802          * is freed. The options will be extended and copied off the stack into
803          * storage by opt_to_opte.
804          */
805         krb5_get_init_creds_opt_init(&local_opts);
806         options = &local_opts;
807     }
808
809     code = krb5int_gic_opt_to_opte(context, options,
810                                    &ctx->opte, 1, "krb5_init_creds_init");
811     if (code != 0)
812         goto cleanup;
813
814     opte = ctx->opte;
815
816     ctx->preauth_rock.magic = CLIENT_ROCK_MAGIC;
817     ctx->preauth_rock.etype = &ctx->etype;
818     ctx->preauth_rock.as_key = &ctx->as_key;
819     ctx->preauth_rock.gak_fct = &ctx->gak_fct;
820     ctx->preauth_rock.gak_data = &ctx->gak_data;
821     ctx->preauth_rock.default_salt = &ctx->default_salt;
822     ctx->preauth_rock.salt = &ctx->salt;
823     ctx->preauth_rock.s2kparams = &ctx->s2kparams;
824     ctx->preauth_rock.client = client;
825     ctx->preauth_rock.prompter = prompter;
826     ctx->preauth_rock.prompter_data = data;
827
828     /* Initialise request parameters as per krb5_get_init_creds() */
829     ctx->request->kdc_options = context->kdc_default_options;
830
831     /* forwaradble */
832     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
833         tmp = opte->forwardable;
834     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
835                                         KRB5_CONF_FORWARDABLE, &tmp) == 0)
836         ;
837     else
838         tmp = 0;
839     if (tmp)
840         ctx->request->kdc_options |= KDC_OPT_FORWARDABLE;
841
842     /* proxiable */
843     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
844         tmp = opte->proxiable;
845     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
846                                         KRB5_CONF_PROXIABLE, &tmp) == 0)
847         ;
848     else
849         tmp = 0;
850     if (tmp)
851         ctx->request->kdc_options |= KDC_OPT_PROXIABLE;
852
853     /* canonicalize */
854     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_CANONICALIZE)
855         tmp = 1;
856     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
857                                         KRB5_CONF_CANONICALIZE, &tmp) == 0)
858         ;
859     else
860         tmp = 0;
861     if (tmp)
862         ctx->request->kdc_options |= KDC_OPT_CANONICALIZE;
863
864     /* allow_postdate */
865     if (ctx->start_time > 0)
866         ctx->request->kdc_options |= KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED;
867
868     /* ticket lifetime */
869     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
870         ctx->tkt_life = options->tkt_life;
871     else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
872                                        KRB5_CONF_TICKET_LIFETIME, &str) == 0) {
873         code = krb5_string_to_deltat(str, &ctx->tkt_life);
874         if (code != 0)
875             goto cleanup;
876         free(str);
877         str = NULL;
878     } else
879         ctx->tkt_life = 24 * 60 * 60; /* previously hardcoded in kinit */
880
881     /* renewable lifetime */
882     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)
883         ctx->renew_life = options->renew_life;
884     else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
885                                        KRB5_CONF_RENEW_LIFETIME, &str) == 0) {
886         code = krb5_string_to_deltat(str, &ctx->renew_life);
887         if (code != 0)
888             goto cleanup;
889         free(str);
890         str = NULL;
891     } else
892         ctx->renew_life = 0;
893
894     if (ctx->renew_life > 0)
895         ctx->request->kdc_options |= KDC_OPT_RENEWABLE;
896
897     /* enctypes */
898     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
899         ctx->request->ktype =
900             k5alloc((opte->etype_list_length * sizeof(krb5_enctype)),
901                     &code);
902         if (code != 0)
903             goto cleanup;
904         ctx->request->nktypes = opte->etype_list_length;
905         memcpy(ctx->request->ktype, opte->etype_list,
906                ctx->request->nktypes * sizeof(krb5_enctype));
907     } else if (krb5_get_default_in_tkt_ktypes(context,
908                                               &ctx->request->ktype) == 0) {
909         ctx->request->nktypes = krb5int_count_etypes(ctx->request->ktype);
910     } else {
911         /* there isn't any useful default here. */
912         code = KRB5_CONFIG_ETYPE_NOSUPP;
913         goto cleanup;
914     }
915
916     /*
917      * Set a default enctype for optimistic preauth.  If we're not doing
918      * optimistic preauth, this should ordinarily get overwritten when we
919      * process the etype-info2 of the preauth-required error.
920      */
921     if (ctx->request->nktypes > 0)
922         ctx->etype = ctx->request->ktype[0];
923
924     /* addresess */
925     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
926         code = krb5_copy_addresses(context, opte->address_list,
927                                    &ctx->request->addresses);
928         if (code != 0)
929             goto cleanup;
930     } else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
931                                           KRB5_CONF_NOADDRESSES, &tmp) != 0
932                || tmp) {
933         ctx->request->addresses = NULL;
934     } else {
935         code = krb5_os_localaddr(context, &ctx->request->addresses);
936         if (code != 0)
937             goto cleanup;
938     }
939
940     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_SALT) {
941         code = krb5int_copy_data_contents(context, opte->salt, &ctx->salt);
942         if (code != 0)
943             goto cleanup;
944         ctx->default_salt = FALSE;
945     } else {
946         ctx->salt = empty_data();
947         ctx->default_salt = TRUE;
948     }
949
950     /* Anonymous. */
951     if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
952         ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
953         /* Remap @REALM to WELLKNOWN/ANONYMOUS@REALM. */
954         if (client->length == 1 && client->data[0].length ==0) {
955             krb5_principal new_client;
956             code = krb5_build_principal_ext(context, &new_client,
957                                             client->realm.length,
958                                             client->realm.data,
959                                             strlen(KRB5_WELLKNOWN_NAMESTR),
960                                             KRB5_WELLKNOWN_NAMESTR,
961                                             strlen(KRB5_ANONYMOUS_PRINCSTR),
962                                             KRB5_ANONYMOUS_PRINCSTR,
963                                             0);
964             if (code)
965                 goto cleanup;
966             krb5_free_principal(context, ctx->request->client);
967             ctx->request->client = new_client;
968             krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
969         }
970     }
971     /* We will also handle anonymous if the input principal is the anonymous
972      * principal. */
973     if (krb5_principal_compare_any_realm(context, ctx->request->client,
974                                          krb5_anonymous_principal())) {
975         ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
976         krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
977     }
978     code = restart_init_creds_loop(context, ctx, NULL);
979     if (code)
980         goto cleanup;
981
982     *pctx = ctx;
983     ctx = NULL;
984
985 cleanup:
986     krb5_init_creds_free(context, ctx);
987     free(str);
988
989     return code;
990 }
991
992 krb5_error_code KRB5_CALLCONV
993 krb5_init_creds_set_service(krb5_context context,
994                             krb5_init_creds_context ctx,
995                             const char *service)
996 {
997     char *s;
998
999     TRACE_INIT_CREDS_SERVICE(context, service);
1000
1001     s = strdup(service);
1002     if (s == NULL)
1003         return ENOMEM;
1004
1005     free(ctx->in_tkt_service);
1006     ctx->in_tkt_service = s;
1007
1008     krb5_preauth_request_context_fini(context);
1009     return restart_init_creds_loop(context, ctx, NULL);
1010 }
1011
1012 static krb5_error_code
1013 init_creds_validate_reply(krb5_context context,
1014                           krb5_init_creds_context ctx,
1015                           krb5_data *reply)
1016 {
1017     krb5_error_code code;
1018     krb5_error *error = NULL;
1019     krb5_kdc_rep *as_reply = NULL;
1020
1021     krb5_free_error(context, ctx->err_reply);
1022     ctx->err_reply = NULL;
1023
1024     krb5_free_kdc_rep(context, ctx->reply);
1025     ctx->reply = NULL;
1026
1027     if (krb5_is_krb_error(reply)) {
1028         code = decode_krb5_error(reply, &error);
1029         if (code != 0)
1030             return code;
1031
1032         assert(error != NULL);
1033
1034         TRACE_INIT_CREDS_ERROR_REPLY(context,
1035                                      error->error + ERROR_TABLE_BASE_krb5);
1036         if (error->error == KRB_ERR_RESPONSE_TOO_BIG) {
1037             krb5_free_error(context, error);
1038             return KRB5KRB_ERR_RESPONSE_TOO_BIG;
1039         } else {
1040             ctx->err_reply = error;
1041             return 0;
1042         }
1043     }
1044
1045     /*
1046      * Check to make sure it isn't a V4 reply.
1047      */
1048     if (reply->length != 0 && !krb5_is_as_rep(reply)) {
1049 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1050 #define V4_KRB_PROT_VERSION     4
1051 #define V4_AUTH_MSG_ERR_REPLY   (5<<1)
1052         /* check here for V4 reply */
1053         unsigned int t_switch;
1054
1055         /* From v4 g_in_tkt.c: This used to be
1056            switch (pkt_msg_type(rpkt) & ~1) {
1057            but SCO 3.2v4 cc compiled that incorrectly.  */
1058         t_switch = reply->data[1];
1059         t_switch &= ~1;
1060
1061         if (t_switch == V4_AUTH_MSG_ERR_REPLY
1062             && reply->data[0] == V4_KRB_PROT_VERSION) {
1063             code = KRB5KRB_AP_ERR_V4_REPLY;
1064         } else {
1065             code = KRB5KRB_AP_ERR_MSG_TYPE;
1066         }
1067         return code;
1068     }
1069
1070     /* It must be a KRB_AS_REP message, or an bad returned packet */
1071     code = decode_krb5_as_rep(reply, &as_reply);
1072     if (code != 0)
1073         return code;
1074
1075     if (as_reply->msg_type != KRB5_AS_REP) {
1076         krb5_free_kdc_rep(context, as_reply);
1077         return KRB5KRB_AP_ERR_MSG_TYPE;
1078     }
1079
1080     ctx->reply = as_reply;
1081
1082     return 0;
1083 }
1084
1085 static krb5_error_code
1086 init_creds_step_request(krb5_context context,
1087                         krb5_init_creds_context ctx,
1088                         krb5_data *out)
1089 {
1090     krb5_error_code code;
1091     krb5_boolean got_real;
1092     char random_buf[4];
1093     krb5_data random_data;
1094
1095     if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
1096         code = KRB5_GET_IN_TKT_LOOP;
1097         goto cleanup;
1098     }
1099     /*
1100      * RFC 6113 requires a new nonce for the inner request on each try. It's
1101      * permitted to change the nonce even for non-FAST so we do here.
1102      */
1103     random_data.length = 4;
1104     random_data.data = (char *)random_buf;
1105     code = krb5_c_random_make_octets(context, &random_data);
1106     if (code !=0)
1107         goto cleanup;
1108     /*
1109      * See RT ticket 3196 at MIT.  If we set the high bit, we may have
1110      * compatibility problems with Heimdal, because we (incorrectly) encode
1111      * this value as signed.
1112      */
1113     ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
1114     krb5_free_data(context, ctx->inner_request_body);
1115     ctx->inner_request_body = NULL;
1116     code = encode_krb5_kdc_req_body(ctx->request, &ctx->inner_request_body);
1117     if (code)
1118         goto cleanup;
1119
1120     if (ctx->err_reply == NULL) {
1121         /* either our first attempt, or retrying after PREAUTH_NEEDED */
1122         code = krb5_do_preauth(context,
1123                                ctx->request,
1124                                ctx->inner_request_body,
1125                                ctx->encoded_previous_request,
1126                                ctx->preauth_to_use,
1127                                &ctx->request->padata,
1128                                ctx->prompter,
1129                                ctx->prompter_data,
1130                                &ctx->preauth_rock,
1131                                ctx->opte,
1132                                &got_real);
1133         if (code == 0 && !got_real && ctx->preauth_required)
1134             code = KRB5_PREAUTH_FAILED;
1135         if (code != 0)
1136             goto cleanup;
1137     } else {
1138         if (ctx->preauth_to_use != NULL) {
1139             /*
1140              * Retry after an error other than PREAUTH_NEEDED,
1141              * using ctx->err_padata to figure out what to change.
1142              */
1143             code = krb5_do_preauth_tryagain(context,
1144                                             ctx->request,
1145                                             ctx->inner_request_body,
1146                                             ctx->encoded_previous_request,
1147                                             ctx->preauth_to_use,
1148                                             &ctx->request->padata,
1149                                             ctx->err_reply,
1150                                             ctx->err_padata,
1151                                             ctx->prompter,
1152                                             ctx->prompter_data,
1153                                             &ctx->preauth_rock,
1154                                             ctx->opte);
1155         } else {
1156             /* No preauth supplied, so can't query the plugins. */
1157             code = KRB5KRB_ERR_GENERIC;
1158         }
1159         if (code != 0) {
1160             /* couldn't come up with anything better */
1161             code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
1162             goto cleanup;
1163         }
1164     }
1165
1166     if (ctx->encoded_previous_request != NULL) {
1167         krb5_free_data(context, ctx->encoded_previous_request);
1168         ctx->encoded_previous_request = NULL;
1169     }
1170     if (ctx->request->padata)
1171         ctx->sent_nontrivial_preauth = 1;
1172     if (ctx->enc_pa_rep_permitted)
1173         code = request_enc_pa_rep(&ctx->request->padata);
1174     if (code)
1175         goto cleanup;
1176     code = krb5int_fast_prep_req(context, ctx->fast_state,
1177                                  ctx->request, ctx->outer_request_body,
1178                                  encode_krb5_as_req,
1179                                  &ctx->encoded_previous_request);
1180     if (code != 0)
1181         goto cleanup;
1182
1183     code = krb5int_copy_data_contents(context,
1184                                       ctx->encoded_previous_request,
1185                                       out);
1186     if (code != 0)
1187         goto cleanup;
1188
1189 cleanup:
1190     krb5_free_pa_data(context, ctx->request->padata);
1191     ctx->request->padata = NULL;
1192     return code;
1193 }
1194
1195 /*
1196  * The control flow is complicated.  In order to switch from non-FAST mode to
1197  * FAST mode, we need to reset our pre-authentication state.  FAST negotiation
1198  * attempts to make sure we rarely have to do this.  When FAST negotiation is
1199  * working, we record whether FAST is available when we obtain an armor ticket;
1200  * if so, we start out with FAST enabled .  There are two complicated
1201  * situations.
1202  *
1203  * First, if we get a PREAUTH_REQUIRED error including PADATA_FX_FAST back from
1204  * a KDC in a case where we were not expecting to use FAST, and we have an
1205  * armor ticket available, then we want to use FAST.  That involves clearing
1206  * out the pre-auth state, reinitializing the plugins and trying again with an
1207  * armor key.
1208  *
1209  * Secondly, using the negotiation can cause problems with some older KDCs.
1210  * Negotiation involves including a special padata item.  Some KDCs, including
1211  * MIT prior to 1.7, will return PREAUTH_FAILED rather than PREAUTH_REQUIRED in
1212  * pre-authentication is required and unknown padata are included in the
1213  * request.  To make matters worse, these KDCs typically do not include a list
1214  * of padata in PREAUTH_FAILED errors.  So, if we get PREAUTH_FAILED and we
1215  * generated no pre-authentication other than the negotiation then we want to
1216  * retry without negotiation.  In this case it is probably also desirable to
1217  * retry with the preauth plugin state cleared.
1218  *
1219  * In all these cases we should not start over more than once.  Control flow is
1220  * managed by several variables.
1221  *
1222  *   sent_nontrivial_preauth: if true, we sent preauth other than negotiation;
1223  *   no restart on PREAUTH_FAILED
1224  *
1225  *   KRB5INT_FAST_ARMOR_AVAIL: fast_state_flag if desired we could generate
1226  *   armor; if not set, then we can't use FAST even if the KDC wants to.
1227  *
1228  *   have_restarted: true if we've already restarted
1229  */
1230 static krb5_boolean
1231 negotiation_requests_restart(krb5_context context, krb5_init_creds_context ctx,
1232                              krb5_pa_data **padata)
1233 {
1234     if (ctx->have_restarted)
1235         return FALSE;
1236     if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
1237         TRACE_INIT_CREDS_RESTART_FAST(context);
1238         return TRUE;
1239     }
1240     if (ctx->err_reply->error == KDC_ERR_PREAUTH_FAILED &&
1241         !ctx->sent_nontrivial_preauth) {
1242         TRACE_INIT_CREDS_RESTART_PREAUTH_FAILED(context);
1243         return TRUE;
1244     }
1245     return FALSE;
1246 }
1247
1248 /* Ensure that the reply enctype was among the requested enctypes. */
1249 static krb5_error_code
1250 check_reply_enctype(krb5_init_creds_context ctx)
1251 {
1252     int i;
1253
1254     for (i = 0; i < ctx->request->nktypes; i++) {
1255         if (ctx->request->ktype[i] == ctx->reply->enc_part.enctype)
1256             return 0;
1257     }
1258     return KRB5_CONFIG_ETYPE_NOSUPP;
1259 }
1260
1261 /* Note the difference between the KDC's time, as reported to us in a
1262  * preauth-required error, and the current time. */
1263 static void
1264 note_req_timestamp(krb5_context kcontext, krb5_clpreauth_rock rock,
1265                    krb5_timestamp kdc_time, krb5_int32 kdc_usec)
1266 {
1267     krb5_timestamp now;
1268     krb5_int32 usec;
1269
1270     if (k5_time_with_offset(0, 0, &now, &usec) != 0)
1271         return;
1272     rock->pa_offset = kdc_time - now;
1273     rock->pa_offset_usec = kdc_usec - usec;
1274     rock->pa_offset_state = (rock->fast_state->armor_key != NULL) ?
1275         AUTH_OFFSET : UNAUTH_OFFSET;
1276 }
1277
1278 static krb5_error_code
1279 init_creds_step_reply(krb5_context context,
1280                       krb5_init_creds_context ctx,
1281                       krb5_data *in)
1282 {
1283     krb5_error_code code;
1284     krb5_pa_data **kdc_padata = NULL;
1285     krb5_boolean retry = FALSE;
1286     int canon_flag = 0;
1287     krb5_keyblock *strengthen_key = NULL;
1288     krb5_keyblock encrypting_key;
1289     krb5_boolean fast_avail, got_real;
1290
1291     encrypting_key.length = 0;
1292     encrypting_key.contents = NULL;
1293
1294     /* process previous KDC response */
1295     code = init_creds_validate_reply(context, ctx, in);
1296     if (code != 0)
1297         goto cleanup;
1298
1299     /* per referrals draft, enterprise principals imply canonicalization */
1300     canon_flag = ((ctx->request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
1301         ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
1302
1303     if (ctx->err_reply != NULL) {
1304         code = krb5int_fast_process_error(context, ctx->fast_state,
1305                                           &ctx->err_reply, &ctx->err_padata,
1306                                           &retry);
1307         if (code != 0)
1308             goto cleanup;
1309         if (negotiation_requests_restart(context, ctx, ctx->err_padata)) {
1310             ctx->have_restarted = 1;
1311             krb5_preauth_request_context_fini(context);
1312             if ((ctx->fast_state->fast_state_flags & KRB5INT_FAST_DO_FAST) ==0)
1313                 ctx->enc_pa_rep_permitted = 0;
1314             code = restart_init_creds_loop(context, ctx, ctx->err_padata);
1315             krb5_free_error(context, ctx->err_reply);
1316             ctx->err_reply = NULL;
1317             krb5_free_pa_data(context, ctx->err_padata);
1318             ctx->err_padata = NULL;
1319         } else if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
1320                    retry) {
1321             /* reset the list of preauth types to try */
1322             krb5_free_pa_data(context, ctx->preauth_to_use);
1323             ctx->preauth_to_use = ctx->err_padata;
1324             ctx->err_padata = NULL;
1325             note_req_timestamp(context, &ctx->preauth_rock,
1326                                ctx->err_reply->stime, ctx->err_reply->susec);
1327             /* this will trigger a new call to krb5_do_preauth() */
1328             krb5_free_error(context, ctx->err_reply);
1329             ctx->err_reply = NULL;
1330             code = sort_krb5_padata_sequence(context,
1331                                              &ctx->request->client->realm,
1332                                              ctx->preauth_to_use);
1333             ctx->preauth_required = TRUE;
1334
1335         } else if (canon_flag && ctx->err_reply->error == KDC_ERR_WRONG_REALM) {
1336             if (ctx->err_reply->client == NULL ||
1337                 !krb5_princ_realm(context, ctx->err_reply->client)->length) {
1338                 code = KRB5KDC_ERR_WRONG_REALM;
1339                 goto cleanup;
1340             }
1341             TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm);
1342             /* Rewrite request.client with realm from error reply */
1343             krb5_free_data_contents(context, &ctx->request->client->realm);
1344             code = krb5int_copy_data_contents(context,
1345                                               &ctx->err_reply->client->realm,
1346                                               &ctx->request->client->realm);
1347             /* this will trigger a new call to krb5_do_preauth() */
1348             krb5_free_error(context, ctx->err_reply);
1349             ctx->err_reply = NULL;
1350             krb5_preauth_request_context_fini(context);
1351             /* Permit another negotiation based restart. */
1352             ctx->have_restarted = 0;
1353             ctx->sent_nontrivial_preauth = 0;
1354             code = restart_init_creds_loop(context, ctx, NULL);
1355             if (code != 0)
1356                 goto cleanup;
1357         } else {
1358             if (retry) {
1359                 code = 0;
1360             } else {
1361                 /* error + no hints = give up */
1362                 code = (krb5_error_code)ctx->err_reply->error +
1363                     ERROR_TABLE_BASE_krb5;
1364             }
1365         }
1366
1367         /* Return error code, or continue with next iteration */
1368         goto cleanup;
1369     }
1370
1371     /* We have a response. Process it. */
1372     assert(ctx->reply != NULL);
1373
1374     /* Check for replies (likely forged) with unasked-for enctypes. */
1375     code = check_reply_enctype(ctx);
1376     if (code != 0)
1377         goto cleanup;
1378
1379     /* process any preauth data in the as_reply */
1380     krb5_clear_preauth_context_use_counts(context);
1381     code = krb5int_fast_process_response(context, ctx->fast_state,
1382                                          ctx->reply, &strengthen_key);
1383     if (code != 0)
1384         goto cleanup;
1385
1386     code = sort_krb5_padata_sequence(context, &ctx->request->client->realm,
1387                                      ctx->reply->padata);
1388     if (code != 0)
1389         goto cleanup;
1390
1391     ctx->etype = ctx->reply->enc_part.enctype;
1392
1393     code = krb5_do_preauth(context,
1394                            ctx->request,
1395                            ctx->inner_request_body,
1396                            ctx->encoded_previous_request,
1397                            ctx->reply->padata,
1398                            &kdc_padata,
1399                            ctx->prompter,
1400                            ctx->prompter_data,
1401                            &ctx->preauth_rock,
1402                            ctx->opte,
1403                            &got_real);
1404     if (code != 0)
1405         goto cleanup;
1406
1407     /*
1408      * If we haven't gotten a salt from another source yet, set up one
1409      * corresponding to the client principal returned by the KDC.  We
1410      * could get the same effect by passing local_as_reply->client to
1411      * gak_fct below, but that would put the canonicalized client name
1412      * in the prompt, which raises issues of needing to sanitize
1413      * unprintable characters.  So for now we just let it affect the
1414      * salt.  local_as_reply->client will be checked later on in
1415      * verify_as_reply.
1416      */
1417     if (ctx->default_salt) {
1418         code = krb5_principal2salt(context, ctx->reply->client, &ctx->salt);
1419         TRACE_INIT_CREDS_SALT_PRINC(context, &ctx->salt);
1420         if (code != 0)
1421             goto cleanup;
1422     }
1423
1424     /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
1425        the AS_REP comes back encrypted in the user's longterm key
1426        instead of in the SAD. If there was a SAM preauth, there
1427        will be an as_key here which will be the SAD. If that fails,
1428        use the gak_fct to get the password, and try again. */
1429
1430     /* XXX because etypes are handled poorly (particularly wrt SAM,
1431        where the etype is fixed by the kdc), we may want to try
1432        decrypt_as_reply twice.  If there's an as_key available, try
1433        it.  If decrypting the as_rep fails, or if there isn't an
1434        as_key at all yet, then use the gak_fct to get one, and try
1435        again.  */
1436     if (ctx->as_key.length) {
1437         TRACE_INIT_CREDS_AS_KEY_PREAUTH(context, &ctx->as_key);
1438         code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1439                                       &encrypting_key);
1440         if (code != 0)
1441             goto cleanup;
1442         code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1443         if (code != 0)
1444             TRACE_INIT_CREDS_PREAUTH_DECRYPT_FAIL(context, code);
1445     } else
1446         code = -1;
1447
1448     if (code != 0) {
1449         /* if we haven't get gotten a key, get it now */
1450         TRACE_INIT_CREDS_GAK(context, &ctx->salt, &ctx->s2kparams);
1451         code = (*ctx->gak_fct)(context, ctx->request->client,
1452                                ctx->reply->enc_part.enctype,
1453                                ctx->prompter, ctx->prompter_data,
1454                                &ctx->salt, &ctx->s2kparams,
1455                                &ctx->as_key, ctx->gak_data);
1456         if (code != 0)
1457             goto cleanup;
1458         TRACE_INIT_CREDS_AS_KEY_GAK(context, &ctx->as_key);
1459
1460         code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1461                                       &encrypting_key);
1462         if (code != 0)
1463             goto cleanup;
1464
1465         code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1466         if (code != 0)
1467             goto cleanup;
1468     }
1469
1470     TRACE_INIT_CREDS_DECRYPTED_REPLY(context, ctx->reply->enc_part2->session);
1471
1472     code = krb5int_fast_verify_nego(context, ctx->fast_state,
1473                                     ctx->reply, ctx->encoded_previous_request,
1474                                     &encrypting_key, &fast_avail);
1475     if (code)
1476         goto cleanup;
1477     code = verify_as_reply(context, ctx->request_time,
1478                            ctx->request, ctx->reply);
1479     if (code != 0)
1480         goto cleanup;
1481     code = verify_anonymous(context, ctx->request, ctx->reply,
1482                             &ctx->as_key);
1483     if (code)
1484         goto cleanup;
1485
1486     code = stash_as_reply(context, ctx->request_time, ctx->request,
1487                           ctx->reply, &ctx->cred, NULL);
1488     if (code != 0)
1489         goto cleanup;
1490     if (ctx->opte && ctx->opte->opt_private->out_ccache) {
1491         krb5_ccache out_ccache = ctx->opte->opt_private->out_ccache;
1492         krb5_data config_data;
1493         code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
1494         if (code != 0)
1495             goto cc_cleanup;
1496         code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
1497         if (code != 0)
1498             goto cc_cleanup;
1499         if (fast_avail) {
1500             config_data.data = "yes";
1501             config_data.length = strlen(config_data.data);
1502             code = krb5_cc_set_config(context, out_ccache, ctx->cred.server,
1503                                       KRB5_CONF_FAST_AVAIL, &config_data);
1504         }
1505     cc_cleanup:
1506         if (code !=0) {
1507             const char *msg;
1508             msg = krb5_get_error_message(context, code);
1509             krb5_set_error_message(context, code,
1510                                    _("%s while storing credentials"), msg);
1511             krb5_free_error_message(context, msg);
1512         }
1513     }
1514
1515     krb5_preauth_request_context_fini(context);
1516
1517     /* success */
1518     code = 0;
1519     ctx->complete = TRUE;
1520
1521 cleanup:
1522     krb5_free_pa_data(context, kdc_padata);
1523     krb5_free_keyblock(context, strengthen_key);
1524     krb5_free_keyblock_contents(context, &encrypting_key);
1525
1526     return code;
1527 }
1528
1529 /*
1530  * Do next step of credentials acquisition.
1531  *
1532  * On success returns 0 or KRB5KRB_ERR_RESPONSE_TOO_BIG if the request
1533  * should be sent with TCP.
1534  */
1535 krb5_error_code KRB5_CALLCONV
1536 krb5_init_creds_step(krb5_context context,
1537                      krb5_init_creds_context ctx,
1538                      krb5_data *in,
1539                      krb5_data *out,
1540                      krb5_data *realm,
1541                      unsigned int *flags)
1542 {
1543     krb5_error_code code = 0, code2;
1544
1545     *flags = 0;
1546
1547     out->data = NULL;
1548     out->length = 0;
1549
1550     realm->data = NULL;
1551     realm->length = 0;
1552
1553     if (ctx->complete)
1554         return EINVAL;
1555
1556     if (in->length != 0) {
1557         code = init_creds_step_reply(context, ctx, in);
1558         if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
1559             code2 = krb5int_copy_data_contents(context,
1560                                                ctx->encoded_previous_request,
1561                                                out);
1562             if (code2 != 0) {
1563                 code = code2;
1564                 goto cleanup;
1565             }
1566             goto copy_realm;
1567         }
1568         if (code != 0 || ctx->complete)
1569             goto cleanup;
1570     }
1571
1572     code = init_creds_step_request(context, ctx, out);
1573     if (code != 0)
1574         goto cleanup;
1575
1576     /* Only a new request increments the loop count, not a TCP retry */
1577     ctx->loopcount++;
1578
1579 copy_realm:
1580     assert(ctx->request->server != NULL);
1581
1582     code2 = krb5int_copy_data_contents(context,
1583                                        &ctx->request->server->realm,
1584                                        realm);
1585     if (code2 != 0) {
1586         code = code2;
1587         goto cleanup;
1588     }
1589
1590 cleanup:
1591     if (code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN) {
1592         char *client_name;
1593
1594         /* See if we can produce a more detailed error message */
1595         code2 = krb5_unparse_name(context, ctx->request->client, &client_name);
1596         if (code2 == 0) {
1597             krb5_set_error_message(context, code,
1598                                    _("Client '%s' not found in Kerberos "
1599                                      "database"), client_name);
1600             krb5_free_unparsed_name(context, client_name);
1601         }
1602     }
1603
1604     *flags = ctx->complete ? 0 : KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
1605     return code;
1606 }
1607
1608 krb5_error_code KRB5_CALLCONV
1609 krb5int_get_init_creds(krb5_context context,
1610                        krb5_creds *creds,
1611                        krb5_principal client,
1612                        krb5_prompter_fct prompter,
1613                        void *prompter_data,
1614                        krb5_deltat start_time,
1615                        const char *in_tkt_service,
1616                        krb5_get_init_creds_opt *options,
1617                        krb5_gic_get_as_key_fct gak_fct,
1618                        void *gak_data,
1619                        int  *use_master,
1620                        krb5_kdc_rep **as_reply)
1621 {
1622     krb5_error_code code;
1623     krb5_init_creds_context ctx = NULL;
1624
1625     code = krb5_init_creds_init(context,
1626                                 client,
1627                                 prompter,
1628                                 prompter_data,
1629                                 start_time,
1630                                 options,
1631                                 &ctx);
1632     if (code != 0)
1633         goto cleanup;
1634
1635     ctx->gak_fct = gak_fct;
1636     ctx->gak_data = gak_data;
1637
1638     if (in_tkt_service) {
1639         code = krb5_init_creds_set_service(context, ctx, in_tkt_service);
1640         if (code != 0)
1641             goto cleanup;
1642     }
1643
1644     code = k5_init_creds_get(context, ctx, use_master);
1645     if (code != 0)
1646         goto cleanup;
1647
1648     code = krb5_init_creds_get_creds(context, ctx, creds);
1649     if (code != 0)
1650         goto cleanup;
1651
1652     if (as_reply != NULL) {
1653         *as_reply = ctx->reply;
1654         ctx->reply = NULL;
1655     }
1656
1657 cleanup:
1658     krb5_init_creds_free(context, ctx);
1659
1660     return code;
1661 }
1662
1663 krb5_error_code
1664 krb5int_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
1665                          krb5_flags options, krb5_address *const *addrs,
1666                          krb5_enctype *ktypes,
1667                          krb5_preauthtype *pre_auth_types, krb5_creds *creds)
1668 {
1669     int i;
1670     krb5_int32 starttime;
1671     krb5_get_init_creds_opt *opt;
1672     krb5_error_code retval;
1673
1674     *out = NULL;
1675     retval = krb5_get_init_creds_opt_alloc(context, &opt);
1676     if (retval)
1677         return(retval);
1678
1679     if (addrs)
1680         krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
1681     if (ktypes) {
1682         i = krb5int_count_etypes(ktypes);
1683         if (i)
1684             krb5_get_init_creds_opt_set_etype_list(opt, ktypes, i);
1685     }
1686     if (pre_auth_types) {
1687         for (i=0; pre_auth_types[i]; i++);
1688         if (i)
1689             krb5_get_init_creds_opt_set_preauth_list(opt, pre_auth_types, i);
1690     }
1691     if (options&KDC_OPT_FORWARDABLE)
1692         krb5_get_init_creds_opt_set_forwardable(opt, 1);
1693     else krb5_get_init_creds_opt_set_forwardable(opt, 0);
1694     if (options&KDC_OPT_PROXIABLE)
1695         krb5_get_init_creds_opt_set_proxiable(opt, 1);
1696     else krb5_get_init_creds_opt_set_proxiable(opt, 0);
1697     if (creds && creds->times.endtime) {
1698         retval = krb5_timeofday(context, &starttime);
1699         if (retval)
1700             goto cleanup;
1701         if (creds->times.starttime) starttime = creds->times.starttime;
1702         krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
1703     }
1704     *out = opt;
1705     return 0;
1706
1707 cleanup:
1708     krb5_get_init_creds_opt_free(context, opt);
1709     return retval;
1710 }