31c2e144cd9a98496ab94132e2ac0a3f7ac44cb8
[krb5.git] / src / kdc / kdc_preauth.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kdc/kdc_preauth.c - Preauthentication routines for the KDC */
3 /*
4  * Copyright 1995, 2003, 2007, 2009 by the Massachusetts Institute of
5  * Technology.  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  * Copyright (C) 1998 by the FundsXpress, INC.
28  *
29  * All rights reserved.
30  *
31  * Export of this software from the United States of America may require
32  * a specific license from the United States Government.  It is the
33  * responsibility of any person or organization contemplating export to
34  * obtain such a license before exporting.
35  *
36  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37  * distribute this software and its documentation for any purpose and
38  * without fee is hereby granted, provided that the above copyright
39  * notice appear in all copies and that both that copyright notice and
40  * this permission notice appear in supporting documentation, and that
41  * the name of FundsXpress. not be used in advertising or publicity pertaining
42  * to distribution of the software without specific, written prior
43  * permission.  FundsXpress makes no representations about the suitability of
44  * this software for any purpose.  It is provided "as is" without express
45  * or implied warranty.
46  *
47  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
50  */
51 /*
52  * Copyright (c) 2006-2008, Novell, Inc.
53  * All rights reserved.
54  *
55  * Redistribution and use in source and binary forms, with or without
56  * modification, are permitted provided that the following conditions are met:
57  *
58  *   * Redistributions of source code must retain the above copyright notice,
59  *       this list of conditions and the following disclaimer.
60  *   * Redistributions in binary form must reproduce the above copyright
61  *       notice, this list of conditions and the following disclaimer in the
62  *       documentation and/or other materials provided with the distribution.
63  *   * The copyright holder's name is not used to endorse or promote products
64  *       derived from this software without specific prior written permission.
65  *
66  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
67  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
68  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
69  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
70  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
71  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
72  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
73  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
74  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
75  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
76  * POSSIBILITY OF SUCH DAMAGE.
77  */
78
79 #include "k5-int.h"
80 #include "kdc_util.h"
81 #include "extern.h"
82 #include <stdio.h>
83 #include "adm_proto.h"
84 #if APPLE_PKINIT
85 #include "pkinit_server.h"
86 #include "pkinit_cert_store.h"
87 #endif /* APPLE_PKINIT */
88
89 #include <syslog.h>
90
91 #include <assert.h>
92 #include "../include/krb5/preauth_plugin.h"
93
94 typedef struct preauth_system_st {
95     const char *name;
96     int type;
97     int flags;
98     krb5_kdcpreauth_moddata moddata;
99     krb5_kdcpreauth_init_fn init;
100     krb5_kdcpreauth_fini_fn fini;
101     krb5_kdcpreauth_edata_fn get_edata;
102     krb5_kdcpreauth_verify_fn verify_padata;
103     krb5_kdcpreauth_return_fn return_padata;
104     krb5_kdcpreauth_free_modreq_fn free_modreq;
105 } preauth_system;
106
107 static void
108 get_etype_info(krb5_context context, krb5_kdc_req *request,
109                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
110                krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
111                krb5_kdcpreauth_edata_respond_fn respond, void *arg);
112
113 static void
114 get_etype_info2(krb5_context context, krb5_kdc_req *request,
115                 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
116                 krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
117                 krb5_kdcpreauth_edata_respond_fn respond, void *arg);
118
119 static krb5_error_code
120 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
121                          krb5_db_entry *client,
122                          krb5_kdc_req *request, krb5_kdc_rep *reply,
123                          krb5_key_data *client_key,
124                          krb5_keyblock *encrypting_key,
125                          krb5_pa_data **send_pa,
126                          int etype_info2);
127
128 static krb5_error_code
129 return_etype_info(krb5_context, krb5_pa_data *padata,
130                   krb5_data *req_pkt, krb5_kdc_req *request,
131                   krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
132                   krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
133                   krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
134                   krb5_kdcpreauth_modreq modreq);
135
136 static krb5_error_code
137 return_etype_info2(krb5_context, krb5_pa_data *padata,
138                    krb5_data *req_pkt, krb5_kdc_req *request,
139                    krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
140                    krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
141                    krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
142                    krb5_kdcpreauth_modreq modreq);
143
144 static krb5_error_code
145 return_pw_salt(krb5_context, krb5_pa_data *padata,
146                krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
147                krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
148                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
149                krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq);
150
151
152 #if APPLE_PKINIT
153 /* PKINIT preauth support */
154 static krb5_error_code get_pkinit_edata(
155     krb5_context context,
156     krb5_kdc_req *request,
157     krb5_db_entry *client,
158     krb5_db_entry *server,
159     preauth_get_entry_data_proc get_entry_data,
160     void *pa_module_context,
161     krb5_pa_data *pa_data);
162 static krb5_error_code verify_pkinit_request(
163     krb5_context context,
164     krb5_db_entry *client,
165     krb5_data *req_pkt,
166     krb5_kdc_req *request,
167     krb5_enc_tkt_part *enc_tkt_reply,
168     krb5_pa_data *data,
169     preauth_get_entry_data_proc get_entry_data,
170     void *pa_module_context,
171     void **pa_request_context,
172     krb5_data **e_data,
173     krb5_authdata ***authz_data);
174 static krb5_error_code return_pkinit_response(
175     krb5_context context,
176     krb5_pa_data * padata,
177     krb5_db_entry *client,
178     krb5_data *req_pkt,
179     krb5_kdc_req *request,
180     krb5_kdc_rep *reply,
181     krb5_key_data *client_key,
182     krb5_keyblock *encrypting_key,
183     krb5_pa_data **send_pa,
184     preauth_get_entry_data_proc get_entry_data,
185     void *pa_module_context,
186     void **pa_request_context);
187 #endif /* APPLE_PKINIT */
188
189 static preauth_system static_preauth_systems[] = {
190 #if APPLE_PKINIT
191     {
192         "pkinit",
193         KRB5_PADATA_PK_AS_REQ,
194         PA_SUFFICIENT,
195         NULL,                   /* pa_sys_context */
196         NULL,                   /* init */
197         NULL,                   /* fini */
198         get_pkinit_edata,
199         verify_pkinit_request,
200         return_pkinit_response,
201         NULL                    /* free_modreq */
202     },
203 #endif /* APPLE_PKINIT */
204     {
205         "FAST",
206         KRB5_PADATA_FX_FAST,
207         PA_HARDWARE,
208         NULL,
209         NULL,
210         NULL,
211         NULL,
212         NULL,
213         0
214     },
215     {
216         "etype-info",
217         KRB5_PADATA_ETYPE_INFO,
218         0,
219         NULL,
220         NULL,
221         NULL,
222         get_etype_info,
223         0,
224         return_etype_info
225     },
226     {
227         "etype-info2",
228         KRB5_PADATA_ETYPE_INFO2,
229         0,
230         NULL,
231         NULL,
232         NULL,
233         get_etype_info2,
234         0,
235         return_etype_info2
236     },
237     {
238         "pw-salt",
239         KRB5_PADATA_PW_SALT,
240         PA_PSEUDO,              /* Don't include this in the error list */
241         NULL,
242         NULL,
243         NULL,
244         0,
245         0,
246         return_pw_salt
247     },
248     {
249         "pac-request",
250         KRB5_PADATA_PAC_REQUEST,
251         PA_PSEUDO,
252         NULL,
253         NULL,
254         NULL,
255         NULL,
256         NULL,
257         NULL
258     },
259 #if 0
260     {
261         "server-referral",
262         KRB5_PADATA_SERVER_REFERRAL,
263         PA_PSEUDO,
264         0,
265         0,
266         return_server_referral
267     },
268 #endif
269 };
270
271 #define NUM_STATIC_PREAUTH_SYSTEMS (sizeof(static_preauth_systems) /    \
272                                     sizeof(*static_preauth_systems))
273
274 static preauth_system *preauth_systems;
275 static size_t n_preauth_systems;
276
277 /* Get all available kdcpreauth vtables and a count of preauth types they
278  * support.  Return an empty list on failure. */
279 static void
280 get_plugin_vtables(krb5_context context,
281                    struct krb5_kdcpreauth_vtable_st **vtables_out,
282                    size_t *n_tables_out, size_t *n_systems_out)
283 {
284     krb5_plugin_initvt_fn *plugins = NULL, *pl;
285     struct krb5_kdcpreauth_vtable_st *vtables;
286     size_t count, n_tables, n_systems, i;
287
288     *vtables_out = NULL;
289     *n_tables_out = *n_systems_out = 0;
290
291     /* Auto-register encrypted challenge and (if possible) pkinit. */
292     k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "pkinit",
293                            "preauth");
294     k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH,
295                        "encrypted_challenge",
296                        kdcpreauth_encrypted_challenge_initvt);
297     k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH,
298                        "encrypted_timestamp",
299                        kdcpreauth_encrypted_timestamp_initvt);
300
301     if (k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPREAUTH, &plugins))
302         return;
303     for (count = 0; plugins[count]; count++);
304     vtables = calloc(count + 1, sizeof(*vtables));
305     if (vtables == NULL)
306         goto cleanup;
307     for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
308         if ((*pl)(context, 1, 1, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
309             n_tables++;
310     }
311     for (i = 0, n_systems = 0; i < n_tables; i++) {
312         for (count = 0; vtables[i].pa_type_list[count] > 0; count++);
313         n_systems += count;
314     }
315     *vtables_out = vtables;
316     *n_tables_out = n_tables;
317     *n_systems_out = n_systems;
318
319 cleanup:
320     k5_plugin_free_modules(context, plugins);
321 }
322
323 /* Make a list of realm names.  The caller should free the list container but
324  * not the list elements (which are aliases into kdc_realmlist). */
325 static krb5_error_code
326 get_realm_names(const char ***list_out)
327 {
328     const char **list;
329     int i;
330
331     list = calloc(kdc_numrealms + 1, sizeof(*list));
332     if (list == NULL)
333         return ENOMEM;
334     for (i = 0; i < kdc_numrealms; i++)
335         list[i] = kdc_realmlist[i]->realm_name;
336     list[i] = NULL;
337     *list_out = list;
338     return 0;
339 }
340
341 void
342 load_preauth_plugins(krb5_context context)
343 {
344     krb5_error_code ret;
345     struct krb5_kdcpreauth_vtable_st *vtables = NULL, *vt;
346     size_t n_systems, n_tables, i, j;
347     krb5_kdcpreauth_moddata moddata;
348     const char **realm_names = NULL, *emsg;
349     preauth_system *sys;
350
351     /* Get all available kdcpreauth vtables. */
352     get_plugin_vtables(context, &vtables, &n_tables, &n_systems);
353
354     /* Allocate the list of static and plugin preauth systems. */
355     n_systems += NUM_STATIC_PREAUTH_SYSTEMS;
356     preauth_systems = calloc(n_systems + 1, sizeof(preauth_system));
357     if (preauth_systems == NULL)
358         goto cleanup;
359
360     if (get_realm_names(&realm_names))
361         goto cleanup;
362
363     /* Add the static system to the list first.  No static systems require
364      * initialization, so just make a direct copy. */
365     memcpy(preauth_systems, static_preauth_systems,
366            sizeof(static_preauth_systems));
367
368     /* Add the dynamically-loaded mechanisms to the list. */
369     n_systems = NUM_STATIC_PREAUTH_SYSTEMS;
370     for (i = 0; i < n_tables; i++) {
371         /* Try to initialize this module. */
372         vt = &vtables[i];
373         moddata = NULL;
374         if (vt->init) {
375             ret = vt->init(context, &moddata, realm_names);
376             if (ret) {
377                 emsg = krb5_get_error_message(context, ret);
378                 krb5_klog_syslog(LOG_ERR, _("preauth %s failed to "
379                                             "initialize: %s"), vt->name, emsg);
380                 krb5_free_error_message(context, emsg);
381                 continue;
382             }
383         }
384         /* Add this module to the systems list once for each pa type. */
385         for (j = 0; vt->pa_type_list[j] > 0; j++) {
386             sys = &preauth_systems[n_systems];
387             sys->name = vt->name;
388             sys->type = vt->pa_type_list[j];
389             sys->flags = (vt->flags) ? vt->flags(context, sys->type) : 0;
390             sys->moddata = moddata;
391             sys->init = vt->init;
392             /* Only call fini once for each plugin. */
393             sys->fini = (j == 0) ? vt->fini : NULL;
394             sys->get_edata = vt->edata;
395             sys->verify_padata = vt->verify;
396             sys->return_padata = vt->return_padata;
397             sys->free_modreq = vt->free_modreq;
398             n_systems++;
399         }
400     }
401     n_preauth_systems = n_systems;
402     /* Add the end-of-list marker. */
403     preauth_systems[n_systems].name = "[end]";
404     preauth_systems[n_systems].type = -1;
405
406 cleanup:
407     free(vtables);
408     free(realm_names);
409 }
410
411 void
412 unload_preauth_plugins(krb5_context context)
413 {
414     size_t i;
415
416     for (i = 0; i < n_preauth_systems; i++) {
417         if (preauth_systems[i].fini)
418             preauth_systems[i].fini(context, preauth_systems[i].moddata);
419     }
420     free(preauth_systems);
421     preauth_systems = NULL;
422     n_preauth_systems = 0;
423 }
424
425 /*
426  * The make_padata_context() function creates a space for storing any
427  * request-specific module data which will be needed by return_padata() later.
428  * Each preauth type gets a storage location of its own.
429  */
430 struct request_pa_context {
431     int n_contexts;
432     struct {
433         preauth_system *pa_system;
434         krb5_kdcpreauth_modreq modreq;
435     } *contexts;
436 };
437
438 static krb5_error_code
439 make_padata_context(krb5_context context, void **padata_context)
440 {
441     int i;
442     struct request_pa_context *ret;
443
444     ret = malloc(sizeof(*ret));
445     if (ret == NULL) {
446         return ENOMEM;
447     }
448
449     ret->n_contexts = n_preauth_systems;
450     ret->contexts = malloc(sizeof(ret->contexts[0]) * ret->n_contexts);
451     if (ret->contexts == NULL) {
452         free(ret);
453         return ENOMEM;
454     }
455
456     memset(ret->contexts, 0, sizeof(ret->contexts[0]) * ret->n_contexts);
457
458     for (i = 0; i < ret->n_contexts; i++) {
459         ret->contexts[i].pa_system = &preauth_systems[i];
460         ret->contexts[i].modreq = NULL;
461     }
462
463     *padata_context = ret;
464
465     return 0;
466 }
467
468 /*
469  * The free_padata_context function frees any context information pointers
470  * which the check_padata() function created but which weren't already cleaned
471  * up by return_padata().
472  */
473 void
474 free_padata_context(krb5_context kcontext, void *padata_context)
475 {
476     struct request_pa_context *context = padata_context;
477     preauth_system *sys;
478     int i;
479
480     if (context == NULL)
481         return;
482     for (i = 0; i < context->n_contexts; i++) {
483         sys = context->contexts[i].pa_system;
484         if (!sys->free_modreq || !context->contexts[i].modreq)
485             continue;
486         sys->free_modreq(kcontext, sys->moddata, context->contexts[i].modreq);
487         context->contexts[i].modreq = NULL;
488     }
489
490     free(context->contexts);
491     free(context);
492 }
493
494 static krb5_deltat
495 max_time_skew(krb5_context context, krb5_kdcpreauth_rock rock)
496 {
497     return context->clockskew;
498 }
499
500 static krb5_error_code
501 client_keys(krb5_context context, krb5_kdcpreauth_rock rock,
502             krb5_keyblock **keys_out)
503 {
504     krb5_kdc_req *request = rock->request;
505     krb5_db_entry *client = rock->client;
506     krb5_keyblock *keys, key;
507     krb5_key_data *entry_key;
508     int i, k;
509
510     keys = malloc(sizeof(krb5_keyblock) * (request->nktypes + 1));
511     if (keys == NULL)
512         return ENOMEM;
513
514     memset(keys, 0, sizeof(krb5_keyblock) * (request->nktypes + 1));
515     k = 0;
516     for (i = 0; i < request->nktypes; i++) {
517         entry_key = NULL;
518         if (krb5_dbe_find_enctype(context, client, request->ktype[i],
519                                   -1, 0, &entry_key) != 0)
520             continue;
521         if (krb5_dbe_decrypt_key_data(context, NULL, entry_key,
522                                       &key, NULL) != 0)
523             continue;
524         keys[k++] = key;
525     }
526     if (k == 0) {
527         free(keys);
528         return ENOENT;
529     }
530     *keys_out = keys;
531     return 0;
532 }
533
534 static void free_keys(krb5_context context, krb5_kdcpreauth_rock rock,
535                       krb5_keyblock *keys)
536 {
537     krb5_keyblock *k;
538
539     if (keys == NULL)
540         return;
541     for (k = keys; k->enctype != 0; k++)
542         krb5_free_keyblock_contents(context, k);
543     free(keys);
544 }
545
546 static krb5_data *
547 request_body(krb5_context context, krb5_kdcpreauth_rock rock)
548 {
549     return rock->inner_body;
550 }
551
552 static krb5_keyblock *
553 fast_armor(krb5_context context, krb5_kdcpreauth_rock rock)
554 {
555     return rock->rstate->armor_key;
556 }
557
558 static krb5_error_code
559 get_string(krb5_context context, krb5_kdcpreauth_rock rock, const char *key,
560            char **value_out)
561 {
562     return krb5_dbe_get_string(context, rock->client, key, value_out);
563 }
564
565 static void
566 free_string(krb5_context context, krb5_kdcpreauth_rock rock, char *string)
567 {
568     krb5_dbe_free_string(context, string);
569 }
570
571 static void *
572 client_entry(krb5_context context, krb5_kdcpreauth_rock rock)
573 {
574     return rock->client;
575 }
576
577 static verto_ctx *
578 event_context(krb5_context context, krb5_kdcpreauth_rock rock)
579 {
580     return rock->vctx;
581 }
582
583 static struct krb5_kdcpreauth_callbacks_st callbacks = {
584     1,
585     max_time_skew,
586     client_keys,
587     free_keys,
588     request_body,
589     fast_armor,
590     get_string,
591     free_string,
592     client_entry,
593     event_context
594 };
595
596 static krb5_error_code
597 find_pa_system(int type, preauth_system **preauth)
598 {
599     preauth_system *ap;
600
601     ap = preauth_systems ? preauth_systems : static_preauth_systems;
602     while ((ap->type != -1) && (ap->type != type))
603         ap++;
604     if (ap->type == -1)
605         return(KRB5_PREAUTH_BAD_TYPE);
606     *preauth = ap;
607     return 0;
608 }
609
610 /* Find a pointer to the request-specific module data for pa_sys. */
611 static krb5_error_code
612 find_modreq(preauth_system *pa_sys, struct request_pa_context *context,
613             krb5_kdcpreauth_modreq **modreq_out)
614 {
615     int i;
616
617     *modreq_out = NULL;
618     if (context == NULL)
619         return KRB5KRB_ERR_GENERIC;
620
621     for (i = 0; i < context->n_contexts; i++) {
622         if (context->contexts[i].pa_system == pa_sys) {
623             *modreq_out = &context->contexts[i].modreq;
624             return 0;
625         }
626     }
627
628     return KRB5KRB_ERR_GENERIC;
629 }
630
631 /*
632  * Create a list of indices into the preauth_systems array, sorted by order of
633  * preference.
634  */
635 static krb5_boolean
636 pa_list_includes(krb5_pa_data **pa_data, krb5_preauthtype pa_type)
637 {
638     while (*pa_data != NULL) {
639         if ((*pa_data)->pa_type == pa_type)
640             return TRUE;
641         pa_data++;
642     }
643     return FALSE;
644 }
645 static void
646 sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order)
647 {
648     size_t i, j, k, n_repliers, n_key_replacers;
649
650     /* First, set up the default order. */
651     i = 0;
652     for (j = 0; j < n_preauth_systems; j++) {
653         if (preauth_systems[j].return_padata != NULL)
654             pa_order[i++] = j;
655     }
656     n_repliers = i;
657     pa_order[n_repliers] = -1;
658
659     /* Reorder so that PA_REPLACES_KEY modules are listed first. */
660     for (i = 0; i < n_repliers; i++) {
661         /* If this module replaces the key, then it's okay to leave it where it
662          * is in the order. */
663         if (preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY)
664             continue;
665         /* If not, search for a module which does, and swap in the first one we
666          * find. */
667         for (j = i + 1; j < n_repliers; j++) {
668             if (preauth_systems[pa_order[j]].flags & PA_REPLACES_KEY) {
669                 k = pa_order[j];
670                 pa_order[j] = pa_order[i];
671                 pa_order[i] = k;
672                 break;
673             }
674         }
675     }
676
677     if (request->padata != NULL) {
678         /* Now reorder the subset of modules which replace the key,
679          * bubbling those which handle pa_data types provided by the
680          * client ahead of the others.
681          */
682         for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) {
683             continue;
684         }
685         n_key_replacers = i;
686         for (i = 0; i < n_key_replacers; i++) {
687             if (pa_list_includes(request->padata,
688                                  preauth_systems[pa_order[i]].type))
689                 continue;
690             for (j = i + 1; j < n_key_replacers; j++) {
691                 if (pa_list_includes(request->padata,
692                                      preauth_systems[pa_order[j]].type)) {
693                     k = pa_order[j];
694                     pa_order[j] = pa_order[i];
695                     pa_order[i] = k;
696                     break;
697                 }
698             }
699         }
700     }
701 #ifdef DEBUG
702     krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:");
703     for (i = 0; i < n_preauth_systems; i++) {
704         if (preauth_systems[i].return_padata != NULL)
705             krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", preauth_systems[i].name,
706                              preauth_systems[i].type);
707     }
708     krb5_klog_syslog(LOG_DEBUG, "sorted preauth mechanism list:");
709     for (i = 0; pa_order[i] != -1; i++) {
710         krb5_klog_syslog(LOG_DEBUG, "... %s(%d)",
711                          preauth_systems[pa_order[i]].name,
712                          preauth_systems[pa_order[i]].type);
713     }
714 #endif
715 }
716
717 const char *missing_required_preauth(krb5_db_entry *client,
718                                      krb5_db_entry *server,
719                                      krb5_enc_tkt_part *enc_tkt_reply)
720 {
721 #if 0
722     /*
723      * If this is the pwchange service, and the pre-auth bit is set,
724      * allow it even if the HW preauth would normally be required.
725      *
726      * Sandia national labs wanted this for some strange reason... we
727      * leave it disabled normally.
728      */
729     if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) &&
730         isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
731         return 0;
732 #endif
733
734 #ifdef DEBUG
735     krb5_klog_syslog (
736         LOG_DEBUG,
737         "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth",
738         isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ",
739         isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ",
740         isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ",
741         isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no ");
742 #endif
743
744     if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
745         !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
746         return "NEEDED_PREAUTH";
747
748     if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
749         !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
750         return "NEEDED_HW_PREAUTH";
751
752     return 0;
753 }
754
755 struct hint_state {
756     kdc_hint_respond_fn respond;
757     void *arg;
758     kdc_realm_t *realm;
759
760     krb5_kdcpreauth_rock rock;
761     krb5_kdc_req *request;
762     krb5_pa_data ***e_data_out;
763
764     int hw_only;
765     preauth_system *ap;
766     krb5_pa_data **pa_data, **pa_cur;
767     krb5_preauthtype pa_type;
768 };
769
770 static void
771 hint_list_finish(struct hint_state *state, krb5_error_code code)
772 {
773     kdc_hint_respond_fn oldrespond = state->respond;
774     void *oldarg = state->arg;
775
776     if (!code) {
777         if (state->pa_data[0] == 0) {
778             krb5_klog_syslog(LOG_INFO,
779                              _("%spreauth required but hint list is empty"),
780                              state->hw_only ? "hw" : "");
781         }
782         /* If we fail to get the cookie it is probably still reasonable to
783          * continue with the response. */
784         kdc_preauth_get_cookie(state->rock->rstate, state->pa_cur);
785
786         *state->e_data_out = state->pa_data;
787         state->pa_data = NULL;
788     }
789
790     krb5_free_pa_data(kdc_context, state->pa_data);
791     free(state);
792     (*oldrespond)(oldarg);
793 }
794
795 static void
796 hint_list_next(struct hint_state *arg);
797
798 static void
799 finish_get_edata(void *arg, krb5_error_code code, krb5_pa_data *pa)
800 {
801     struct hint_state *state = arg;
802
803     kdc_active_realm = state->realm;
804     if (code == 0) {
805         if (pa == NULL) {
806             /* Include an empty value of the current type. */
807             pa = calloc(1, sizeof(*pa));
808             pa->magic = KV5M_PA_DATA;
809             pa->pa_type = state->pa_type;
810         }
811         *state->pa_cur++ = pa;
812     }
813
814     state->ap++;
815     hint_list_next(state);
816 }
817
818 static void
819 hint_list_next(struct hint_state *state)
820 {
821     preauth_system *ap = state->ap;
822
823     if (ap->type == -1) {
824         hint_list_finish(state, 0);
825         return;
826     }
827
828     if (state->hw_only && !(ap->flags & PA_HARDWARE))
829         goto next;
830     if (ap->flags & PA_PSEUDO)
831         goto next;
832
833     state->pa_type = ap->type;
834     if (ap->get_edata) {
835         ap->get_edata(kdc_context, state->request, &callbacks, state->rock,
836                       ap->moddata, ap->type, finish_get_edata, state);
837     } else
838         finish_get_edata(state, 0, NULL);
839     return;
840
841 next:
842     state->ap++;
843     hint_list_next(state);
844 }
845
846 void
847 get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
848                       krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond,
849                       void *arg)
850 {
851     struct hint_state *state;
852
853     *e_data_out = NULL;
854
855     /* Allocate our state. */
856     state = calloc(1, sizeof(*state));
857     if (state == NULL) {
858         (*respond)(arg);
859         return;
860     }
861     state->hw_only = isflagset(rock->client->attributes,
862                                KRB5_KDB_REQUIRES_HW_AUTH);
863     state->respond = respond;
864     state->arg = arg;
865     state->request = request;
866     state->rock = rock;
867     state->realm = kdc_active_realm;
868     state->e_data_out = e_data_out;
869
870     /* Allocate two extra entries for the cookie and the terminator. */
871     state->pa_data = calloc(n_preauth_systems + 2, sizeof(krb5_pa_data *));
872     if (!state->pa_data) {
873         free(state);
874         (*respond)(arg);
875         return;
876     }
877
878     state->pa_cur = state->pa_data;
879     state->ap = preauth_systems;
880     hint_list_next(state);
881 }
882
883 /*
884  * Add authorization data returned from preauth modules to the ticket
885  * It is assumed that ad is a "null-terminated" array of krb5_authdata ptrs
886  */
887 static krb5_error_code
888 add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad)
889 {
890     krb5_authdata **newad;
891     int oldones, newones;
892     int i;
893
894     if (enc_tkt_part == NULL || ad == NULL)
895         return EINVAL;
896
897     for (newones = 0; ad[newones] != NULL; newones++);
898     if (newones == 0)
899         return 0;   /* nothing to add */
900
901     if (enc_tkt_part->authorization_data == NULL)
902         oldones = 0;
903     else
904         for (oldones = 0;
905              enc_tkt_part->authorization_data[oldones] != NULL; oldones++);
906
907     newad = malloc((oldones + newones + 1) * sizeof(krb5_authdata *));
908     if (newad == NULL)
909         return ENOMEM;
910
911     /* Copy any existing pointers */
912     for (i = 0; i < oldones; i++)
913         newad[i] = enc_tkt_part->authorization_data[i];
914
915     /* Add the new ones */
916     for (i = 0; i < newones; i++)
917         newad[oldones+i] = ad[i];
918
919     /* Terminate the new list */
920     newad[oldones+i] = NULL;
921
922     /* Free any existing list */
923     if (enc_tkt_part->authorization_data != NULL)
924         free(enc_tkt_part->authorization_data);
925
926     /* Install our new list */
927     enc_tkt_part->authorization_data = newad;
928
929     return 0;
930 }
931
932 struct padata_state {
933     kdc_preauth_respond_fn respond;
934     void *arg;
935     kdc_realm_t *realm;
936
937     krb5_kdcpreauth_modreq *modreq_ptr;
938     krb5_pa_data **padata;
939     int pa_found;
940     krb5_context context;
941     krb5_kdcpreauth_rock rock;
942     krb5_data *req_pkt;
943     krb5_kdc_req *request;
944     krb5_enc_tkt_part *enc_tkt_reply;
945     void **padata_context;
946
947     preauth_system *pa_sys;
948     krb5_pa_data **pa_e_data;
949     krb5_boolean typed_e_data_flag;
950     int pa_ok;
951     krb5_error_code saved_code;
952
953     krb5_pa_data ***e_data_out;
954     krb5_boolean *typed_e_data_out;
955 };
956
957 static void
958 finish_check_padata(struct padata_state *state, krb5_error_code code)
959 {
960     kdc_preauth_respond_fn oldrespond;
961     void *oldarg;
962
963     assert(state);
964     oldrespond = state->respond;
965     oldarg = state->arg;
966
967     if (!state->pa_ok) {
968         /* Return any saved preauth e-data. */
969         *state->e_data_out = state->pa_e_data;
970         *state->typed_e_data_out = state->typed_e_data_flag;
971     } else
972         krb5_free_pa_data(state->context, state->pa_e_data);
973
974     if (state->pa_ok) {
975         free(state);
976         (*oldrespond)(oldarg, 0);
977         return;
978     }
979
980     /* pa system was not found; we may return PREAUTH_REQUIRED later,
981        but we did not actually fail to verify the pre-auth. */
982     if (!state->pa_found) {
983         free(state);
984         (*oldrespond)(oldarg, 0);
985         return;
986     }
987     free(state);
988
989     /* The following switch statement allows us
990      * to return some preauth system errors back to the client.
991      */
992     switch(code) {
993     case 0: /* in case of PA-PAC-REQUEST with no PA-ENC-TIMESTAMP */
994     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
995     case KRB5KRB_AP_ERR_SKEW:
996     case KRB5KDC_ERR_PREAUTH_REQUIRED:
997     case KRB5KDC_ERR_ETYPE_NOSUPP:
998         /* rfc 4556 */
999     case KRB5KDC_ERR_CLIENT_NOT_TRUSTED:
1000     case KRB5KDC_ERR_INVALID_SIG:
1001     case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
1002     case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
1003     case KRB5KDC_ERR_INVALID_CERTIFICATE:
1004     case KRB5KDC_ERR_REVOKED_CERTIFICATE:
1005     case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN:
1006     case KRB5KDC_ERR_CLIENT_NAME_MISMATCH:
1007     case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE:
1008     case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED:
1009     case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED:
1010     case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED:
1011     case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED:
1012         /* earlier drafts of what became rfc 4556 */
1013     case KRB5KDC_ERR_CERTIFICATE_MISMATCH:
1014     case KRB5KDC_ERR_KDC_NOT_TRUSTED:
1015     case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE:
1016         /* This value is shared with
1017          *     KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
1018         /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
1019     case KRB5KDC_ERR_DISCARD:
1020         /* pkinit alg-agility */
1021     case KRB5KDC_ERR_NO_ACCEPTABLE_KDF:
1022         (*oldrespond)(oldarg, code);
1023         return;
1024     default:
1025         (*oldrespond)(oldarg, KRB5KDC_ERR_PREAUTH_FAILED);
1026         return;
1027     }
1028 }
1029
1030 static void
1031 next_padata(struct padata_state *state);
1032
1033 static void
1034 finish_verify_padata(void *arg, krb5_error_code code,
1035                      krb5_kdcpreauth_modreq modreq, krb5_pa_data **e_data,
1036                      krb5_authdata **authz_data)
1037 {
1038     struct padata_state *state = arg;
1039     const char *emsg;
1040     krb5_boolean typed_e_data_flag;
1041
1042     assert(state);
1043     kdc_active_realm = state->realm; /* Restore the realm. */
1044     *state->modreq_ptr = modreq;
1045
1046     if (code) {
1047         emsg = krb5_get_error_message(state->context, code);
1048         krb5_klog_syslog(LOG_INFO, "preauth (%s) verify failure: %s",
1049                          state->pa_sys->name, emsg);
1050         krb5_free_error_message(state->context, emsg);
1051
1052         /* Ignore authorization data returned from modules that fail */
1053         if (authz_data != NULL) {
1054             krb5_free_authdata(state->context, authz_data);
1055             authz_data = NULL;
1056         }
1057
1058         typed_e_data_flag = ((state->pa_sys->flags & PA_TYPED_E_DATA) != 0);
1059
1060         /*
1061          * We'll return edata from either the first PA_REQUIRED module
1062          * that fails, or the first non-PA_REQUIRED module that fails.
1063          * Hang on to edata from the first non-PA_REQUIRED module.
1064          * If we've already got one saved, simply discard this one.
1065          */
1066         if (state->pa_sys->flags & PA_REQUIRED) {
1067             /* free up any previous edata we might have been saving */
1068             if (state->pa_e_data != NULL)
1069                 krb5_free_pa_data(state->context, state->pa_e_data);
1070             state->pa_e_data = e_data;
1071             state->typed_e_data_flag = typed_e_data_flag;
1072
1073             /* Make sure we use the current retval */
1074             state->pa_ok = 0;
1075             finish_check_padata(state, code);
1076             return;
1077         } else if (state->pa_e_data == NULL) {
1078             /* save the first error code and e-data */
1079             state->pa_e_data = e_data;
1080             state->typed_e_data_flag = typed_e_data_flag;
1081             state->saved_code = code;
1082         } else if (e_data != NULL) {
1083             /* discard this extra e-data from non-PA_REQUIRED module */
1084             krb5_free_pa_data(state->context, e_data);
1085         }
1086     } else {
1087 #ifdef DEBUG
1088         krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
1089 #endif
1090
1091         /* Ignore any edata returned on success */
1092         if (e_data != NULL)
1093             krb5_free_pa_data(state->context, e_data);
1094
1095         /* Add any authorization data to the ticket */
1096         if (authz_data != NULL) {
1097             add_authorization_data(state->enc_tkt_reply, authz_data);
1098             free(authz_data);
1099         }
1100
1101         state->pa_ok = 1;
1102         if (state->pa_sys->flags & PA_SUFFICIENT) {
1103             finish_check_padata(state, state->saved_code);
1104             return;
1105         }
1106     }
1107
1108     next_padata(state);
1109 }
1110
1111 static void
1112 next_padata(struct padata_state *state)
1113 {
1114     assert(state);
1115     if (!state->padata)
1116         state->padata = state->request->padata;
1117     else
1118         state->padata++;
1119
1120     if (!*state->padata) {
1121         finish_check_padata(state, state->saved_code);
1122         return;
1123     }
1124
1125 #ifdef DEBUG
1126     krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*state->padata)->pa_type);
1127 #endif
1128     if (find_pa_system((*state->padata)->pa_type, &state->pa_sys))
1129         goto next;
1130     if (find_modreq(state->pa_sys, *state->padata_context, &state->modreq_ptr))
1131         goto next;
1132 #ifdef DEBUG
1133     krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", state->pa_sys->name);
1134 #endif
1135     if (state->pa_sys->verify_padata == 0)
1136         goto next;
1137
1138     state->pa_found++;
1139     state->pa_sys->verify_padata(state->context, state->req_pkt,
1140                                  state->request, state->enc_tkt_reply,
1141                                  *state->padata, &callbacks, state->rock,
1142                                  state->pa_sys->moddata, finish_verify_padata,
1143                                  state);
1144     return;
1145
1146 next:
1147     next_padata(state);
1148 }
1149
1150 /*
1151  * This routine is called to verify the preauthentication information
1152  * for a V5 request.
1153  *
1154  * Returns 0 if the pre-authentication is valid, non-zero to indicate
1155  * an error code of some sort.
1156  */
1157
1158 void
1159 check_padata(krb5_context context, krb5_kdcpreauth_rock rock,
1160              krb5_data *req_pkt, krb5_kdc_req *request,
1161              krb5_enc_tkt_part *enc_tkt_reply, void **padata_context,
1162              krb5_pa_data ***e_data, krb5_boolean *typed_e_data,
1163              kdc_preauth_respond_fn respond, void *arg)
1164 {
1165     struct padata_state *state;
1166
1167     if (request->padata == 0) {
1168         (*respond)(arg, 0);
1169         return;
1170     }
1171
1172     if (make_padata_context(context, padata_context) != 0) {
1173         (*respond)(arg, KRB5KRB_ERR_GENERIC);
1174         return;
1175     }
1176
1177     state = calloc(1, sizeof(*state));
1178     if (state == NULL) {
1179         (*respond)(arg, ENOMEM);
1180         return;
1181     }
1182     state->respond = respond;
1183     state->arg = arg;
1184     state->context = context;
1185     state->rock = rock;
1186     state->req_pkt = req_pkt;
1187     state->request = request;
1188     state->enc_tkt_reply = enc_tkt_reply;
1189     state->padata_context = padata_context;
1190     state->e_data_out = e_data;
1191     state->typed_e_data_out = typed_e_data;
1192     state->realm = kdc_active_realm;
1193
1194 #ifdef DEBUG
1195     krb5_klog_syslog (LOG_DEBUG, "checking padata");
1196 #endif
1197
1198     next_padata(state);
1199 }
1200
1201 /*
1202  * return_padata creates any necessary preauthentication
1203  * structures which should be returned by the KDC to the client
1204  */
1205 krb5_error_code
1206 return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
1207               krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
1208               krb5_keyblock *encrypting_key, void **padata_context)
1209 {
1210     krb5_error_code             retval;
1211     krb5_pa_data **             padata;
1212     krb5_pa_data **             send_pa_list;
1213     krb5_pa_data **             send_pa;
1214     krb5_pa_data *              pa = 0;
1215     krb5_pa_data null_item;
1216     preauth_system *            ap;
1217     int *                       pa_order;
1218     int *                       pa_type;
1219     int                         size = 0;
1220     krb5_kdcpreauth_modreq      *modreq_ptr;
1221     krb5_boolean                key_modified;
1222     krb5_keyblock               original_key;
1223     if ((!*padata_context) &&
1224         (make_padata_context(context, padata_context) != 0)) {
1225         return KRB5KRB_ERR_GENERIC;
1226     }
1227
1228     for (ap = preauth_systems; ap->type != -1; ap++) {
1229         if (ap->return_padata)
1230             size++;
1231     }
1232
1233     if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
1234         return ENOMEM;
1235     if ((pa_order = malloc((size+1) * sizeof(int))) == NULL) {
1236         free(send_pa_list);
1237         return ENOMEM;
1238     }
1239     sort_pa_order(context, request, pa_order);
1240
1241     retval = krb5_copy_keyblock_contents(context, encrypting_key,
1242                                          &original_key);
1243     if (retval) {
1244         free(send_pa_list);
1245         free(pa_order);
1246         return retval;
1247     }
1248     key_modified = FALSE;
1249     null_item.contents = NULL;
1250     null_item.length = 0;
1251     send_pa = send_pa_list;
1252     *send_pa = 0;
1253
1254     for (pa_type = pa_order; *pa_type != -1; pa_type++) {
1255         ap = &preauth_systems[*pa_type];
1256         if (!key_modified)
1257             if (original_key.enctype != encrypting_key->enctype)
1258                 key_modified = TRUE;
1259         if (!key_modified)
1260             if (original_key.length != encrypting_key->length)
1261                 key_modified = TRUE;
1262         if (!key_modified)
1263             if (memcmp(original_key.contents, encrypting_key->contents,
1264                        original_key.length) != 0)
1265                 key_modified = TRUE;
1266         if (key_modified && (ap->flags & PA_REPLACES_KEY))
1267             continue;
1268         if (ap->return_padata == 0)
1269             continue;
1270         if (find_modreq(ap, *padata_context, &modreq_ptr))
1271             continue;
1272         pa = &null_item;
1273         null_item.pa_type = ap->type;
1274         if (request->padata) {
1275             for (padata = request->padata; *padata; padata++) {
1276                 if ((*padata)->pa_type == ap->type) {
1277                     pa = *padata;
1278                     break;
1279                 }
1280             }
1281         }
1282         retval = ap->return_padata(context, pa, req_pkt, request, reply,
1283                                    encrypting_key, send_pa, &callbacks, rock,
1284                                    ap->moddata, *modreq_ptr);
1285         if (retval)
1286             goto cleanup;
1287
1288         if (*send_pa)
1289             send_pa++;
1290         *send_pa = 0;
1291     }
1292
1293     retval = 0;
1294
1295     if (send_pa_list[0]) {
1296         reply->padata = send_pa_list;
1297         send_pa_list = 0;
1298     }
1299
1300 cleanup:
1301     krb5_free_keyblock_contents(context, &original_key);
1302     free(pa_order);
1303     if (send_pa_list)
1304         krb5_free_pa_data(context, send_pa_list);
1305
1306     return (retval);
1307 }
1308
1309 static krb5_boolean
1310 request_contains_enctype(krb5_context context,  const krb5_kdc_req *request,
1311                          krb5_enctype enctype)
1312 {
1313     int i;
1314     for (i =0; i < request->nktypes; i++)
1315         if (request->ktype[i] == enctype)
1316             return 1;
1317     return 0;
1318 }
1319
1320 static krb5_error_code
1321 _make_etype_info_entry(krb5_context context,
1322                        krb5_principal client_princ, krb5_key_data *client_key,
1323                        krb5_enctype etype, krb5_etype_info_entry **entry_out,
1324                        int etype_info2)
1325 {
1326     krb5_error_code retval;
1327     krb5_int16 salttype;
1328     krb5_data *salt = NULL;
1329     krb5_etype_info_entry *entry = NULL;
1330
1331     *entry_out = NULL;
1332     entry = malloc(sizeof(*entry));
1333     if (entry == NULL)
1334         return ENOMEM;
1335
1336     entry->magic = KV5M_ETYPE_INFO_ENTRY;
1337     entry->etype = etype;
1338     entry->length = KRB5_ETYPE_NO_SALT;
1339     entry->salt = NULL;
1340     entry->s2kparams = empty_data();
1341     retval = krb5_dbe_compute_salt(context, client_key, client_princ,
1342                                    &salttype, &salt);
1343     if (retval)
1344         goto cleanup;
1345     if (etype_info2 && salttype == KRB5_KDB_SALTTYPE_AFS3) {
1346         switch (etype) {
1347         case ENCTYPE_DES_CBC_CRC:
1348         case ENCTYPE_DES_CBC_MD4:
1349         case ENCTYPE_DES_CBC_MD5:
1350             retval = alloc_data(&entry->s2kparams, 1);
1351             if (retval)
1352                 goto cleanup;
1353             entry->s2kparams.data[0] = 1;
1354             break;
1355         default:
1356             break;
1357         }
1358     }
1359
1360     entry->length = salt->length;
1361     entry->salt = (unsigned char *)salt->data;
1362     salt->data = NULL;
1363     *entry_out = entry;
1364     entry = NULL;
1365
1366 cleanup:
1367     if (entry != NULL)
1368         krb5_free_data_contents(context, &entry->s2kparams);
1369     free(entry);
1370     krb5_free_data(context, salt);
1371     return retval;
1372 }
1373
1374 /* Create etype information for a client for the preauth-required hint list,
1375  * for either etype-info or etype-info2. */
1376 static void
1377 etype_info_helper(krb5_context context, krb5_kdc_req *request,
1378                   krb5_db_entry *client, krb5_preauthtype pa_type,
1379                   krb5_kdcpreauth_edata_respond_fn respond, void *arg)
1380 {
1381     krb5_error_code retval;
1382     krb5_pa_data *pa = NULL;
1383     krb5_etype_info_entry **entry = NULL;
1384     krb5_data *scratch = NULL;
1385     krb5_key_data *client_key;
1386     krb5_enctype db_etype;
1387     int i = 0, start = 0, seen_des = 0;
1388     int etype_info2 = (pa_type == KRB5_PADATA_ETYPE_INFO2);
1389
1390     entry = k5alloc((client->n_key_data * 2 + 1) * sizeof(*entry), &retval);
1391     if (entry == NULL)
1392         goto cleanup;
1393     entry[0] = NULL;
1394
1395     while (1) {
1396         retval = krb5_dbe_search_enctype(context, client, &start, -1,
1397                                          -1, 0, &client_key);
1398         if (retval == KRB5_KDB_NO_MATCHING_KEY)
1399             break;
1400         if (retval)
1401             goto cleanup;
1402         db_etype = client_key->key_data_type[0];
1403         if (db_etype == ENCTYPE_DES_CBC_MD4)
1404             db_etype = ENCTYPE_DES_CBC_MD5;
1405
1406         if (request_contains_enctype(context, request, db_etype)) {
1407             assert(etype_info2 ||
1408                    !enctype_requires_etype_info_2(db_etype));
1409             retval = _make_etype_info_entry(context, client->princ, client_key,
1410                                             db_etype, &entry[i], etype_info2);
1411             if (retval != 0)
1412                 goto cleanup;
1413             i++;
1414         }
1415
1416         /*
1417          * If there is a des key in the kdb, try the "similar" enctypes,
1418          * avoid duplicate entries.
1419          */
1420         if (!seen_des) {
1421             switch (db_etype) {
1422             case ENCTYPE_DES_CBC_MD5:
1423                 db_etype = ENCTYPE_DES_CBC_CRC;
1424                 break;
1425             case ENCTYPE_DES_CBC_CRC:
1426                 db_etype = ENCTYPE_DES_CBC_MD5;
1427                 break;
1428             default:
1429                 continue;
1430
1431             }
1432             if (request_contains_enctype(context, request, db_etype)) {
1433                 retval = _make_etype_info_entry(context, client->princ,
1434                                                 client_key, db_etype,
1435                                                 &entry[i], etype_info2);
1436                 if (retval != 0)
1437                     goto cleanup;
1438                 entry[i+1] = 0;
1439                 i++;
1440             }
1441             seen_des++;
1442         }
1443     }
1444     if (etype_info2)
1445         retval = encode_krb5_etype_info2(entry, &scratch);
1446     else
1447         retval = encode_krb5_etype_info(entry, &scratch);
1448     if (retval)
1449         goto cleanup;
1450     pa = k5alloc(sizeof(*pa), &retval);
1451     if (pa == NULL)
1452         goto cleanup;
1453     pa->magic = KV5M_PA_DATA;
1454     pa->pa_type = pa_type;
1455     pa->contents = (unsigned char *)scratch->data;
1456     pa->length = scratch->length;
1457     scratch->data = NULL;
1458
1459 cleanup:
1460     krb5_free_etype_info(context, entry);
1461     krb5_free_data(context, scratch);
1462     (*respond)(arg, retval, pa);
1463 }
1464
1465 static void
1466 get_etype_info(krb5_context context, krb5_kdc_req *request,
1467                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
1468                krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
1469                krb5_kdcpreauth_edata_respond_fn respond, void *arg)
1470 {
1471     int i;
1472
1473     for (i=0;  i < request->nktypes; i++) {
1474         if (enctype_requires_etype_info_2(request->ktype[i])) {
1475             /* Requestor understands etype-info2, so don't send etype-info. */
1476             (*respond)(arg, KRB5KDC_ERR_PADATA_TYPE_NOSUPP, NULL);
1477             return;
1478         }
1479     }
1480
1481     etype_info_helper(context, request, rock->client, pa_type, respond, arg);
1482 }
1483
1484 static void
1485 get_etype_info2(krb5_context context, krb5_kdc_req *request,
1486                 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
1487                 krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
1488                 krb5_kdcpreauth_edata_respond_fn respond, void *arg)
1489 {
1490     etype_info_helper(context, request, rock->client, pa_type, respond, arg);
1491 }
1492
1493 static krb5_error_code
1494 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
1495                          krb5_db_entry *client,
1496                          krb5_kdc_req *request, krb5_kdc_rep *reply,
1497                          krb5_key_data *client_key,
1498                          krb5_keyblock *encrypting_key,
1499                          krb5_pa_data **send_pa,
1500                          int etype_info2)
1501 {
1502     int i;
1503     krb5_error_code retval;
1504     krb5_pa_data *tmp_padata;
1505     krb5_etype_info_entry **entry = NULL;
1506     krb5_data *scratch = NULL;
1507
1508     /*
1509      * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer"
1510      * enctypes.
1511      */
1512     if (!etype_info2) {
1513         for (i = 0; i < request->nktypes; i++) {
1514             if (enctype_requires_etype_info_2(request->ktype[i])) {
1515                 *send_pa = NULL;
1516                 return 0;
1517             }
1518         }
1519     }
1520
1521     tmp_padata = malloc( sizeof(krb5_pa_data));
1522     if (tmp_padata == NULL)
1523         return ENOMEM;
1524     if (etype_info2)
1525         tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2;
1526     else
1527         tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO;
1528
1529     entry = malloc(2 * sizeof(krb5_etype_info_entry *));
1530     if (entry == NULL) {
1531         retval = ENOMEM;
1532         goto cleanup;
1533     }
1534     entry[0] = NULL;
1535     entry[1] = NULL;
1536     retval = _make_etype_info_entry(context, client->princ, client_key,
1537                                     encrypting_key->enctype, entry,
1538                                     etype_info2);
1539     if (retval)
1540         goto cleanup;
1541
1542     if (etype_info2)
1543         retval = encode_krb5_etype_info2(entry, &scratch);
1544     else
1545         retval = encode_krb5_etype_info(entry, &scratch);
1546
1547     if (retval)
1548         goto cleanup;
1549     tmp_padata->contents = (krb5_octet *)scratch->data;
1550     tmp_padata->length = scratch->length;
1551     *send_pa = tmp_padata;
1552
1553     /* For cleanup - we no longer own the contents of the krb5_data
1554      * only to pointer to the krb5_data
1555      */
1556     scratch->data = 0;
1557
1558 cleanup:
1559     if (entry)
1560         krb5_free_etype_info(context, entry);
1561     if (retval) {
1562         if (tmp_padata)
1563             free(tmp_padata);
1564     }
1565     if (scratch)
1566         krb5_free_data(context, scratch);
1567     return retval;
1568 }
1569
1570 static krb5_error_code
1571 return_etype_info2(krb5_context context, krb5_pa_data * padata,
1572                    krb5_data *req_pkt, krb5_kdc_req *request,
1573                    krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
1574                    krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
1575                    krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
1576                    krb5_kdcpreauth_modreq modreq)
1577 {
1578     return etype_info_as_rep_helper(context, padata, rock->client, request,
1579                                     reply, rock->client_key, encrypting_key,
1580                                     send_pa, 1);
1581 }
1582
1583
1584 static krb5_error_code
1585 return_etype_info(krb5_context context, krb5_pa_data *padata,
1586                   krb5_data *req_pkt, krb5_kdc_req *request,
1587                   krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
1588                   krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
1589                   krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
1590                   krb5_kdcpreauth_modreq modreq)
1591 {
1592     return etype_info_as_rep_helper(context, padata, rock->client, request,
1593                                     reply, rock->client_key, encrypting_key,
1594                                     send_pa, 0);
1595 }
1596
1597 static krb5_error_code
1598 return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
1599                krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
1600                krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
1601                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
1602                krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
1603 {
1604     krb5_error_code     retval;
1605     krb5_pa_data *      padata;
1606     krb5_data *         salt = NULL;
1607     krb5_int16          salttype;
1608     krb5_key_data *     client_key = rock->client_key;
1609     int i;
1610
1611     for (i = 0; i < request->nktypes; i++) {
1612         if (enctype_requires_etype_info_2(request->ktype[i]))
1613             return 0;
1614     }
1615     retval = krb5_dbe_compute_salt(context, client_key, request->client,
1616                                    &salttype, &salt);
1617     if (retval)
1618         return 0;
1619
1620     padata = k5alloc(sizeof(*padata), &retval);
1621     if (padata == NULL)
1622         goto cleanup;
1623     padata->magic = KV5M_PA_DATA;
1624
1625     if (salttype == KRB5_KDB_SALTTYPE_AFS3) {
1626         padata->contents = k5alloc(salt->length + 1, &retval);
1627         if (padata->contents == NULL)
1628             goto cleanup;
1629         memcpy(padata->contents, salt->data, salt->length);
1630         padata->pa_type = KRB5_PADATA_AFS3_SALT;
1631         padata->contents[salt->length] = '\0';
1632         padata->length = salt->length + 1;
1633     } else {
1634         padata->pa_type = KRB5_PADATA_PW_SALT;
1635         padata->length = salt->length;
1636         padata->contents = (krb5_octet *)salt->data;
1637         salt->data = NULL;
1638     }
1639
1640     *send_pa = padata;
1641     padata = NULL;
1642
1643 cleanup:
1644     free(padata);
1645     krb5_free_data(context, salt);
1646     return retval;
1647 }
1648
1649
1650
1651 #if APPLE_PKINIT
1652 /* PKINIT preauth support */
1653 #define  PKINIT_DEBUG    0
1654 #if     PKINIT_DEBUG
1655 #define kdcPkinitDebug(args...)       printf(args)
1656 #else
1657 #define kdcPkinitDebug(args...)
1658 #endif
1659
1660 /*
1661  * get_edata() - our only job is to determine whether this KDC is capable of
1662  * performing PKINIT. We infer that from the presence or absence of any
1663  * KDC signing cert.
1664  */
1665 static krb5_error_code get_pkinit_edata(
1666     krb5_context context,
1667     krb5_kdc_req *request,
1668     krb5_db_entry *client,
1669     krb5_db_entry *server,
1670     preauth_get_entry_data_proc pkinit_get_entry_data,
1671     void *pa_module_context,
1672     krb5_pa_data *pa_data)
1673 {
1674     krb5_pkinit_signing_cert_t cert = NULL;
1675     krb5_error_code err = krb5_pkinit_get_kdc_cert(0, NULL, NULL, &cert);
1676
1677     kdcPkinitDebug("get_pkinit_edata: kdc cert %s\n", err ? "NOT FOUND" : "FOUND");
1678     if(cert) {
1679         krb5_pkinit_release_cert(cert);
1680     }
1681     return err;
1682 }
1683
1684 /*
1685  * This is 0 only for testing until the KDC DB contains
1686  * the hash of the client cert
1687  */
1688 #define REQUIRE_CLIENT_CERT_MATCH   1
1689
1690 static krb5_error_code verify_pkinit_request(
1691     krb5_context context,
1692     krb5_db_entry *client,
1693     krb5_data *req_pkt,
1694     krb5_kdc_req *request,
1695     krb5_enc_tkt_part *enc_tkt_reply,
1696     krb5_pa_data *data,
1697     preauth_get_entry_data_proc pkinit_get_entry_data,
1698     void *pa_module_context,
1699     void **pa_request_context,
1700     krb5_data **e_data,
1701     krb5_authdata ***authz_data)
1702 {
1703     krb5_error_code         krtn;
1704     krb5_data               pa_data;
1705     krb5_data               *der_req = NULL;
1706     krb5_boolean            valid_cksum;
1707     char                    *cert_hash = NULL;
1708     unsigned                cert_hash_len;
1709     unsigned                key_dex;
1710     unsigned                cert_match = 0;
1711     krb5_keyblock           decrypted_key, *mkey_ptr;
1712
1713     /* the data we get from the AS-REQ */
1714     krb5_timestamp          client_ctime = 0;
1715     krb5_ui_4               client_cusec = 0;
1716     krb5_timestamp          kdc_ctime = 0;
1717     krb5_int32              kdc_cusec = 0;
1718     krb5_ui_4               nonce = 0;
1719     krb5_checksum           pa_cksum;
1720     krb5int_cert_sig_status cert_sig_status;
1721     krb5_data               client_cert = {0, 0, NULL};
1722
1723     krb5_kdc_req *tmp_as_req = NULL;
1724
1725     kdcPkinitDebug("verify_pkinit_request\n");
1726
1727     decrypted_key.contents = NULL;
1728     pa_data.data = (char *)data->contents;
1729     pa_data.length = data->length;
1730     krtn = krb5int_pkinit_as_req_parse(context, &pa_data,
1731                                        &client_ctime, &client_cusec,
1732                                        &nonce, &pa_cksum,
1733                                        &cert_sig_status,
1734                                        NULL, NULL,/* num_cms_types, cms_types */
1735                                        &client_cert,       /* signer_cert */
1736                                        /* remaining fields unused (for now) */
1737                                        NULL, NULL,/* num_all_certs, all_certs */
1738                                        NULL, NULL,/* num_trusted_CAs, trusted_CAs */
1739                                        NULL);     /* kdc_cert */
1740     if(krtn) {
1741         kdcPkinitDebug("pa_pk_as_req_parse returned %d; PKINIT aborting.\n",
1742                        (int)krtn);
1743         return krtn;
1744     }
1745 #if     PKINIT_DEBUG
1746     if(cert_sig_status != pki_cs_good) {
1747         kdcPkinitDebug("verify_pkinit_request: cert_sig_status %d\n",
1748                        (int)cert_sig_status);
1749     }
1750 #endif  /* PKINIT_DEBUG */
1751
1752     /*
1753      * Verify signature and cert.
1754      * FIXME: The spec calls for an e-data with error-specific type to be
1755      * returned on error here. TD_TRUSTED_CERTIFIERS
1756      * to be returned to the client here. There is no way for a preauth
1757      * module to pass back e-data to process_as_req at this time. We
1758      * might want to add such capability via an out param to check_padata
1759      * and to its callees.
1760      */
1761     switch(cert_sig_status) {
1762     case pki_cs_good:
1763         break;
1764     case pki_cs_sig_verify_fail:
1765         /* no e-data */
1766         krtn = KDC_ERR_INVALID_SIG;
1767         goto cleanup;
1768     case pki_cs_no_root:
1769     case pki_cs_unknown_root:
1770     case pki_cs_untrusted:
1771         /*
1772          * Can't verify to known root.
1773          * e-data TD_TRUSTED_CERTIFIERS
1774          */
1775         kdcPkinitDebug("verify_pkinit_request: KDC_ERR_CANT_VERIFY_CERTIFICATE\n");
1776         krtn = KDC_ERR_CANT_VERIFY_CERTIFICATE;
1777         goto cleanup;
1778     case pki_cs_bad_leaf:
1779     case pki_cs_expired:
1780     case pki_cs_not_valid_yet:
1781         /*
1782          * Problems with client cert itself.
1783          * e-data type TD_INVALID_CERTIFICATES
1784          */
1785         krtn = KDC_ERR_INVALID_CERTIFICATE;
1786         goto cleanup;
1787     case pki_cs_revoked:
1788         /* e-data type TD-INVALID-CERTIFICATES */
1789         krtn = KDC_ERR_REVOKED_CERTIFICATE;
1790         goto cleanup;
1791     case pki_bad_key_use:
1792         krtn = KDC_ERR_INCONSISTENT_KEY_PURPOSE;
1793         /* no e-data */
1794         goto cleanup;
1795     case pki_bad_digest:
1796         /* undefined (explicitly!) e-data */
1797         krtn = KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
1798         goto cleanup;
1799     case pki_bad_cms:
1800     case pki_cs_other_err:
1801     default:
1802         krtn = KRB5KDC_ERR_PREAUTH_FAILED;
1803         goto cleanup;
1804     }
1805
1806     krtn = krb5_us_timeofday(context, &kdc_ctime, &kdc_cusec);
1807     if(krtn) {
1808         goto cleanup;
1809     }
1810     if (labs(kdc_ctime - client_ctime) > context->clockskew) {
1811         kdcPkinitDebug("verify_pkinit_request: clock skew violation client %d svr %d\n",
1812                        (int)client_ctime, (int)kdc_ctime);
1813         krtn = KRB5KRB_AP_ERR_SKEW;
1814         goto cleanup;
1815     }
1816
1817     /*
1818      * The KDC may have modified the request after decoding it.
1819      * We need to compute the checksum on the data that
1820      * came from the client.  Therefore, we use the original
1821      * packet contents.
1822      */
1823     krtn = decode_krb5_as_req(req_pkt, &tmp_as_req);
1824     if(krtn) {
1825         kdcPkinitDebug("decode_krb5_as_req returned %d\n", (int)krtn);
1826         goto cleanup;
1827     }
1828
1829     /* calculate and compare checksum */
1830     krtn = encode_krb5_kdc_req_body(tmp_as_req, &der_req);
1831     if(krtn) {
1832         kdcPkinitDebug("encode_krb5_kdc_req_body returned %d\n", (int)krtn);
1833         goto cleanup;
1834     }
1835     krtn = krb5_c_verify_checksum(context, NULL, 0, der_req,
1836                                   &pa_cksum, &valid_cksum);
1837     if(krtn) {
1838         kdcPkinitDebug("krb5_c_verify_checksum returned %d\n", (int)krtn);
1839         goto cleanup;
1840     }
1841     if(!valid_cksum) {
1842         kdcPkinitDebug("verify_pkinit_request: checksum error\n");
1843         krtn = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1844         goto cleanup;
1845     }
1846
1847 #if REQUIRE_CLIENT_CERT_MATCH
1848     /* look up in the KDB to ensure correct client/cert binding */
1849     cert_hash = krb5_pkinit_cert_hash_str(&client_cert);
1850     if(cert_hash == NULL) {
1851         krtn = ENOMEM;
1852         goto cleanup;
1853     }
1854     cert_hash_len = strlen(cert_hash);
1855     for(key_dex=0; key_dex<client->n_key_data; key_dex++) {
1856         krb5_key_data *key_data = &client->key_data[key_dex];
1857         kdcPkinitDebug("--- key %u type[0] %u length[0] %u type[1] %u length[1] %u\n",
1858                        key_dex,
1859                        key_data->key_data_type[0], key_data->key_data_length[0],
1860                        key_data->key_data_type[1], key_data->key_data_length[1]);
1861         if(key_data->key_data_type[1] != KRB5_KDB_SALTTYPE_CERTHASH) {
1862             continue;
1863         }
1864
1865         /*
1866          * Unfortunately this key is stored encrypted even though it's
1867          * not sensitive...
1868          */
1869         krtn = krb5_dbe_decrypt_key_data(context, NULL, key_data,
1870                                          &decrypted_key, NULL);
1871         if(krtn) {
1872             kdcPkinitDebug("verify_pkinit_request: error decrypting cert hash block\n");
1873             break;
1874         }
1875         if((decrypted_key.contents != NULL) &&
1876            (cert_hash_len == decrypted_key.length) &&
1877            !memcmp(decrypted_key.contents, cert_hash, cert_hash_len)) {
1878             cert_match = 1;
1879             break;
1880         }
1881     }
1882     if(decrypted_key.contents) {
1883         krb5_free_keyblock_contents(context, &decrypted_key);
1884     }
1885     if(!cert_match) {
1886         kdcPkinitDebug("verify_pkinit_request: client cert does not match\n");
1887         krtn = KDC_ERR_CLIENT_NOT_TRUSTED;
1888         goto cleanup;
1889     }
1890 #endif   /* REQUIRE_CLIENT_CERT_MATCH */
1891     krtn = 0;
1892     setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
1893
1894 cleanup:
1895     if(pa_cksum.contents) {
1896         free(pa_cksum.contents);
1897     }
1898     if (tmp_as_req) {
1899         krb5_free_kdc_req(context, tmp_as_req);
1900     }
1901     if (der_req) {
1902         krb5_free_data(context, der_req);
1903     }
1904     if(cert_hash) {
1905         free(cert_hash);
1906     }
1907     if(client_cert.data) {
1908         free(client_cert.data);
1909     }
1910     kdcPkinitDebug("verify_pkinit_request: returning %d\n", (int)krtn);
1911     return krtn;
1912 }
1913
1914 static krb5_error_code return_pkinit_response(
1915     krb5_context context,
1916     krb5_pa_data * padata,
1917     krb5_db_entry *client,
1918     krb5_data *req_pkt,
1919     krb5_kdc_req *request,
1920     krb5_kdc_rep *reply,
1921     krb5_key_data *client_key,
1922     krb5_keyblock *encrypting_key,
1923     krb5_pa_data **send_pa,
1924     preauth_get_entry_data_proc pkinit_get_entry_data,
1925     void *pa_module_context,
1926     void **pa_request_context)
1927 {
1928     krb5_error_code             krtn;
1929     krb5_data                   pa_data;
1930     krb5_pkinit_signing_cert_t  signing_cert = NULL;
1931     krb5_checksum               as_req_checksum = {0};
1932     krb5_data                   *encoded_as_req = NULL;
1933     krb5int_algorithm_id        *cms_types = NULL;
1934     krb5_ui_4                   num_cms_types = 0;
1935
1936     /* the data we get from the AS-REQ */
1937     krb5_ui_4                   nonce = 0;
1938     krb5_data                   client_cert = {0};
1939
1940     /*
1941      * Trusted CA list and specific KC cert optionally obtained via
1942      * krb5int_pkinit_as_req_parse(). All are DER-encoded
1943      * issuerAndSerialNumbers.
1944      */
1945     krb5_data                   *trusted_CAs = NULL;
1946     krb5_ui_4                   num_trusted_CAs;
1947     krb5_data                   kdc_cert = {0};
1948
1949     if (padata == NULL) {
1950         /* Client has to send us something */
1951         return 0;
1952     }
1953
1954     kdcPkinitDebug("return_pkinit_response\n");
1955     pa_data.data = (char *)padata->contents;
1956     pa_data.length = padata->length;
1957
1958     /*
1959      * We've already verified; just obtain the fields we need to create a response
1960      */
1961     krtn = krb5int_pkinit_as_req_parse(context,
1962                                        &pa_data,
1963                                        NULL, NULL, &nonce,     /* ctime, cusec, nonce */
1964                                        NULL, NULL,             /* pa_cksum, cert_status */
1965                                        &num_cms_types, &cms_types,
1966                                        &client_cert,   /* signer_cert: we encrypt for this */
1967                                        /* remaining fields unused (for now) */
1968                                        NULL, NULL,     /* num_all_certs, all_certs */
1969                                        &num_trusted_CAs, &trusted_CAs,
1970                                        &kdc_cert);
1971     if(krtn) {
1972         kdcPkinitDebug("pa_pk_as_req_parse returned %d; PKINIT aborting.\n",
1973                        (int)krtn);
1974         goto cleanup;
1975     }
1976     if(client_cert.data == NULL) {
1977         kdcPkinitDebug("pa_pk_as_req_parse failed to give a client_cert; aborting.\n");
1978         krtn = KRB5KDC_ERR_PREAUTH_FAILED;
1979         goto cleanup;
1980     }
1981
1982     if(krb5_pkinit_get_kdc_cert(num_trusted_CAs, trusted_CAs,
1983                                 (kdc_cert.data ? &kdc_cert : NULL),
1984                                 &signing_cert)) {
1985         /*
1986          * Since get_pkinit_edata was able to obtain *some* KDC cert,
1987          * this means that we can't satisfy the client's requirement.
1988          * FIXME - particular error status for this?
1989          */
1990         kdcPkinitDebug("return_pkinit_response: NO appropriate signing cert!\n");
1991         krtn = KRB5KDC_ERR_PREAUTH_FAILED;
1992         goto cleanup;
1993     }
1994
1995     /*
1996      * Cook up keyblock for caller and for outgoing AS-REP.
1997      * FIXME how much is known to be valid about encrypting_key?
1998      * Will encrypting_key->enctype always be valid here? Seems that
1999      * if we allow for clients without a shared secret (i.e. preauth
2000      * by PKINIT only) there won't be a valid encrypting_key set up
2001      * here for us.
2002      */
2003     krb5_free_keyblock_contents(context, encrypting_key);
2004     krb5_c_make_random_key(context, encrypting_key->enctype, encrypting_key);
2005
2006     /* calculate checksum of incoming AS-REQ */
2007     krtn = encode_krb5_as_req(request, &encoded_as_req);
2008     if(krtn) {
2009         kdcPkinitDebug("encode_krb5_as_req returned %d; PKINIT aborting.\n", (int)krtn);
2010         goto cleanup;
2011     }
2012     krtn = krb5_c_make_checksum(context, context->kdc_req_sumtype,
2013                                 encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
2014                                 encoded_as_req, &as_req_checksum);
2015     if(krtn) {
2016         goto cleanup;
2017     }
2018
2019     /*
2020      * FIXME: here we assume that the client has one cert - the one that
2021      * signed the AuthPack in the request (and that we therefore obtained from
2022      * krb5int_pkinit_as_req_parse()), and the one we're using to encrypt the
2023      * ReplyKeyPack with here. This may need rethinking.
2024      */
2025     krtn = krb5int_pkinit_as_rep_create(context,
2026                                         encrypting_key, &as_req_checksum,
2027                                         signing_cert, TRUE,
2028                                         &client_cert,
2029                                         num_cms_types, cms_types,
2030                                         num_trusted_CAs, trusted_CAs,
2031                                         (kdc_cert.data ? &kdc_cert : NULL),
2032                                         &pa_data);
2033     if(krtn) {
2034         kdcPkinitDebug("pa_pk_as_rep_create returned %d; PKINIT aborting.\n",
2035                        (int)krtn);
2036         goto cleanup;
2037     }
2038
2039     *send_pa = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
2040     if(*send_pa == NULL) {
2041         krtn = ENOMEM;
2042         free(pa_data.data);
2043         goto cleanup;
2044     }
2045     (*send_pa)->magic = KV5M_PA_DATA;
2046     (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
2047     (*send_pa)->length = pa_data.length;
2048     (*send_pa)->contents = (krb5_octet *)pa_data.data;
2049     krtn = 0;
2050
2051 #if PKINIT_DEBUG
2052     fprintf(stderr, "return_pkinit_response: SUCCESS\n");
2053     fprintf(stderr, "nonce 0x%x enctype %d keydata %02x %02x %02x %02x...\n",
2054             (int)nonce, (int)encrypting_key->enctype,
2055             encrypting_key->contents[0], encrypting_key->contents[1],
2056             encrypting_key->contents[2], encrypting_key->contents[3]);
2057 #endif
2058
2059 cleanup:
2060     /* all of this was allocd by krb5int_pkinit_as_req_parse() */
2061     if(signing_cert) {
2062         krb5_pkinit_release_cert(signing_cert);
2063     }
2064     if(cms_types) {
2065         unsigned dex;
2066         krb5int_algorithm_id *alg_id;
2067
2068         for(dex=0; dex<num_cms_types; dex++) {
2069             alg_id = &cms_types[dex];
2070             if(alg_id->algorithm.data) {
2071                 free(alg_id->algorithm.data);
2072             }
2073             if(alg_id->parameters.data) {
2074                 free(alg_id->parameters.data);
2075             }
2076         }
2077         free(cms_types);
2078     }
2079     if(trusted_CAs) {
2080         unsigned dex;
2081         for(dex=0; dex<num_trusted_CAs; dex++) {
2082             free(trusted_CAs[dex].data);
2083         }
2084         free(trusted_CAs);
2085     }
2086     if(kdc_cert.data) {
2087         free(kdc_cert.data);
2088     }
2089     if(client_cert.data) {
2090         free(client_cert.data);
2091     }
2092     if(encoded_as_req) {
2093         krb5_free_data(context, encoded_as_req);
2094     }
2095     return krtn;
2096 }
2097
2098 #endif /* APPLE_PKINIT */
2099
2100 /*
2101  * Returns TRUE if the PAC should be included
2102  */
2103 krb5_boolean
2104 include_pac_p(krb5_context context, krb5_kdc_req *request)
2105 {
2106     krb5_error_code             code;
2107     krb5_pa_data                **padata;
2108     krb5_boolean                retval = TRUE; /* default is to return PAC */
2109     krb5_data                   data;
2110     krb5_pa_pac_req             *req = NULL;
2111
2112     if (request->padata == NULL) {
2113         return retval;
2114     }
2115
2116     for (padata = request->padata; *padata != NULL; padata++) {
2117         if ((*padata)->pa_type == KRB5_PADATA_PAC_REQUEST) {
2118             data.data = (char *)(*padata)->contents;
2119             data.length = (*padata)->length;
2120
2121             code = decode_krb5_pa_pac_req(&data, &req);
2122             if (code == 0) {
2123                 retval = req->include_pac;
2124                 krb5_free_pa_pac_req(context, req);
2125                 req = NULL;
2126             }
2127             break;
2128         }
2129     }
2130
2131     return retval;
2132 }
2133
2134 static krb5_error_code
2135 return_referral_enc_padata( krb5_context context,
2136                             krb5_enc_kdc_rep_part *reply,
2137                             krb5_db_entry *server)
2138 {
2139     krb5_error_code             code;
2140     krb5_tl_data                tl_data;
2141     krb5_pa_data                pa_data;
2142
2143     tl_data.tl_data_type = KRB5_TL_SVR_REFERRAL_DATA;
2144     code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
2145     if (code || tl_data.tl_data_length == 0)
2146         return 0;
2147
2148     pa_data.magic = KV5M_PA_DATA;
2149     pa_data.pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
2150     pa_data.length = tl_data.tl_data_length;
2151     pa_data.contents = tl_data.tl_data_contents;
2152     return add_pa_data_element(context, &pa_data, &reply->enc_padata, TRUE);
2153 }
2154
2155 krb5_error_code
2156 return_enc_padata(krb5_context context, krb5_data *req_pkt,
2157                   krb5_kdc_req *request, krb5_keyblock *reply_key,
2158                   krb5_db_entry *server, krb5_enc_kdc_rep_part *reply_encpart,
2159                   krb5_boolean is_referral)
2160 {
2161     krb5_error_code code = 0;
2162     /* This should be initialized and only used for Win2K compat and other
2163      * specific standardized uses such as FAST negotiation. */
2164     assert(reply_encpart->enc_padata == NULL);
2165     if (is_referral) {
2166         code = return_referral_enc_padata(context, reply_encpart, server);
2167         if (code)
2168             return code;
2169     }
2170     code = kdc_handle_protected_negotiation(req_pkt, request, reply_key,
2171                                             &reply_encpart->enc_padata);
2172     if (code)
2173         goto cleanup;
2174     /*Add potentially other enc_padata providers*/
2175 cleanup:
2176     return code;
2177 }
2178
2179
2180 #if 0
2181 static krb5_error_code return_server_referral(krb5_context context,
2182                                               krb5_pa_data * padata,
2183                                               krb5_db_entry *client,
2184                                               krb5_db_entry *server,
2185                                               krb5_kdc_req *request,
2186                                               krb5_kdc_rep *reply,
2187                                               krb5_key_data *client_key,
2188                                               krb5_keyblock *encrypting_key,
2189                                               krb5_pa_data **send_pa)
2190 {
2191     krb5_error_code             code;
2192     krb5_tl_data                tl_data;
2193     krb5_pa_data                *pa_data;
2194     krb5_enc_data               enc_data;
2195     krb5_data                   plain;
2196     krb5_data                   *enc_pa_data;
2197
2198     *send_pa = NULL;
2199
2200     tl_data.tl_data_type = KRB5_TL_SERVER_REFERRAL;
2201
2202     code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
2203     if (code || tl_data.tl_data_length == 0)
2204         return 0; /* no server referrals to return */
2205
2206     plain.length = tl_data.tl_data_length;
2207     plain.data = tl_data.tl_data_contents;
2208
2209     /* Encrypt ServerReferralData */
2210     code = krb5_encrypt_helper(context, encrypting_key,
2211                                KRB5_KEYUSAGE_PA_SERVER_REFERRAL_DATA,
2212                                &plain, &enc_data);
2213     if (code)
2214         return code;
2215
2216     /* Encode ServerReferralData into PA-SERVER-REFERRAL-DATA */
2217     code = encode_krb5_enc_data(&enc_data, &enc_pa_data);
2218     if (code) {
2219         krb5_free_data_contents(context, &enc_data.ciphertext);
2220         return code;
2221     }
2222
2223     krb5_free_data_contents(context, &enc_data.ciphertext);
2224
2225     /* Return PA-SERVER-REFERRAL-DATA */
2226     pa_data = (krb5_pa_data *)malloc(sizeof(*pa_data));
2227     if (pa_data == NULL) {
2228         krb5_free_data(context, enc_pa_data);
2229         return ENOMEM;
2230     }
2231
2232     pa_data->magic = KV5M_PA_DATA;
2233     pa_data->pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
2234     pa_data->length = enc_pa_data->length;
2235     pa_data->contents = enc_pa_data->data;
2236
2237     free(enc_pa_data); /* don't free contents */
2238
2239     *send_pa = pa_data;
2240
2241     return 0;
2242 }
2243 #endif