471834611a16830445538bfc192038e84fd57bfd
[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.salt = &ctx->salt;
826     ctx->preauth_rock.s2kparams = &ctx->s2kparams;
827     ctx->preauth_rock.client = client;
828     ctx->preauth_rock.prompter = prompter;
829     ctx->preauth_rock.prompter_data = data;
830
831     /* Initialise request parameters as per krb5_get_init_creds() */
832     ctx->request->kdc_options = context->kdc_default_options;
833
834     /* forwaradble */
835     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
836         tmp = opte->forwardable;
837     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
838                                         KRB5_CONF_FORWARDABLE, &tmp) == 0)
839         ;
840     else
841         tmp = 0;
842     if (tmp)
843         ctx->request->kdc_options |= KDC_OPT_FORWARDABLE;
844
845     /* proxiable */
846     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
847         tmp = opte->proxiable;
848     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
849                                         KRB5_CONF_PROXIABLE, &tmp) == 0)
850         ;
851     else
852         tmp = 0;
853     if (tmp)
854         ctx->request->kdc_options |= KDC_OPT_PROXIABLE;
855
856     /* canonicalize */
857     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_CANONICALIZE)
858         tmp = 1;
859     else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
860                                         KRB5_CONF_CANONICALIZE, &tmp) == 0)
861         ;
862     else
863         tmp = 0;
864     if (tmp)
865         ctx->request->kdc_options |= KDC_OPT_CANONICALIZE;
866
867     /* allow_postdate */
868     if (ctx->start_time > 0)
869         ctx->request->kdc_options |= KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED;
870
871     /* ticket lifetime */
872     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
873         ctx->tkt_life = options->tkt_life;
874     else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
875                                        KRB5_CONF_TICKET_LIFETIME, &str) == 0) {
876         code = krb5_string_to_deltat(str, &ctx->tkt_life);
877         if (code != 0)
878             goto cleanup;
879         free(str);
880         str = NULL;
881     } else
882         ctx->tkt_life = 24 * 60 * 60; /* previously hardcoded in kinit */
883
884     /* renewable lifetime */
885     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)
886         ctx->renew_life = options->renew_life;
887     else if (krb5int_libdefault_string(context, &ctx->request->client->realm,
888                                        KRB5_CONF_RENEW_LIFETIME, &str) == 0) {
889         code = krb5_string_to_deltat(str, &ctx->renew_life);
890         if (code != 0)
891             goto cleanup;
892         free(str);
893         str = NULL;
894     } else
895         ctx->renew_life = 0;
896
897     if (ctx->renew_life > 0)
898         ctx->request->kdc_options |= KDC_OPT_RENEWABLE;
899
900     /* enctypes */
901     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
902         ctx->request->ktype =
903             k5alloc((opte->etype_list_length * sizeof(krb5_enctype)),
904                     &code);
905         if (code != 0)
906             goto cleanup;
907         ctx->request->nktypes = opte->etype_list_length;
908         memcpy(ctx->request->ktype, opte->etype_list,
909                ctx->request->nktypes * sizeof(krb5_enctype));
910     } else if (krb5_get_default_in_tkt_ktypes(context,
911                                               &ctx->request->ktype) == 0) {
912         ctx->request->nktypes = krb5int_count_etypes(ctx->request->ktype);
913     } else {
914         /* there isn't any useful default here. */
915         code = KRB5_CONFIG_ETYPE_NOSUPP;
916         goto cleanup;
917     }
918
919     /*
920      * Set a default enctype for optimistic preauth.  If we're not doing
921      * optimistic preauth, this should ordinarily get overwritten when we
922      * process the etype-info2 of the preauth-required error.
923      */
924     if (ctx->request->nktypes > 0)
925         ctx->etype = ctx->request->ktype[0];
926
927     /* addresess */
928     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
929         code = krb5_copy_addresses(context, opte->address_list,
930                                    &ctx->request->addresses);
931         if (code != 0)
932             goto cleanup;
933     } else if (krb5int_libdefault_boolean(context, &ctx->request->client->realm,
934                                           KRB5_CONF_NOADDRESSES, &tmp) != 0
935                || tmp) {
936         ctx->request->addresses = NULL;
937     } else {
938         code = krb5_os_localaddr(context, &ctx->request->addresses);
939         if (code != 0)
940             goto cleanup;
941     }
942
943     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_SALT) {
944         code = krb5int_copy_data_contents(context, opte->salt, &ctx->salt);
945         if (code != 0)
946             goto cleanup;
947     } else {
948         ctx->salt.length = SALT_TYPE_AFS_LENGTH;
949         ctx->salt.data = NULL;
950     }
951
952     /* Anonymous. */
953     if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
954         ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
955         /* Remap @REALM to WELLKNOWN/ANONYMOUS@REALM. */
956         if (client->length == 1 && client->data[0].length ==0) {
957             krb5_principal new_client;
958             code = krb5_build_principal_ext(context, &new_client,
959                                             client->realm.length,
960                                             client->realm.data,
961                                             strlen(KRB5_WELLKNOWN_NAMESTR),
962                                             KRB5_WELLKNOWN_NAMESTR,
963                                             strlen(KRB5_ANONYMOUS_PRINCSTR),
964                                             KRB5_ANONYMOUS_PRINCSTR,
965                                             0);
966             if (code)
967                 goto cleanup;
968             krb5_free_principal(context, ctx->request->client);
969             ctx->request->client = new_client;
970             krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
971         }
972     }
973     /* We will also handle anonymous if the input principal is the anonymous
974      * principal. */
975     if (krb5_principal_compare_any_realm(context, ctx->request->client,
976                                          krb5_anonymous_principal())) {
977         ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
978         krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
979     }
980     code = restart_init_creds_loop(context, ctx, NULL);
981     if (code)
982         goto cleanup;
983
984     *pctx = ctx;
985     ctx = NULL;
986
987 cleanup:
988     krb5_init_creds_free(context, ctx);
989     free(str);
990
991     return code;
992 }
993
994 krb5_error_code KRB5_CALLCONV
995 krb5_init_creds_set_service(krb5_context context,
996                             krb5_init_creds_context ctx,
997                             const char *service)
998 {
999     char *s;
1000
1001     TRACE_INIT_CREDS_SERVICE(context, service);
1002
1003     s = strdup(service);
1004     if (s == NULL)
1005         return ENOMEM;
1006
1007     free(ctx->in_tkt_service);
1008     ctx->in_tkt_service = s;
1009
1010     krb5_preauth_request_context_fini(context);
1011     return restart_init_creds_loop(context, ctx, NULL);
1012 }
1013
1014 static krb5_error_code
1015 init_creds_validate_reply(krb5_context context,
1016                           krb5_init_creds_context ctx,
1017                           krb5_data *reply)
1018 {
1019     krb5_error_code code;
1020     krb5_error *error = NULL;
1021     krb5_kdc_rep *as_reply = NULL;
1022
1023     krb5_free_error(context, ctx->err_reply);
1024     ctx->err_reply = NULL;
1025
1026     krb5_free_kdc_rep(context, ctx->reply);
1027     ctx->reply = NULL;
1028
1029     if (krb5_is_krb_error(reply)) {
1030         code = decode_krb5_error(reply, &error);
1031         if (code != 0)
1032             return code;
1033
1034         assert(error != NULL);
1035
1036         TRACE_INIT_CREDS_ERROR_REPLY(context,
1037                                      error->error + ERROR_TABLE_BASE_krb5);
1038         if (error->error == KRB_ERR_RESPONSE_TOO_BIG) {
1039             krb5_free_error(context, error);
1040             return KRB5KRB_ERR_RESPONSE_TOO_BIG;
1041         } else {
1042             ctx->err_reply = error;
1043             return 0;
1044         }
1045     }
1046
1047     /*
1048      * Check to make sure it isn't a V4 reply.
1049      */
1050     if (reply->length != 0 && !krb5_is_as_rep(reply)) {
1051 /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1052 #define V4_KRB_PROT_VERSION     4
1053 #define V4_AUTH_MSG_ERR_REPLY   (5<<1)
1054         /* check here for V4 reply */
1055         unsigned int t_switch;
1056
1057         /* From v4 g_in_tkt.c: This used to be
1058            switch (pkt_msg_type(rpkt) & ~1) {
1059            but SCO 3.2v4 cc compiled that incorrectly.  */
1060         t_switch = reply->data[1];
1061         t_switch &= ~1;
1062
1063         if (t_switch == V4_AUTH_MSG_ERR_REPLY
1064             && reply->data[0] == V4_KRB_PROT_VERSION) {
1065             code = KRB5KRB_AP_ERR_V4_REPLY;
1066         } else {
1067             code = KRB5KRB_AP_ERR_MSG_TYPE;
1068         }
1069         return code;
1070     }
1071
1072     /* It must be a KRB_AS_REP message, or an bad returned packet */
1073     code = decode_krb5_as_rep(reply, &as_reply);
1074     if (code != 0)
1075         return code;
1076
1077     if (as_reply->msg_type != KRB5_AS_REP) {
1078         krb5_free_kdc_rep(context, as_reply);
1079         return KRB5KRB_AP_ERR_MSG_TYPE;
1080     }
1081
1082     ctx->reply = as_reply;
1083
1084     return 0;
1085 }
1086
1087 static krb5_error_code
1088 init_creds_step_request(krb5_context context,
1089                         krb5_init_creds_context ctx,
1090                         krb5_data *out)
1091 {
1092     krb5_error_code code;
1093     krb5_boolean got_real;
1094     char random_buf[4];
1095     krb5_data random_data;
1096
1097     if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
1098         code = KRB5_GET_IN_TKT_LOOP;
1099         goto cleanup;
1100     }
1101     /*
1102      * RFC 6113 requires a new nonce for the inner request on each try. It's
1103      * permitted to change the nonce even for non-FAST so we do here.
1104      */
1105     random_data.length = 4;
1106     random_data.data = (char *)random_buf;
1107     code = krb5_c_random_make_octets(context, &random_data);
1108     if (code !=0)
1109         goto cleanup;
1110     /*
1111      * See RT ticket 3196 at MIT.  If we set the high bit, we may have
1112      * compatibility problems with Heimdal, because we (incorrectly) encode
1113      * this value as signed.
1114      */
1115     ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
1116     krb5_free_data(context, ctx->inner_request_body);
1117     ctx->inner_request_body = NULL;
1118     code = encode_krb5_kdc_req_body(ctx->request, &ctx->inner_request_body);
1119     if (code)
1120         goto cleanup;
1121
1122     if (ctx->err_reply == NULL) {
1123         /* either our first attempt, or retrying after PREAUTH_NEEDED */
1124         code = krb5_do_preauth(context,
1125                                ctx->request,
1126                                ctx->inner_request_body,
1127                                ctx->encoded_previous_request,
1128                                ctx->preauth_to_use,
1129                                &ctx->request->padata,
1130                                ctx->prompter,
1131                                ctx->prompter_data,
1132                                &ctx->preauth_rock,
1133                                ctx->opte,
1134                                &got_real);
1135         if (code == 0 && !got_real && ctx->preauth_required)
1136             code = KRB5_PREAUTH_FAILED;
1137         if (code != 0)
1138             goto cleanup;
1139     } else {
1140         if (ctx->preauth_to_use != NULL) {
1141             /*
1142              * Retry after an error other than PREAUTH_NEEDED,
1143              * using ctx->err_padata to figure out what to change.
1144              */
1145             code = krb5_do_preauth_tryagain(context,
1146                                             ctx->request,
1147                                             ctx->inner_request_body,
1148                                             ctx->encoded_previous_request,
1149                                             ctx->preauth_to_use,
1150                                             &ctx->request->padata,
1151                                             ctx->err_reply,
1152                                             ctx->err_padata,
1153                                             ctx->prompter,
1154                                             ctx->prompter_data,
1155                                             &ctx->preauth_rock,
1156                                             ctx->opte);
1157         } else {
1158             /* No preauth supplied, so can't query the plugins. */
1159             code = KRB5KRB_ERR_GENERIC;
1160         }
1161         if (code != 0) {
1162             /* couldn't come up with anything better */
1163             code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
1164             goto cleanup;
1165         }
1166     }
1167
1168     if (ctx->encoded_previous_request != NULL) {
1169         krb5_free_data(context, ctx->encoded_previous_request);
1170         ctx->encoded_previous_request = NULL;
1171     }
1172     if (ctx->request->padata)
1173         ctx->sent_nontrivial_preauth = 1;
1174     if (ctx->enc_pa_rep_permitted)
1175         code = request_enc_pa_rep(&ctx->request->padata);
1176     if (code)
1177         goto cleanup;
1178     code = krb5int_fast_prep_req(context, ctx->fast_state,
1179                                  ctx->request, ctx->outer_request_body,
1180                                  encode_krb5_as_req,
1181                                  &ctx->encoded_previous_request);
1182     if (code != 0)
1183         goto cleanup;
1184
1185     code = krb5int_copy_data_contents(context,
1186                                       ctx->encoded_previous_request,
1187                                       out);
1188     if (code != 0)
1189         goto cleanup;
1190
1191 cleanup:
1192     krb5_free_pa_data(context, ctx->request->padata);
1193     ctx->request->padata = NULL;
1194     return code;
1195 }
1196
1197 /*
1198  * The control flow is complicated.  In order to switch from non-FAST mode to
1199  * FAST mode, we need to reset our pre-authentication state.  FAST negotiation
1200  * attempts to make sure we rarely have to do this.  When FAST negotiation is
1201  * working, we record whether FAST is available when we obtain an armor ticket;
1202  * if so, we start out with FAST enabled .  There are two complicated
1203  * situations.
1204  *
1205  * First, if we get a PREAUTH_REQUIRED error including PADATA_FX_FAST back from
1206  * a KDC in a case where we were not expecting to use FAST, and we have an
1207  * armor ticket available, then we want to use FAST.  That involves clearing
1208  * out the pre-auth state, reinitializing the plugins and trying again with an
1209  * armor key.
1210  *
1211  * Secondly, using the negotiation can cause problems with some older KDCs.
1212  * Negotiation involves including a special padata item.  Some KDCs, including
1213  * MIT prior to 1.7, will return PREAUTH_FAILED rather than PREAUTH_REQUIRED in
1214  * pre-authentication is required and unknown padata are included in the
1215  * request.  To make matters worse, these KDCs typically do not include a list
1216  * of padata in PREAUTH_FAILED errors.  So, if we get PREAUTH_FAILED and we
1217  * generated no pre-authentication other than the negotiation then we want to
1218  * retry without negotiation.  In this case it is probably also desirable to
1219  * retry with the preauth plugin state cleared.
1220  *
1221  * In all these cases we should not start over more than once.  Control flow is
1222  * managed by several variables.
1223  *
1224  *   sent_nontrivial_preauth: if true, we sent preauth other than negotiation;
1225  *   no restart on PREAUTH_FAILED
1226  *
1227  *   KRB5INT_FAST_ARMOR_AVAIL: fast_state_flag if desired we could generate
1228  *   armor; if not set, then we can't use FAST even if the KDC wants to.
1229  *
1230  *   have_restarted: true if we've already restarted
1231  */
1232 static krb5_boolean
1233 negotiation_requests_restart(krb5_context context, krb5_init_creds_context ctx,
1234                              krb5_pa_data **padata)
1235 {
1236     if (ctx->have_restarted)
1237         return FALSE;
1238     if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
1239         TRACE_INIT_CREDS_RESTART_FAST(context);
1240         return TRUE;
1241     }
1242     if (ctx->err_reply->error == KDC_ERR_PREAUTH_FAILED &&
1243         !ctx->sent_nontrivial_preauth) {
1244         TRACE_INIT_CREDS_RESTART_PREAUTH_FAILED(context);
1245         return TRUE;
1246     }
1247     return FALSE;
1248 }
1249
1250 /* Ensure that the reply enctype was among the requested enctypes. */
1251 static krb5_error_code
1252 check_reply_enctype(krb5_init_creds_context ctx)
1253 {
1254     int i;
1255
1256     for (i = 0; i < ctx->request->nktypes; i++) {
1257         if (ctx->request->ktype[i] == ctx->reply->enc_part.enctype)
1258             return 0;
1259     }
1260     return KRB5_CONFIG_ETYPE_NOSUPP;
1261 }
1262
1263 /* Note the difference between the KDC's time, as reported to us in a
1264  * preauth-required error, and the current time. */
1265 static void
1266 note_req_timestamp(krb5_context kcontext, krb5_clpreauth_rock rock,
1267                    krb5_timestamp kdc_time, krb5_int32 kdc_usec)
1268 {
1269     krb5_timestamp now;
1270     krb5_int32 usec;
1271
1272     if (k5_time_with_offset(0, 0, &now, &usec) != 0)
1273         return;
1274     rock->pa_offset = kdc_time - now;
1275     rock->pa_offset_usec = kdc_usec - usec;
1276     rock->pa_offset_state = (rock->fast_state->armor_key != NULL) ?
1277         AUTH_OFFSET : UNAUTH_OFFSET;
1278 }
1279
1280 static krb5_error_code
1281 init_creds_step_reply(krb5_context context,
1282                       krb5_init_creds_context ctx,
1283                       krb5_data *in)
1284 {
1285     krb5_error_code code;
1286     krb5_pa_data **kdc_padata = NULL;
1287     krb5_boolean retry = FALSE;
1288     int canon_flag = 0;
1289     krb5_keyblock *strengthen_key = NULL;
1290     krb5_keyblock encrypting_key;
1291     krb5_boolean fast_avail, got_real;
1292
1293     encrypting_key.length = 0;
1294     encrypting_key.contents = NULL;
1295
1296     /* process previous KDC response */
1297     code = init_creds_validate_reply(context, ctx, in);
1298     if (code != 0)
1299         goto cleanup;
1300
1301     /* per referrals draft, enterprise principals imply canonicalization */
1302     canon_flag = ((ctx->request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
1303         ctx->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
1304
1305     if (ctx->err_reply != NULL) {
1306         code = krb5int_fast_process_error(context, ctx->fast_state,
1307                                           &ctx->err_reply, &ctx->err_padata,
1308                                           &retry);
1309         if (code != 0)
1310             goto cleanup;
1311         if (negotiation_requests_restart(context, ctx, ctx->err_padata)) {
1312             ctx->have_restarted = 1;
1313             krb5_preauth_request_context_fini(context);
1314             if ((ctx->fast_state->fast_state_flags & KRB5INT_FAST_DO_FAST) ==0)
1315                 ctx->enc_pa_rep_permitted = 0;
1316             code = restart_init_creds_loop(context, ctx, ctx->err_padata);
1317             krb5_free_error(context, ctx->err_reply);
1318             ctx->err_reply = NULL;
1319             krb5_free_pa_data(context, ctx->err_padata);
1320             ctx->err_padata = NULL;
1321         } else if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
1322                    retry) {
1323             /* reset the list of preauth types to try */
1324             krb5_free_pa_data(context, ctx->preauth_to_use);
1325             ctx->preauth_to_use = ctx->err_padata;
1326             ctx->err_padata = NULL;
1327             note_req_timestamp(context, &ctx->preauth_rock,
1328                                ctx->err_reply->stime, ctx->err_reply->susec);
1329             /* this will trigger a new call to krb5_do_preauth() */
1330             krb5_free_error(context, ctx->err_reply);
1331             ctx->err_reply = NULL;
1332             code = sort_krb5_padata_sequence(context,
1333                                              &ctx->request->client->realm,
1334                                              ctx->preauth_to_use);
1335             ctx->preauth_required = TRUE;
1336
1337         } else if (canon_flag && ctx->err_reply->error == KDC_ERR_WRONG_REALM) {
1338             if (ctx->err_reply->client == NULL ||
1339                 !krb5_princ_realm(context, ctx->err_reply->client)->length) {
1340                 code = KRB5KDC_ERR_WRONG_REALM;
1341                 goto cleanup;
1342             }
1343             TRACE_INIT_CREDS_REFERRAL(context, &ctx->err_reply->client->realm);
1344             /* Rewrite request.client with realm from error reply */
1345             krb5_free_data_contents(context, &ctx->request->client->realm);
1346             code = krb5int_copy_data_contents(context,
1347                                               &ctx->err_reply->client->realm,
1348                                               &ctx->request->client->realm);
1349             /* this will trigger a new call to krb5_do_preauth() */
1350             krb5_free_error(context, ctx->err_reply);
1351             ctx->err_reply = NULL;
1352             krb5_preauth_request_context_fini(context);
1353             /* Permit another negotiation based restart. */
1354             ctx->have_restarted = 0;
1355             ctx->sent_nontrivial_preauth = 0;
1356             code = restart_init_creds_loop(context, ctx, NULL);
1357             if (code != 0)
1358                 goto cleanup;
1359         } else {
1360             if (retry) {
1361                 code = 0;
1362             } else {
1363                 /* error + no hints = give up */
1364                 code = (krb5_error_code)ctx->err_reply->error +
1365                     ERROR_TABLE_BASE_krb5;
1366             }
1367         }
1368
1369         /* Return error code, or continue with next iteration */
1370         goto cleanup;
1371     }
1372
1373     /* We have a response. Process it. */
1374     assert(ctx->reply != NULL);
1375
1376     /* Check for replies (likely forged) with unasked-for enctypes. */
1377     code = check_reply_enctype(ctx);
1378     if (code != 0)
1379         goto cleanup;
1380
1381     /* process any preauth data in the as_reply */
1382     krb5_clear_preauth_context_use_counts(context);
1383     code = krb5int_fast_process_response(context, ctx->fast_state,
1384                                          ctx->reply, &strengthen_key);
1385     if (code != 0)
1386         goto cleanup;
1387
1388     code = sort_krb5_padata_sequence(context, &ctx->request->client->realm,
1389                                      ctx->reply->padata);
1390     if (code != 0)
1391         goto cleanup;
1392
1393     ctx->etype = ctx->reply->enc_part.enctype;
1394
1395     code = krb5_do_preauth(context,
1396                            ctx->request,
1397                            ctx->inner_request_body,
1398                            ctx->encoded_previous_request,
1399                            ctx->reply->padata,
1400                            &kdc_padata,
1401                            ctx->prompter,
1402                            ctx->prompter_data,
1403                            &ctx->preauth_rock,
1404                            ctx->opte,
1405                            &got_real);
1406     if (code != 0)
1407         goto cleanup;
1408
1409     /*
1410      * If we haven't gotten a salt from another source yet, set up one
1411      * corresponding to the client principal returned by the KDC.  We
1412      * could get the same effect by passing local_as_reply->client to
1413      * gak_fct below, but that would put the canonicalized client name
1414      * in the prompt, which raises issues of needing to sanitize
1415      * unprintable characters.  So for now we just let it affect the
1416      * salt.  local_as_reply->client will be checked later on in
1417      * verify_as_reply.
1418      */
1419     if (ctx->salt.length == SALT_TYPE_AFS_LENGTH && ctx->salt.data == NULL) {
1420         code = krb5_principal2salt(context, ctx->reply->client, &ctx->salt);
1421         TRACE_INIT_CREDS_SALT_PRINC(context, &ctx->salt);
1422         if (code != 0)
1423             goto cleanup;
1424     }
1425
1426     /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
1427        the AS_REP comes back encrypted in the user's longterm key
1428        instead of in the SAD. If there was a SAM preauth, there
1429        will be an as_key here which will be the SAD. If that fails,
1430        use the gak_fct to get the password, and try again. */
1431
1432     /* XXX because etypes are handled poorly (particularly wrt SAM,
1433        where the etype is fixed by the kdc), we may want to try
1434        decrypt_as_reply twice.  If there's an as_key available, try
1435        it.  If decrypting the as_rep fails, or if there isn't an
1436        as_key at all yet, then use the gak_fct to get one, and try
1437        again.  */
1438     if (ctx->as_key.length) {
1439         TRACE_INIT_CREDS_AS_KEY_PREAUTH(context, &ctx->as_key);
1440         code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1441                                       &encrypting_key);
1442         if (code != 0)
1443             goto cleanup;
1444         code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1445         if (code != 0)
1446             TRACE_INIT_CREDS_PREAUTH_DECRYPT_FAIL(context, code);
1447     } else
1448         code = -1;
1449
1450     if (code != 0) {
1451         /* if we haven't get gotten a key, get it now */
1452         TRACE_INIT_CREDS_GAK(context, &ctx->salt, &ctx->s2kparams);
1453         code = (*ctx->gak_fct)(context, ctx->request->client,
1454                                ctx->reply->enc_part.enctype,
1455                                ctx->prompter, ctx->prompter_data,
1456                                &ctx->salt, &ctx->s2kparams,
1457                                &ctx->as_key, ctx->gak_data);
1458         if (code != 0)
1459             goto cleanup;
1460         TRACE_INIT_CREDS_AS_KEY_GAK(context, &ctx->as_key);
1461
1462         code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
1463                                       &encrypting_key);
1464         if (code != 0)
1465             goto cleanup;
1466
1467         code = decrypt_as_reply(context, NULL, ctx->reply, &encrypting_key);
1468         if (code != 0)
1469             goto cleanup;
1470     }
1471
1472     TRACE_INIT_CREDS_DECRYPTED_REPLY(context, ctx->reply->enc_part2->session);
1473
1474     code = krb5int_fast_verify_nego(context, ctx->fast_state,
1475                                     ctx->reply, ctx->encoded_previous_request,
1476                                     &encrypting_key, &fast_avail);
1477     if (code)
1478         goto cleanup;
1479     code = verify_as_reply(context, ctx->request_time,
1480                            ctx->request, ctx->reply);
1481     if (code != 0)
1482         goto cleanup;
1483     code = verify_anonymous(context, ctx->request, ctx->reply,
1484                             &ctx->as_key);
1485     if (code)
1486         goto cleanup;
1487
1488     code = stash_as_reply(context, ctx->request_time, ctx->request,
1489                           ctx->reply, &ctx->cred, NULL);
1490     if (code != 0)
1491         goto cleanup;
1492     if (ctx->opte && ctx->opte->opt_private->out_ccache) {
1493         krb5_ccache out_ccache = ctx->opte->opt_private->out_ccache;
1494         krb5_data config_data;
1495         code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
1496         if (code != 0)
1497             goto cc_cleanup;
1498         code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
1499         if (code != 0)
1500             goto cc_cleanup;
1501         if (fast_avail) {
1502             config_data.data = "yes";
1503             config_data.length = strlen(config_data.data);
1504             code = krb5_cc_set_config(context, out_ccache, ctx->cred.server,
1505                                       KRB5_CONF_FAST_AVAIL, &config_data);
1506         }
1507     cc_cleanup:
1508         if (code !=0) {
1509             const char *msg;
1510             msg = krb5_get_error_message(context, code);
1511             krb5_set_error_message(context, code,
1512                                    _("%s while storing credentials"), msg);
1513             krb5_free_error_message(context, msg);
1514         }
1515     }
1516
1517     krb5_preauth_request_context_fini(context);
1518
1519     /* success */
1520     code = 0;
1521     ctx->complete = TRUE;
1522
1523 cleanup:
1524     krb5_free_pa_data(context, kdc_padata);
1525     krb5_free_keyblock(context, strengthen_key);
1526     krb5_free_keyblock_contents(context, &encrypting_key);
1527
1528     return code;
1529 }
1530
1531 /*
1532  * Do next step of credentials acquisition.
1533  *
1534  * On success returns 0 or KRB5KRB_ERR_RESPONSE_TOO_BIG if the request
1535  * should be sent with TCP.
1536  */
1537 krb5_error_code KRB5_CALLCONV
1538 krb5_init_creds_step(krb5_context context,
1539                      krb5_init_creds_context ctx,
1540                      krb5_data *in,
1541                      krb5_data *out,
1542                      krb5_data *realm,
1543                      unsigned int *flags)
1544 {
1545     krb5_error_code code = 0, code2;
1546
1547     *flags = 0;
1548
1549     out->data = NULL;
1550     out->length = 0;
1551
1552     realm->data = NULL;
1553     realm->length = 0;
1554
1555     if (ctx->complete)
1556         return EINVAL;
1557
1558     if (in->length != 0) {
1559         code = init_creds_step_reply(context, ctx, in);
1560         if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
1561             code2 = krb5int_copy_data_contents(context,
1562                                                ctx->encoded_previous_request,
1563                                                out);
1564             if (code2 != 0) {
1565                 code = code2;
1566                 goto cleanup;
1567             }
1568             goto copy_realm;
1569         }
1570         if (code != 0 || ctx->complete)
1571             goto cleanup;
1572     }
1573
1574     code = init_creds_step_request(context, ctx, out);
1575     if (code != 0)
1576         goto cleanup;
1577
1578     /* Only a new request increments the loop count, not a TCP retry */
1579     ctx->loopcount++;
1580
1581 copy_realm:
1582     assert(ctx->request->server != NULL);
1583
1584     code2 = krb5int_copy_data_contents(context,
1585                                        &ctx->request->server->realm,
1586                                        realm);
1587     if (code2 != 0) {
1588         code = code2;
1589         goto cleanup;
1590     }
1591
1592 cleanup:
1593     if (code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN) {
1594         char *client_name;
1595
1596         /* See if we can produce a more detailed error message */
1597         code2 = krb5_unparse_name(context, ctx->request->client, &client_name);
1598         if (code2 == 0) {
1599             krb5_set_error_message(context, code,
1600                                    _("Client '%s' not found in Kerberos "
1601                                      "database"), client_name);
1602             krb5_free_unparsed_name(context, client_name);
1603         }
1604     }
1605
1606     *flags = ctx->complete ? 0 : KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
1607     return code;
1608 }
1609
1610 krb5_error_code KRB5_CALLCONV
1611 krb5int_get_init_creds(krb5_context context,
1612                        krb5_creds *creds,
1613                        krb5_principal client,
1614                        krb5_prompter_fct prompter,
1615                        void *prompter_data,
1616                        krb5_deltat start_time,
1617                        char *in_tkt_service,
1618                        krb5_get_init_creds_opt *options,
1619                        krb5_gic_get_as_key_fct gak_fct,
1620                        void *gak_data,
1621                        int  *use_master,
1622                        krb5_kdc_rep **as_reply)
1623 {
1624     krb5_error_code code;
1625     krb5_init_creds_context ctx = NULL;
1626
1627     code = krb5_init_creds_init(context,
1628                                 client,
1629                                 prompter,
1630                                 prompter_data,
1631                                 start_time,
1632                                 options,
1633                                 &ctx);
1634     if (code != 0)
1635         goto cleanup;
1636
1637     ctx->gak_fct = gak_fct;
1638     ctx->gak_data = gak_data;
1639
1640     if (in_tkt_service) {
1641         code = krb5_init_creds_set_service(context, ctx, in_tkt_service);
1642         if (code != 0)
1643             goto cleanup;
1644     }
1645
1646     code = k5_init_creds_get(context, ctx, use_master);
1647     if (code != 0)
1648         goto cleanup;
1649
1650     code = krb5_init_creds_get_creds(context, ctx, creds);
1651     if (code != 0)
1652         goto cleanup;
1653
1654     if (as_reply != NULL) {
1655         *as_reply = ctx->reply;
1656         ctx->reply = NULL;
1657     }
1658
1659 cleanup:
1660     krb5_init_creds_free(context, ctx);
1661
1662     return code;
1663 }
1664
1665 krb5_error_code
1666 krb5int_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out,
1667                          krb5_flags options, krb5_address *const *addrs,
1668                          krb5_enctype *ktypes,
1669                          krb5_preauthtype *pre_auth_types, krb5_creds *creds)
1670 {
1671     int i;
1672     krb5_int32 starttime;
1673     krb5_get_init_creds_opt *opt;
1674     krb5_error_code retval;
1675
1676     *out = NULL;
1677     retval = krb5_get_init_creds_opt_alloc(context, &opt);
1678     if (retval)
1679         return(retval);
1680
1681     if (addrs)
1682         krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
1683     if (ktypes) {
1684         i = krb5int_count_etypes(ktypes);
1685         if (i)
1686             krb5_get_init_creds_opt_set_etype_list(opt, ktypes, i);
1687     }
1688     if (pre_auth_types) {
1689         for (i=0; pre_auth_types[i]; i++);
1690         if (i)
1691             krb5_get_init_creds_opt_set_preauth_list(opt, pre_auth_types, i);
1692     }
1693     if (options&KDC_OPT_FORWARDABLE)
1694         krb5_get_init_creds_opt_set_forwardable(opt, 1);
1695     else krb5_get_init_creds_opt_set_forwardable(opt, 0);
1696     if (options&KDC_OPT_PROXIABLE)
1697         krb5_get_init_creds_opt_set_proxiable(opt, 1);
1698     else krb5_get_init_creds_opt_set_proxiable(opt, 0);
1699     if (creds && creds->times.endtime) {
1700         retval = krb5_timeofday(context, &starttime);
1701         if (retval)
1702             goto cleanup;
1703         if (creds->times.starttime) starttime = creds->times.starttime;
1704         krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
1705     }
1706     *out = opt;
1707     return 0;
1708
1709 cleanup:
1710     krb5_get_init_creds_opt_free(context, opt);
1711     return retval;
1712 }