Stop using SALT_TYPE_AFS_LENGTH
[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                   char *in_tkt_service,
441                   krb5_const_principal client,
442                   krb5_principal *server)
443 {
444     krb5_error_code ret;
445
446     *server = NULL;
447
448     if (in_tkt_service) {
449         /* this is ugly, because so are the data structures involved.  I'm
450            in the library, so I'm going to manipulate the data structures
451            directly, otherwise, it will be worse. */
452
453         if ((ret = krb5_parse_name(context, in_tkt_service, server)))
454             return ret;
455
456         /* stuff the client realm into the server principal.
457            realloc if necessary */
458         if ((*server)->realm.length < client->realm.length) {
459             char *p = realloc((*server)->realm.data,
460                               client->realm.length);
461             if (p == NULL) {
462                 krb5_free_principal(context, *server);
463                 *server = NULL;
464                 return ENOMEM;
465             }
466             (*server)->realm.data = p;
467         }
468
469         (*server)->realm.length = client->realm.length;
470         memcpy((*server)->realm.data, client->realm.data, client->realm.length);
471     } else {
472         ret = krb5_build_principal_ext(context, server,
473                                        client->realm.length,
474                                        client->realm.data,
475                                        KRB5_TGS_NAME_SIZE,
476                                        KRB5_TGS_NAME,
477                                        client->realm.length,
478                                        client->realm.data,
479                                        0);
480         if (ret)
481             return ret;
482     }
483     /*
484      * Windows Server 2008 R2 RODC insists on TGS principal names having the
485      * right name type.
486      */
487     if (krb5_princ_size(context, *server) == 2 &&
488         data_eq_string(*krb5_princ_component(context, *server, 0),
489                        KRB5_TGS_NAME)) {
490         krb5_princ_type(context, *server) = KRB5_NT_SRV_INST;
491     }
492     return 0;
493 }
494
495 void KRB5_CALLCONV
496 krb5_init_creds_free(krb5_context context,
497                      krb5_init_creds_context ctx)
498 {
499     if (ctx == NULL)
500         return;
501
502     if (ctx->opte != NULL && krb5_gic_opt_is_shadowed(ctx->opte)) {
503         krb5_get_init_creds_opt_free(context,
504                                      (krb5_get_init_creds_opt *)ctx->opte);
505     }
506     free(ctx->in_tkt_service);
507     zap(ctx->password.data, ctx->password.length);
508     krb5_free_data_contents(context, &ctx->password);
509     krb5_free_error(context, ctx->err_reply);
510     krb5_free_pa_data(context, ctx->err_padata);
511     krb5_free_cred_contents(context, &ctx->cred);
512     krb5_free_kdc_req(context, ctx->request);
513     krb5_free_kdc_rep(context, ctx->reply);
514     krb5_free_data(context, ctx->outer_request_body);
515     krb5_free_data(context, ctx->inner_request_body);
516     krb5_free_data(context, ctx->encoded_previous_request);
517     krb5int_fast_free_state(context, ctx->fast_state);
518     krb5_free_pa_data(context, ctx->preauth_to_use);
519     krb5_free_data_contents(context, &ctx->salt);
520     krb5_free_data_contents(context, &ctx->s2kparams);
521     krb5_free_keyblock_contents(context, &ctx->as_key);
522     free(ctx);
523 }
524
525 krb5_error_code
526 k5_init_creds_get(krb5_context context, krb5_init_creds_context ctx,
527                   int *use_master)
528 {
529     krb5_error_code code;
530     krb5_data request;
531     krb5_data reply;
532     krb5_data realm;
533     unsigned int flags = 0;
534     int tcp_only = 0;
535
536     request.length = 0;
537     request.data = NULL;
538     reply.length = 0;
539     reply.data = NULL;
540     realm.length = 0;
541     realm.data = NULL;
542
543     for (;;) {
544         code = krb5_init_creds_step(context,
545                                     ctx,
546                                     &reply,
547                                     &request,
548                                     &realm,
549                                     &flags);
550         if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !tcp_only) {
551             TRACE_INIT_CREDS_RETRY_TCP(context);
552             tcp_only = 1;
553         } else if (code != 0 || !(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE))
554             break;
555
556         krb5_free_data_contents(context, &reply);
557
558         code = krb5_sendto_kdc(context, &request, &realm,
559                                &reply, use_master, tcp_only);
560         if (code != 0)
561             break;
562
563         krb5_free_data_contents(context, &request);
564         krb5_free_data_contents(context, &realm);
565     }
566
567     krb5_free_data_contents(context, &request);
568     krb5_free_data_contents(context, &reply);
569     krb5_free_data_contents(context, &realm);
570
571     return code;
572 }
573
574 /* Heimdal API */
575 krb5_error_code KRB5_CALLCONV
576 krb5_init_creds_get(krb5_context context,
577                     krb5_init_creds_context ctx)
578 {
579     int use_master = 0;
580
581     return k5_init_creds_get(context, ctx, &use_master);
582 }
583
584 krb5_error_code KRB5_CALLCONV
585 krb5_init_creds_get_creds(krb5_context context,
586                           krb5_init_creds_context ctx,
587                           krb5_creds *creds)
588 {
589     if (!ctx->complete)
590         return KRB5_NO_TKT_SUPPLIED;
591
592     return krb5int_copy_creds_contents(context, &ctx->cred, creds);
593 }
594
595 krb5_error_code KRB5_CALLCONV
596 krb5_init_creds_get_times(krb5_context context,
597                           krb5_init_creds_context ctx,
598                           krb5_ticket_times *times)
599 {
600     if (!ctx->complete)
601         return KRB5_NO_TKT_SUPPLIED;
602
603     *times = ctx->cred.times;
604
605     return 0;
606 }
607
608 krb5_error_code KRB5_CALLCONV
609 krb5_init_creds_get_error(krb5_context context,
610                           krb5_init_creds_context ctx,
611                           krb5_error **error)
612 {
613     krb5_error_code code;
614     krb5_error *ret = NULL;
615
616     *error = NULL;
617
618     if (ctx->err_reply == NULL)
619         return 0;
620
621     ret = k5alloc(sizeof(*ret), &code);
622     if (code != 0)
623         goto cleanup;
624
625     ret->magic = KV5M_ERROR;
626     ret->ctime = ctx->err_reply->ctime;
627     ret->cusec = ctx->err_reply->cusec;
628     ret->susec = ctx->err_reply->susec;
629     ret->stime = ctx->err_reply->stime;
630     ret->error = ctx->err_reply->error;
631
632     if (ctx->err_reply->client != NULL) {
633         code = krb5_copy_principal(context, ctx->err_reply->client,
634                                    &ret->client);
635         if (code != 0)
636             goto cleanup;
637     }
638
639     code = krb5_copy_principal(context, ctx->err_reply->server, &ret->server);
640     if (code != 0)
641         goto cleanup;
642
643     code = krb5int_copy_data_contents(context, &ctx->err_reply->text,
644                                       &ret->text);
645     if (code != 0)
646         goto cleanup;
647
648     code = krb5int_copy_data_contents(context, &ctx->err_reply->e_data,
649                                       &ret->e_data);
650     if (code != 0)
651         goto cleanup;
652
653     *error = ret;
654
655 cleanup:
656     if (code != 0)
657         krb5_free_error(context, ret);
658
659     return code;
660 }
661
662 /**
663  * Throw away any state related to specific realm either at the beginning of a
664  * request, or when a realm changes, or when we start to use FAST after
665  * assuming we would not do so.
666  *
667  * @param padata padata from an error if an error from the realm we now expect
668  * to talk to caused the restart.  Used to infer negotiation characteristics
669  * such as whether FAST is used.
670  */
671 static krb5_error_code
672 restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx,
673                         krb5_pa_data **padata)
674 {
675     krb5_error_code code = 0;
676     unsigned char random_buf[4];
677     krb5_data random_data;
678     if (ctx->preauth_to_use) {
679         krb5_free_pa_data(context, ctx->preauth_to_use);
680         ctx->preauth_to_use = NULL;
681     }
682
683     if (ctx->fast_state) {
684         krb5int_fast_free_state(context, ctx->fast_state);
685         ctx->fast_state = NULL;
686     }
687     code = krb5int_fast_make_state(context, &ctx->fast_state);
688     if (code != 0)
689         goto cleanup;
690     ctx->preauth_rock.fast_state = ctx->fast_state;
691     krb5_preauth_request_context_init(context);
692     if (ctx->outer_request_body) {
693         krb5_free_data(context, ctx->outer_request_body);
694         ctx->outer_request_body = NULL;
695     }
696     if (ctx->opte &&
697         (ctx->opte->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
698         if ((code = make_preauth_list(context, ctx->opte->preauth_list,
699                                       ctx->opte->preauth_list_length,
700                                       &ctx->preauth_to_use)))
701             goto cleanup;
702     }
703
704     /* Set the request nonce. */
705     random_data.length = 4;
706     random_data.data = (char *)random_buf;
707     code = krb5_c_random_make_octets(context, &random_data);
708     if (code !=0)
709         goto cleanup;
710     /*
711      * See RT ticket 3196 at MIT.  If we set the high bit, we may have
712      * compatibility problems with Heimdal, because we (incorrectly) encode
713      * this value as signed.
714      */
715     ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
716     krb5_free_principal(context, ctx->request->server);
717     ctx->request->server = NULL;
718
719     code = build_in_tkt_name(context, ctx->in_tkt_service,
720                              ctx->request->client,
721                              &ctx->request->server);
722     if (code != 0)
723         goto cleanup;
724
725     ctx->request_time = time(NULL);
726
727     code = krb5int_fast_as_armor(context, ctx->fast_state,
728                                  ctx->opte, ctx->request);
729     if (code != 0)
730         goto cleanup;
731     if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
732         code = krb5int_fast_as_armor(context, ctx->fast_state,
733                                      ctx->opte, ctx->request);
734         if (code != 0)
735             goto cleanup;
736     }
737     /* give the preauth plugins a chance to prep the request body */
738     krb5_preauth_prepare_request(context, ctx->opte, ctx->request);
739
740     ctx->request->from = krb5int_addint32(ctx->request_time,
741                                           ctx->start_time);
742     ctx->request->till = krb5int_addint32(ctx->request->from,
743                                           ctx->tkt_life);
744
745     if (ctx->renew_life > 0) {
746         ctx->request->rtime =
747             krb5int_addint32(ctx->request->from, ctx->renew_life);
748         if (ctx->request->rtime < ctx->request->till) {
749             /* don't ask for a smaller renewable time than the lifetime */
750             ctx->request->rtime = ctx->request->till;
751         }
752         ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
753     } else
754         ctx->request->rtime = 0;
755     code = krb5int_fast_prep_req_body(context, ctx->fast_state,
756                                       ctx->request,
757                                       &ctx->outer_request_body);
758     if (code != 0)
759         goto cleanup;
760 cleanup:
761     return code;
762 }
763
764 krb5_error_code KRB5_CALLCONV
765 krb5_init_creds_init(krb5_context context,
766                      krb5_principal client,
767                      krb5_prompter_fct prompter,
768                      void *data,
769                      krb5_deltat start_time,
770                      krb5_get_init_creds_opt *options,
771                      krb5_init_creds_context *pctx)
772 {
773     krb5_error_code code;
774     krb5_init_creds_context ctx;
775     int tmp;
776     char *str = NULL;
777     krb5_gic_opt_ext *opte;
778     krb5_get_init_creds_opt local_opts;
779
780     TRACE_INIT_CREDS(context, client);
781
782     ctx = k5alloc(sizeof(*ctx), &code);
783     if (code != 0)
784         goto cleanup;
785
786     ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
787     if (code != 0)
788         goto cleanup;
789     ctx->enc_pa_rep_permitted = 1;
790     code = krb5_copy_principal(context, client, &ctx->request->client);
791     if (code != 0)
792         goto cleanup;
793
794     ctx->prompter = prompter;
795     ctx->prompter_data = data;
796     ctx->gak_fct = krb5_get_as_key_password;
797     ctx->gak_data = &ctx->password;
798
799     ctx->request_time = 0; /* filled in later */
800     ctx->start_time = start_time;
801
802     if (options == NULL) {
803         /*
804          * We initialize a non-extended options because that way the shadowed
805          * flag will be sent and they will be freed when the init_creds context
806          * is freed. The options will be extended and copied off the stack into
807          * storage by opt_to_opte.
808          */
809         krb5_get_init_creds_opt_init(&local_opts);
810         options = &local_opts;
811     }
812
813     code = krb5int_gic_opt_to_opte(context, options,
814                                    &ctx->opte, 1, "krb5_init_creds_init");
815     if (code != 0)
816         goto cleanup;
817
818     opte = ctx->opte;
819
820     ctx->preauth_rock.magic = CLIENT_ROCK_MAGIC;
821     ctx->preauth_rock.etype = &ctx->etype;
822     ctx->preauth_rock.as_key = &ctx->as_key;
823     ctx->preauth_rock.gak_fct = &ctx->gak_fct;
824     ctx->preauth_rock.gak_data = &ctx->gak_data;
825     ctx->preauth_rock.default_salt = &ctx->default_salt;
826     ctx->preauth_rock.salt = &ctx->salt;
827     ctx->preauth_rock.s2kparams = &ctx->s2kparams;
828     ctx->preauth_rock.client = client;
829     ctx->preauth_rock.prompter = prompter;
830     ctx->preauth_rock.prompter_data = data;
831
832     /* Initialise request parameters as per krb5_get_init_creds() */
833     ctx->request->kdc_options = context->kdc_default_options;
834
835     /* forwaradble */
836     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
837         tmp = opte->forwardable;
838     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
839                                         KRB5_CONF_FORWARDABLE, &tmp) == 0)
840         ;
841     else
842         tmp = 0;
843     if (tmp)
844         ctx->request->kdc_options |= KDC_OPT_FORWARDABLE;
845
846     /* proxiable */
847     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
848         tmp = opte->proxiable;
849     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
850                                         KRB5_CONF_PROXIABLE, &tmp) == 0)
851         ;
852     else
853         tmp = 0;
854     if (tmp)
855         ctx->request->kdc_options |= KDC_OPT_PROXIABLE;
856
857     /* canonicalize */
858     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_CANONICALIZE)
859         tmp = 1;
860     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
861                                         KRB5_CONF_CANONICALIZE, &tmp) == 0)
862         ;
863     else
864         tmp = 0;
865     if (tmp)
866         ctx->request->kdc_options |= KDC_OPT_CANONICALIZE;
867
868     /* allow_postdate */
869     if (ctx->start_time > 0)
870         ctx->request->kdc_options |= KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED;
871
872     /* ticket lifetime */
873     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
874         ctx->tkt_life = options->tkt_life;
875     else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
876                                        KRB5_CONF_TICKET_LIFETIME, &str) == 0) {
877         code = krb5_string_to_deltat(str, &ctx->tkt_life);
878         if (code != 0)
879             goto cleanup;
880         free(str);
881         str = NULL;
882     } else
883         ctx->tkt_life = 24 * 60 * 60; /* previously hardcoded in kinit */
884
885     /* renewable lifetime */
886     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)
887         ctx->renew_life = options->renew_life;
888     else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
889                                        KRB5_CONF_RENEW_LIFETIME, &str) == 0) {
890         code = krb5_string_to_deltat(str, &ctx->renew_life);
891         if (code != 0)
892             goto cleanup;
893         free(str);
894         str = NULL;
895     } else
896         ctx->renew_life = 0;
897
898     if (ctx->renew_life > 0)
899         ctx->request->kdc_options |= KDC_OPT_RENEWABLE;
900
901     /* enctypes */
902     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
903         ctx->request->ktype =
904             k5alloc((opte->etype_list_length * sizeof(krb5_enctype)),
905                     &code);
906         if (code != 0)
907             goto cleanup;
908         ctx->request->nktypes = opte->etype_list_length;
909         memcpy(ctx->request->ktype, opte->etype_list,
910                ctx->request->nktypes * sizeof(krb5_enctype));
911     } else if (krb5_get_default_in_tkt_ktypes(context,
912                                               &ctx->request->ktype) == 0) {
913         ctx->request->nktypes = krb5int_count_etypes(ctx->request->ktype);
914     } else {
915         /* there isn't any useful default here. */
916         code = KRB5_CONFIG_ETYPE_NOSUPP;
917         goto cleanup;
918     }
919
920     /*
921      * Set a default enctype for optimistic preauth.  If we're not doing
922      * optimistic preauth, this should ordinarily get overwritten when we
923      * process the etype-info2 of the preauth-required error.
924      */
925     if (ctx->request->nktypes > 0)
926         ctx->etype = ctx->request->ktype[0];
927
928     /* addresess */
929     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
930         code = krb5_copy_addresses(context, opte->address_list,
931                                    &ctx->request->addresses);
932         if (code != 0)
933             goto cleanup;
934     } else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
935                                           KRB5_CONF_NOADDRESSES, &tmp) != 0
936                || tmp) {
937         ctx->request->addresses = NULL;
938     } else {
939         code = krb5_os_localaddr(context, &ctx->request->addresses);
940         if (code != 0)
941             goto cleanup;
942     }
943
944     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_SALT) {
945         code = krb5int_copy_data_contents(context, opte->salt, &ctx->salt);
946         if (code != 0)
947             goto cleanup;
948         ctx->default_salt = FALSE;
949     } else {
950         ctx->salt = empty_data();
951         ctx->default_salt = TRUE;
952     }
953
954     /* Anonymous. */
955     if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
956         ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
957         /* Remap @REALM to WELLKNOWN/ANONYMOUS@REALM. */
958         if (client->length == 1 && client->data[0].length ==0) {
959             krb5_principal new_client;
960             code = krb5_build_principal_ext(context, &new_client,
961                                             client->realm.length,
962                                             client->realm.data,
963                                             strlen(KRB5_WELLKNOWN_NAMESTR),
964                                             KRB5_WELLKNOWN_NAMESTR,
965                                             strlen(KRB5_ANONYMOUS_PRINCSTR),
966                                             KRB5_ANONYMOUS_PRINCSTR,
967                                             0);
968             if (code)
969                 goto cleanup;
970             krb5_free_principal(context, ctx->request->client);
971             ctx->request->client = new_client;
972             krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
973         }
974     }
975     /* We will also handle anonymous if the input principal is the anonymous
976      * principal. */
977     if (krb5_principal_compare_any_realm(context, ctx->request->client,
978                                          krb5_anonymous_principal())) {
979         ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
980         krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
981     }
982     code = restart_init_creds_loop(context, ctx, NULL);
983     if (code)
984         goto cleanup;
985
986     *pctx = ctx;
987     ctx = NULL;
988
989 cleanup:
990     krb5_init_creds_free(context, ctx);
991     free(str);
992
993     return code;
994 }
995
996 krb5_error_code KRB5_CALLCONV
997 krb5_init_creds_set_service(krb5_context context,
998                             krb5_init_creds_context ctx,
999                             const char *service)
1000 {
1001     char *s;
1002
1003     TRACE_INIT_CREDS_SERVICE(context, service);
1004
1005     s = strdup(service);
1006     if (s == NULL)
1007         return ENOMEM;
1008
1009     free(ctx->in_tkt_service);
1010     ctx->in_tkt_service = s;
1011
1012     krb5_preauth_request_context_fini(context);
1013     return restart_init_creds_loop(context, ctx, NULL);
1014 }
1015
1016 static krb5_error_code
1017 init_creds_validate_reply(krb5_context context,
1018                           krb5_init_creds_context ctx,
1019                           krb5_data *reply)
1020 {
1021     krb5_error_code code;
1022     krb5_error *error = NULL;
1023     krb5_kdc_rep *as_reply = NULL;
1024
1025     krb5_free_error(context, ctx->err_reply);
1026     ctx->err_reply = NULL;
1027
1028     krb5_free_kdc_rep(context, ctx->reply);
1029     ctx->reply = NULL;
1030
1031     if (krb5_is_krb_error(reply)) {
1032         code = decode_krb5_error(reply, &error);
1033         if (code != 0)
1034             return code;
1035
1036         assert(error != NULL);
1037
1038         TRACE_INIT_CREDS_ERROR_REPLY(context,
1039                                      error->error + ERROR_TABLE_BASE_krb5);
1040         if (error->error == KRB_ERR_RESPONSE_TOO_BIG) {
1041             krb5_free_error(context, error);
1042             return KRB5KRB_ERR_RESPONSE_TOO_BIG;
1043         } else {
1044             ctx->err_reply = error;
1045             return 0;
1046         }
1047     }
1048
1049     /*
1050      * Check to make sure it isn't a V4 reply.
1051      */
1052     if (reply->length != 0 && !krb5_is_as_rep(reply)) {
1053 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1054 #define V4_KRB_PROT_VERSION     4
1055 #define V4_AUTH_MSG_ERR_REPLY   (5<<1)
1056         /* check here for V4 reply */
1057         unsigned int t_switch;
1058
1059         /* From v4 g_in_tkt.c: This used to be
1060            switch (pkt_msg_type(rpkt) & ~1) {
1061            but SCO 3.2v4 cc compiled that incorrectly.  */
1062         t_switch = reply->data[1];
1063         t_switch &= ~1;
1064
1065         if (t_switch == V4_AUTH_MSG_ERR_REPLY
1066             && reply->data[0] == V4_KRB_PROT_VERSION) {
1067             code = KRB5KRB_AP_ERR_V4_REPLY;
1068         } else {
1069             code = KRB5KRB_AP_ERR_MSG_TYPE;
1070         }
1071         return code;
1072     }
1073
1074     /* It must be a KRB_AS_REP message, or an bad returned packet */
1075     code = decode_krb5_as_rep(reply, &as_reply);
1076     if (code != 0)
1077         return code;
1078
1079     if (as_reply->msg_type != KRB5_AS_REP) {
1080         krb5_free_kdc_rep(context, as_reply);
1081         return KRB5KRB_AP_ERR_MSG_TYPE;
1082     }
1083
1084     ctx->reply = as_reply;
1085
1086     return 0;
1087 }
1088
1089 static krb5_error_code
1090 init_creds_step_request(krb5_context context,
1091                         krb5_init_creds_context ctx,
1092                         krb5_data *out)
1093 {
1094     krb5_error_code code;
1095     krb5_boolean got_real;
1096     char random_buf[4];
1097     krb5_data random_data;
1098
1099     if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
1100         code = KRB5_GET_IN_TKT_LOOP;
1101         goto cleanup;
1102     }
1103     /*
1104      * RFC 6113 requires a new nonce for the inner request on each try. It's
1105      * permitted to change the nonce even for non-FAST so we do here.
1106      */
1107     random_data.length = 4;
1108     random_data.data = (char *)random_buf;
1109     code = krb5_c_random_make_octets(context, &random_data);
1110     if (code !=0)
1111         goto cleanup;
1112     /*
1113      * See RT ticket 3196 at MIT.  If we set the high bit, we may have
1114      * compatibility problems with Heimdal, because we (incorrectly) encode
1115      * this value as signed.
1116      */
1117     ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
1118     krb5_free_data(context, ctx->inner_request_body);
1119     ctx->inner_request_body = NULL;
1120     code = encode_krb5_kdc_req_body(ctx->request, &ctx->inner_request_body);
1121     if (code)
1122         goto cleanup;
1123
1124     if (ctx->err_reply == NULL) {
1125         /* either our first attempt, or retrying after PREAUTH_NEEDED */
1126         code = krb5_do_preauth(context,
1127                                ctx->request,
1128                                ctx->inner_request_body,
1129                                ctx->encoded_previous_request,
1130                                ctx->preauth_to_use,
1131                                &ctx->request->padata,
1132                                ctx->prompter,
1133                                ctx->prompter_data,
1134                                &ctx->preauth_rock,
1135                                ctx->opte,
1136                                &got_real);
1137         if (code == 0 && !got_real && ctx->preauth_required)
1138             code = KRB5_PREAUTH_FAILED;
1139         if (code != 0)
1140             goto cleanup;
1141     } else {
1142         if (ctx->preauth_to_use != NULL) {
1143             /*
1144              * Retry after an error other than PREAUTH_NEEDED,
1145              * using ctx->err_padata to figure out what to change.
1146              */
1147             code = krb5_do_preauth_tryagain(context,
1148                                             ctx->request,
1149                                             ctx->inner_request_body,
1150                                             ctx->encoded_previous_request,
1151                                             ctx->preauth_to_use,
1152                                             &ctx->request->padata,
1153                                             ctx->err_reply,
1154                                             ctx->err_padata,
1155                                             ctx->prompter,
1156                                             ctx->prompter_data,
1157                                             &ctx->preauth_rock,
1158                                             ctx->opte);
1159         } else {
1160             /* No preauth supplied, so can't query the plugins. */
1161             code = KRB5KRB_ERR_GENERIC;
1162         }
1163         if (code != 0) {
1164             /* couldn't come up with anything better */
1165             code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
1166             goto cleanup;
1167         }
1168     }
1169
1170     if (ctx->encoded_previous_request != NULL) {
1171         krb5_free_data(context, ctx->encoded_previous_request);
1172         ctx->encoded_previous_request = NULL;
1173     }
1174     if (ctx->request->padata)
1175         ctx->sent_nontrivial_preauth = 1;
1176     if (ctx->enc_pa_rep_permitted)
1177         code = request_enc_pa_rep(&ctx->request->padata);
1178     if (code)
1179         goto cleanup;
1180     code = krb5int_fast_prep_req(context, ctx->fast_state,
1181                                  ctx->request, ctx->outer_request_body,
1182                                  encode_krb5_as_req,
1183                                  &ctx->encoded_previous_request);
1184     if (code != 0)
1185         goto cleanup;
1186
1187     code = krb5int_copy_data_contents(context,
1188                                       ctx->encoded_previous_request,
1189                                       out);
1190     if (code != 0)
1191         goto cleanup;
1192
1193 cleanup:
1194     krb5_free_pa_data(context, ctx->request->padata);
1195     ctx->request->padata = NULL;
1196     return code;
1197 }
1198
1199 /*
1200  * The control flow is complicated.  In order to switch from non-FAST mode to
1201  * FAST mode, we need to reset our pre-authentication state.  FAST negotiation
1202  * attempts to make sure we rarely have to do this.  When FAST negotiation is
1203  * working, we record whether FAST is available when we obtain an armor ticket;
1204  * if so, we start out with FAST enabled .  There are two complicated
1205  * situations.
1206  *
1207  * First, if we get a PREAUTH_REQUIRED error including PADATA_FX_FAST back from
1208  * a KDC in a case where we were not expecting to use FAST, and we have an
1209  * armor ticket available, then we want to use FAST.  That involves clearing
1210  * out the pre-auth state, reinitializing the plugins and trying again with an
1211  * armor key.
1212  *
1213  * Secondly, using the negotiation can cause problems with some older KDCs.
1214  * Negotiation involves including a special padata item.  Some KDCs, including
1215  * MIT prior to 1.7, will return PREAUTH_FAILED rather than PREAUTH_REQUIRED in
1216  * pre-authentication is required and unknown padata are included in the
1217  * request.  To make matters worse, these KDCs typically do not include a list
1218  * of padata in PREAUTH_FAILED errors.  So, if we get PREAUTH_FAILED and we
1219  * generated no pre-authentication other than the negotiation then we want to
1220  * retry without negotiation.  In this case it is probably also desirable to
1221  * retry with the preauth plugin state cleared.
1222  *
1223  * In all these cases we should not start over more than once.  Control flow is
1224  * managed by several variables.
1225  *
1226  *   sent_nontrivial_preauth: if true, we sent preauth other than negotiation;
1227  *   no restart on PREAUTH_FAILED
1228  *
1229  *   KRB5INT_FAST_ARMOR_AVAIL: fast_state_flag if desired we could generate
1230  *   armor; if not set, then we can't use FAST even if the KDC wants to.
1231  *
1232  *   have_restarted: true if we've already restarted
1233  */
1234 static krb5_boolean
1235 negotiation_requests_restart(krb5_context context, krb5_init_creds_context ctx,
1236                              krb5_pa_data **padata)
1237 {
1238     if (ctx->have_restarted)
1239         return FALSE;
1240     if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
1241         TRACE_INIT_CREDS_RESTART_FAST(context);
1242         return TRUE;
1243     }
1244     if (ctx->err_reply->error == KDC_ERR_PREAUTH_FAILED &&
1245         !ctx->sent_nontrivial_preauth) {
1246         TRACE_INIT_CREDS_RESTART_PREAUTH_FAILED(context);
1247         return TRUE;
1248     }
1249     return FALSE;
1250 }
1251
1252 /* Ensure that the reply enctype was among the requested enctypes. */
1253 static krb5_error_code
1254 check_reply_enctype(krb5_init_creds_context ctx)
1255 {
1256     int i;
1257
1258     for (i = 0; i < ctx->request->nktypes; i++) {
1259         if (ctx->request->ktype[i] == ctx->reply->enc_part.enctype)
1260             return 0;
1261     }
1262     return KRB5_CONFIG_ETYPE_NOSUPP;
1263 }
1264
1265 /* Note the difference between the KDC's time, as reported to us in a
1266  * preauth-required error, and the current time. */
1267 static void
1268 note_req_timestamp(krb5_context kcontext, krb5_clpreauth_rock rock,
1269                    krb5_timestamp kdc_time, krb5_int32 kdc_usec)
1270 {
1271     krb5_timestamp now;
1272     krb5_int32 usec;
1273
1274     if (k5_time_with_offset(0, 0, &now, &usec) != 0)
1275         return;
1276     rock->pa_offset = kdc_time - now;
1277     rock->pa_offset_usec = kdc_usec - usec;
1278     rock->pa_offset_state = (rock->fast_state->armor_key != NULL) ?
1279         AUTH_OFFSET : UNAUTH_OFFSET;
1280 }
1281
1282 static krb5_error_code
1283 init_creds_step_reply(krb5_context context,
1284                       krb5_init_creds_context ctx,
1285                       krb5_data *in)
1286 {
1287     krb5_error_code code;
1288     krb5_pa_data **kdc_padata = NULL;
1289     krb5_boolean retry = FALSE;
1290     int canon_flag = 0;
1291     krb5_keyblock *strengthen_key = NULL;
1292     krb5_keyblock encrypting_key;
1293     krb5_boolean fast_avail, got_real;
1294
1295     encrypting_key.length = 0;
1296     encrypting_key.contents = NULL;
1297
1298     /* process previous KDC response */
1299     code = init_creds_validate_reply(context, ctx, in);
1300     if (code != 0)
1301         goto cleanup;
1302
1303     /* per referrals draft, enterprise principals imply canonicalization */
1304     canon_flag = ((ctx->request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
1305         ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
1306
1307     if (ctx->err_reply != NULL) {
1308         code = krb5int_fast_process_error(context, ctx->fast_state,
1309                                           &ctx->err_reply, &ctx->err_padata,
1310                                           &retry);
1311         if (code != 0)
1312             goto cleanup;
1313         if (negotiation_requests_restart(context, ctx, ctx->err_padata)) {
1314             ctx->have_restarted = 1;
1315             krb5_preauth_request_context_fini(context);
1316             if ((ctx->fast_state->fast_state_flags & KRB5INT_FAST_DO_FAST) ==0)
1317                 ctx->enc_pa_rep_permitted = 0;
1318             code = restart_init_creds_loop(context, ctx, ctx->err_padata);
1319             krb5_free_error(context, ctx->err_reply);
1320             ctx->err_reply = NULL;
1321             krb5_free_pa_data(context, ctx->err_padata);
1322             ctx->err_padata = NULL;
1323         } else if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
1324                    retry) {
1325             /* reset the list of preauth types to try */
1326             krb5_free_pa_data(context, ctx->preauth_to_use);
1327             ctx->preauth_to_use = ctx->err_padata;
1328             ctx->err_padata = NULL;
1329             note_req_timestamp(context, &ctx->preauth_rock,
1330                                ctx->err_reply->stime, ctx->err_reply->susec);
1331             /* this will trigger a new call to krb5_do_preauth() */
1332             krb5_free_error(context, ctx->err_reply);
1333             ctx->err_reply = NULL;
1334             code = sort_krb5_padata_sequence(context,
1335                                              &ctx->request->client->realm,
1336                                              ctx->preauth_to_use);
1337             ctx->preauth_required = TRUE;
1338
1339         } else if (canon_flag && ctx->err_reply->error == KDC_ERR_WRONG_REALM) {
1340             if (ctx->err_reply->client == NULL ||
1341                 !krb5_princ_realm(context, ctx->err_reply->client)->length) {
1342                 code = KRB5KDC_ERR_WRONG_REALM;
1343                 goto cleanup;
1344             }
1345             TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm);
1346             /* Rewrite request.client with realm from error reply */
1347             krb5_free_data_contents(context, &ctx->request->client->realm);
1348             code = krb5int_copy_data_contents(context,
1349                                               &ctx->err_reply->client->realm,
1350                                               &ctx->request->client->realm);
1351             /* this will trigger a new call to krb5_do_preauth() */
1352             krb5_free_error(context, ctx->err_reply);
1353             ctx->err_reply = NULL;
1354             krb5_preauth_request_context_fini(context);
1355             /* Permit another negotiation based restart. */
1356             ctx->have_restarted = 0;
1357             ctx->sent_nontrivial_preauth = 0;
1358             code = restart_init_creds_loop(context, ctx, NULL);
1359             if (code != 0)
1360                 goto cleanup;
1361         } else {
1362             if (retry) {
1363                 code = 0;
1364             } else {
1365                 /* error + no hints = give up */
1366                 code = (krb5_error_code)ctx->err_reply->error +
1367                     ERROR_TABLE_BASE_krb5;
1368             }
1369         }
1370
1371         /* Return error code, or continue with next iteration */
1372         goto cleanup;
1373     }
1374
1375     /* We have a response. Process it. */
1376     assert(ctx->reply != NULL);
1377
1378     /* Check for replies (likely forged) with unasked-for enctypes. */
1379     code = check_reply_enctype(ctx);
1380     if (code != 0)
1381         goto cleanup;
1382
1383     /* process any preauth data in the as_reply */
1384     krb5_clear_preauth_context_use_counts(context);
1385     code = krb5int_fast_process_response(context, ctx->fast_state,
1386                                          ctx->reply, &strengthen_key);
1387     if (code != 0)
1388         goto cleanup;
1389
1390     code = sort_krb5_padata_sequence(context, &ctx->request->client->realm,
1391                                      ctx->reply->padata);
1392     if (code != 0)
1393         goto cleanup;
1394
1395     ctx->etype = ctx->reply->enc_part.enctype;
1396
1397     code = krb5_do_preauth(context,
1398                            ctx->request,
1399                            ctx->inner_request_body,
1400                            ctx->encoded_previous_request,
1401                            ctx->reply->padata,
1402                            &kdc_padata,
1403                            ctx->prompter,
1404                            ctx->prompter_data,
1405                            &ctx->preauth_rock,
1406                            ctx->opte,
1407                            &got_real);
1408     if (code != 0)
1409         goto cleanup;
1410
1411     /*
1412      * If we haven't gotten a salt from another source yet, set up one
1413      * corresponding to the client principal returned by the KDC.  We
1414      * could get the same effect by passing local_as_reply->client to
1415      * gak_fct below, but that would put the canonicalized client name
1416      * in the prompt, which raises issues of needing to sanitize
1417      * unprintable characters.  So for now we just let it affect the
1418      * salt.  local_as_reply->client will be checked later on in
1419      * verify_as_reply.
1420      */
1421     if (ctx->default_salt) {
1422         code = krb5_principal2salt(context, ctx->reply->client, &ctx->salt);
1423         TRACE_INIT_CREDS_SALT_PRINC(context, &ctx->salt);
1424         if (code != 0)
1425             goto cleanup;
1426     }
1427
1428     /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
1429        the AS_REP comes back encrypted in the user's longterm key
1430        instead of in the SAD. If there was a SAM preauth, there
1431        will be an as_key here which will be the SAD. If that fails,
1432        use the gak_fct to get the password, and try again. */
1433
1434     /* XXX because etypes are handled poorly (particularly wrt SAM,
1435        where the etype is fixed by the kdc), we may want to try
1436        decrypt_as_reply twice.  If there's an as_key available, try
1437        it.  If decrypting the as_rep fails, or if there isn't an
1438        as_key at all yet, then use the gak_fct to get one, and try
1439        again.  */
1440     if (ctx->as_key.length) {
1441         TRACE_INIT_CREDS_AS_KEY_PREAUTH(context, &ctx->as_key);
1442         code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1443                                       &encrypting_key);
1444         if (code != 0)
1445             goto cleanup;
1446         code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1447         if (code != 0)
1448             TRACE_INIT_CREDS_PREAUTH_DECRYPT_FAIL(context, code);
1449     } else
1450         code = -1;
1451
1452     if (code != 0) {
1453         /* if we haven't get gotten a key, get it now */
1454         TRACE_INIT_CREDS_GAK(context, &ctx->salt, &ctx->s2kparams);
1455         code = (*ctx->gak_fct)(context, ctx->request->client,
1456                                ctx->reply->enc_part.enctype,
1457                                ctx->prompter, ctx->prompter_data,
1458                                &ctx->salt, &ctx->s2kparams,
1459                                &ctx->as_key, ctx->gak_data);
1460         if (code != 0)
1461             goto cleanup;
1462         TRACE_INIT_CREDS_AS_KEY_GAK(context, &ctx->as_key);
1463
1464         code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1465                                       &encrypting_key);
1466         if (code != 0)
1467             goto cleanup;
1468
1469         code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1470         if (code != 0)
1471             goto cleanup;
1472     }
1473
1474     TRACE_INIT_CREDS_DECRYPTED_REPLY(context, ctx->reply->enc_part2->session);
1475
1476     code = krb5int_fast_verify_nego(context, ctx->fast_state,
1477                                     ctx->reply, ctx->encoded_previous_request,
1478                                     &encrypting_key, &fast_avail);
1479     if (code)
1480         goto cleanup;
1481     code = verify_as_reply(context, ctx->request_time,
1482                            ctx->request, ctx->reply);
1483     if (code != 0)
1484         goto cleanup;
1485     code = verify_anonymous(context, ctx->request, ctx->reply,
1486                             &ctx->as_key);
1487     if (code)
1488         goto cleanup;
1489
1490     code = stash_as_reply(context, ctx->request_time, ctx->request,
1491                           ctx->reply, &ctx->cred, NULL);
1492     if (code != 0)
1493         goto cleanup;
1494     if (ctx->opte && ctx->opte->opt_private->out_ccache) {
1495         krb5_ccache out_ccache = ctx->opte->opt_private->out_ccache;
1496         krb5_data config_data;
1497         code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
1498         if (code != 0)
1499             goto cc_cleanup;
1500         code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
1501         if (code != 0)
1502             goto cc_cleanup;
1503         if (fast_avail) {
1504             config_data.data = "yes";
1505             config_data.length = strlen(config_data.data);
1506             code = krb5_cc_set_config(context, out_ccache, ctx->cred.server,
1507                                       KRB5_CONF_FAST_AVAIL, &config_data);
1508         }
1509     cc_cleanup:
1510         if (code !=0) {
1511             const char *msg;
1512             msg = krb5_get_error_message(context, code);
1513             krb5_set_error_message(context, code,
1514                                    _("%s while storing credentials"), msg);
1515             krb5_free_error_message(context, msg);
1516         }
1517     }
1518
1519     krb5_preauth_request_context_fini(context);
1520
1521     /* success */
1522     code = 0;
1523     ctx->complete = TRUE;
1524
1525 cleanup:
1526     krb5_free_pa_data(context, kdc_padata);
1527     krb5_free_keyblock(context, strengthen_key);
1528     krb5_free_keyblock_contents(context, &encrypting_key);
1529
1530     return code;
1531 }
1532
1533 /*
1534  * Do next step of credentials acquisition.
1535  *
1536  * On success returns 0 or KRB5KRB_ERR_RESPONSE_TOO_BIG if the request
1537  * should be sent with TCP.
1538  */
1539 krb5_error_code KRB5_CALLCONV
1540 krb5_init_creds_step(krb5_context context,
1541                      krb5_init_creds_context ctx,
1542                      krb5_data *in,
1543                      krb5_data *out,
1544                      krb5_data *realm,
1545                      unsigned int *flags)
1546 {
1547     krb5_error_code code = 0, code2;
1548
1549     *flags = 0;
1550
1551     out->data = NULL;
1552     out->length = 0;
1553
1554     realm->data = NULL;
1555     realm->length = 0;
1556
1557     if (ctx->complete)
1558         return EINVAL;
1559
1560     if (in->length != 0) {
1561         code = init_creds_step_reply(context, ctx, in);
1562         if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
1563             code2 = krb5int_copy_data_contents(context,
1564                                                ctx->encoded_previous_request,
1565                                                out);
1566             if (code2 != 0) {
1567                 code = code2;
1568                 goto cleanup;
1569             }
1570             goto copy_realm;
1571         }
1572         if (code != 0 || ctx->complete)
1573             goto cleanup;
1574     }
1575
1576     code = init_creds_step_request(context, ctx, out);
1577     if (code != 0)
1578         goto cleanup;
1579
1580     /* Only a new request increments the loop count, not a TCP retry */
1581     ctx->loopcount++;
1582
1583 copy_realm:
1584     assert(ctx->request->server != NULL);
1585
1586     code2 = krb5int_copy_data_contents(context,
1587                                        &ctx->request->server->realm,
1588                                        realm);
1589     if (code2 != 0) {
1590         code = code2;
1591         goto cleanup;
1592     }
1593
1594 cleanup:
1595     if (code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN) {
1596         char *client_name;
1597
1598         /* See if we can produce a more detailed error message */
1599         code2 = krb5_unparse_name(context, ctx->request->client, &client_name);
1600         if (code2 == 0) {
1601             krb5_set_error_message(context, code,
1602                                    _("Client '%s' not found in Kerberos "
1603                                      "database"), client_name);
1604             krb5_free_unparsed_name(context, client_name);
1605         }
1606     }
1607
1608     *flags = ctx->complete ? 0 : KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
1609     return code;
1610 }
1611
1612 krb5_error_code KRB5_CALLCONV
1613 krb5int_get_init_creds(krb5_context context,
1614                        krb5_creds *creds,
1615                        krb5_principal client,
1616                        krb5_prompter_fct prompter,
1617                        void *prompter_data,
1618                        krb5_deltat start_time,
1619                        char *in_tkt_service,
1620                        krb5_get_init_creds_opt *options,
1621                        krb5_gic_get_as_key_fct gak_fct,
1622                        void *gak_data,
1623                        int  *use_master,
1624                        krb5_kdc_rep **as_reply)
1625 {
1626     krb5_error_code code;
1627     krb5_init_creds_context ctx = NULL;
1628
1629     code = krb5_init_creds_init(context,
1630                                 client,
1631                                 prompter,
1632                                 prompter_data,
1633                                 start_time,
1634                                 options,
1635                                 &ctx);
1636     if (code != 0)
1637         goto cleanup;
1638
1639     ctx->gak_fct = gak_fct;
1640     ctx->gak_data = gak_data;
1641
1642     if (in_tkt_service) {
1643         code = krb5_init_creds_set_service(context, ctx, in_tkt_service);
1644         if (code != 0)
1645             goto cleanup;
1646     }
1647
1648     code = k5_init_creds_get(context, ctx, use_master);
1649     if (code != 0)
1650         goto cleanup;
1651
1652     code = krb5_init_creds_get_creds(context, ctx, creds);
1653     if (code != 0)
1654         goto cleanup;
1655
1656     if (as_reply != NULL) {
1657         *as_reply = ctx->reply;
1658         ctx->reply = NULL;
1659     }
1660
1661 cleanup:
1662     krb5_init_creds_free(context, ctx);
1663
1664     return code;
1665 }
1666
1667 krb5_error_code
1668 krb5int_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
1669                          krb5_flags options, krb5_address *const *addrs,
1670                          krb5_enctype *ktypes,
1671                          krb5_preauthtype *pre_auth_types, krb5_creds *creds)
1672 {
1673     int i;
1674     krb5_int32 starttime;
1675     krb5_get_init_creds_opt *opt;
1676     krb5_error_code retval;
1677
1678     *out = NULL;
1679     retval = krb5_get_init_creds_opt_alloc(context, &opt);
1680     if (retval)
1681         return(retval);
1682
1683     if (addrs)
1684         krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
1685     if (ktypes) {
1686         i = krb5int_count_etypes(ktypes);
1687         if (i)
1688             krb5_get_init_creds_opt_set_etype_list(opt, ktypes, i);
1689     }
1690     if (pre_auth_types) {
1691         for (i=0; pre_auth_types[i]; i++);
1692         if (i)
1693             krb5_get_init_creds_opt_set_preauth_list(opt, pre_auth_types, i);
1694     }
1695     if (options&KDC_OPT_FORWARDABLE)
1696         krb5_get_init_creds_opt_set_forwardable(opt, 1);
1697     else krb5_get_init_creds_opt_set_forwardable(opt, 0);
1698     if (options&KDC_OPT_PROXIABLE)
1699         krb5_get_init_creds_opt_set_proxiable(opt, 1);
1700     else krb5_get_init_creds_opt_set_proxiable(opt, 0);
1701     if (creds && creds->times.endtime) {
1702         retval = krb5_timeofday(context, &starttime);
1703         if (retval)
1704             goto cleanup;
1705         if (creds->times.starttime) starttime = creds->times.starttime;
1706         krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
1707     }
1708     *out = opt;
1709     return 0;
1710
1711 cleanup:
1712     krb5_get_init_creds_opt_free(context, opt);
1713     return retval;
1714 }