xref: /freebsd/crypto/krb5/src/kdc/kdc_preauth.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* kdc/kdc_preauth.c - Preauthentication routines for the KDC */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 1995, 2003, 2007, 2009 by the Massachusetts Institute of
5*7f2fe78bSCy Schubert  * Technology.  All Rights Reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert /*
27*7f2fe78bSCy Schubert  * Copyright (C) 1998 by the FundsXpress, INC.
28*7f2fe78bSCy Schubert  *
29*7f2fe78bSCy Schubert  * All rights reserved.
30*7f2fe78bSCy Schubert  *
31*7f2fe78bSCy Schubert  * Export of this software from the United States of America may require
32*7f2fe78bSCy Schubert  * a specific license from the United States Government.  It is the
33*7f2fe78bSCy Schubert  * responsibility of any person or organization contemplating export to
34*7f2fe78bSCy Schubert  * obtain such a license before exporting.
35*7f2fe78bSCy Schubert  *
36*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
38*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
39*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
40*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
41*7f2fe78bSCy Schubert  * the name of FundsXpress. not be used in advertising or publicity pertaining
42*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
43*7f2fe78bSCy Schubert  * permission.  FundsXpress makes no representations about the suitability of
44*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
45*7f2fe78bSCy Schubert  * or implied warranty.
46*7f2fe78bSCy Schubert  *
47*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48*7f2fe78bSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49*7f2fe78bSCy Schubert  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
50*7f2fe78bSCy Schubert  */
51*7f2fe78bSCy Schubert /*
52*7f2fe78bSCy Schubert  * Copyright (c) 2006-2008, Novell, Inc.
53*7f2fe78bSCy Schubert  * All rights reserved.
54*7f2fe78bSCy Schubert  *
55*7f2fe78bSCy Schubert  * Redistribution and use in source and binary forms, with or without
56*7f2fe78bSCy Schubert  * modification, are permitted provided that the following conditions are met:
57*7f2fe78bSCy Schubert  *
58*7f2fe78bSCy Schubert  *   * Redistributions of source code must retain the above copyright notice,
59*7f2fe78bSCy Schubert  *       this list of conditions and the following disclaimer.
60*7f2fe78bSCy Schubert  *   * Redistributions in binary form must reproduce the above copyright
61*7f2fe78bSCy Schubert  *       notice, this list of conditions and the following disclaimer in the
62*7f2fe78bSCy Schubert  *       documentation and/or other materials provided with the distribution.
63*7f2fe78bSCy Schubert  *   * The copyright holder's name is not used to endorse or promote products
64*7f2fe78bSCy Schubert  *       derived from this software without specific prior written permission.
65*7f2fe78bSCy Schubert  *
66*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
67*7f2fe78bSCy Schubert  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
68*7f2fe78bSCy Schubert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
69*7f2fe78bSCy Schubert  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
70*7f2fe78bSCy Schubert  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
71*7f2fe78bSCy Schubert  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
72*7f2fe78bSCy Schubert  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
73*7f2fe78bSCy Schubert  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
74*7f2fe78bSCy Schubert  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
75*7f2fe78bSCy Schubert  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
76*7f2fe78bSCy Schubert  * POSSIBILITY OF SUCH DAMAGE.
77*7f2fe78bSCy Schubert  */
78*7f2fe78bSCy Schubert 
79*7f2fe78bSCy Schubert #include "k5-int.h"
80*7f2fe78bSCy Schubert #include "kdc_util.h"
81*7f2fe78bSCy Schubert #include "extern.h"
82*7f2fe78bSCy Schubert #include <stdio.h>
83*7f2fe78bSCy Schubert #include "adm_proto.h"
84*7f2fe78bSCy Schubert 
85*7f2fe78bSCy Schubert #include <syslog.h>
86*7f2fe78bSCy Schubert 
87*7f2fe78bSCy Schubert #include <assert.h>
88*7f2fe78bSCy Schubert #include <krb5/kdcpreauth_plugin.h>
89*7f2fe78bSCy Schubert 
90*7f2fe78bSCy Schubert /* Let freshness tokens be valid for ten minutes. */
91*7f2fe78bSCy Schubert #define FRESHNESS_LIFETIME 600
92*7f2fe78bSCy Schubert 
93*7f2fe78bSCy Schubert typedef struct preauth_system_st {
94*7f2fe78bSCy Schubert     const char *name;
95*7f2fe78bSCy Schubert     int type;
96*7f2fe78bSCy Schubert     int flags;
97*7f2fe78bSCy Schubert     krb5_kdcpreauth_moddata moddata;
98*7f2fe78bSCy Schubert     krb5_kdcpreauth_init_fn init;
99*7f2fe78bSCy Schubert     krb5_kdcpreauth_fini_fn fini;
100*7f2fe78bSCy Schubert     krb5_kdcpreauth_edata_fn get_edata;
101*7f2fe78bSCy Schubert     krb5_kdcpreauth_verify_fn verify_padata;
102*7f2fe78bSCy Schubert     krb5_kdcpreauth_return_fn return_padata;
103*7f2fe78bSCy Schubert     krb5_kdcpreauth_free_modreq_fn free_modreq;
104*7f2fe78bSCy Schubert     krb5_kdcpreauth_loop_fn loop;
105*7f2fe78bSCy Schubert } preauth_system;
106*7f2fe78bSCy Schubert 
107*7f2fe78bSCy Schubert static preauth_system *preauth_systems;
108*7f2fe78bSCy Schubert static size_t n_preauth_systems;
109*7f2fe78bSCy Schubert 
110*7f2fe78bSCy Schubert static krb5_error_code
111*7f2fe78bSCy Schubert make_etype_info(krb5_context context, krb5_boolean etype_info2,
112*7f2fe78bSCy Schubert                 krb5_principal client, krb5_key_data *client_key,
113*7f2fe78bSCy Schubert                 krb5_enctype enctype, krb5_data **der_out);
114*7f2fe78bSCy Schubert 
115*7f2fe78bSCy Schubert /* Get all available kdcpreauth vtables and a count of preauth types they
116*7f2fe78bSCy Schubert  * support.  Return an empty list on failure. */
117*7f2fe78bSCy Schubert static void
get_plugin_vtables(krb5_context context,struct krb5_kdcpreauth_vtable_st ** vtables_out,size_t * n_tables_out,size_t * n_systems_out)118*7f2fe78bSCy Schubert get_plugin_vtables(krb5_context context,
119*7f2fe78bSCy Schubert                    struct krb5_kdcpreauth_vtable_st **vtables_out,
120*7f2fe78bSCy Schubert                    size_t *n_tables_out, size_t *n_systems_out)
121*7f2fe78bSCy Schubert {
122*7f2fe78bSCy Schubert     krb5_plugin_initvt_fn *plugins = NULL, *pl;
123*7f2fe78bSCy Schubert     struct krb5_kdcpreauth_vtable_st *vtables;
124*7f2fe78bSCy Schubert     size_t count, n_tables, n_systems, i;
125*7f2fe78bSCy Schubert 
126*7f2fe78bSCy Schubert     *vtables_out = NULL;
127*7f2fe78bSCy Schubert     *n_tables_out = *n_systems_out = 0;
128*7f2fe78bSCy Schubert 
129*7f2fe78bSCy Schubert     /* Auto-register encrypted challenge and (if possible) pkinit. */
130*7f2fe78bSCy Schubert     k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "pkinit",
131*7f2fe78bSCy Schubert                            "preauth");
132*7f2fe78bSCy Schubert     k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "otp",
133*7f2fe78bSCy Schubert                            "preauth");
134*7f2fe78bSCy Schubert     k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "spake",
135*7f2fe78bSCy Schubert                            "preauth");
136*7f2fe78bSCy Schubert     k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH,
137*7f2fe78bSCy Schubert                        "encrypted_challenge",
138*7f2fe78bSCy Schubert                        kdcpreauth_encrypted_challenge_initvt);
139*7f2fe78bSCy Schubert     k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH,
140*7f2fe78bSCy Schubert                        "encrypted_timestamp",
141*7f2fe78bSCy Schubert                        kdcpreauth_encrypted_timestamp_initvt);
142*7f2fe78bSCy Schubert 
143*7f2fe78bSCy Schubert     if (k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPREAUTH, &plugins))
144*7f2fe78bSCy Schubert         return;
145*7f2fe78bSCy Schubert     for (count = 0; plugins[count]; count++);
146*7f2fe78bSCy Schubert     vtables = calloc(count + 1, sizeof(*vtables));
147*7f2fe78bSCy Schubert     if (vtables == NULL)
148*7f2fe78bSCy Schubert         goto cleanup;
149*7f2fe78bSCy Schubert     for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
150*7f2fe78bSCy Schubert         if ((*pl)(context, 1, 2, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
151*7f2fe78bSCy Schubert             n_tables++;
152*7f2fe78bSCy Schubert     }
153*7f2fe78bSCy Schubert     for (i = 0, n_systems = 0; i < n_tables; i++) {
154*7f2fe78bSCy Schubert         for (count = 0; vtables[i].pa_type_list[count] != 0; count++);
155*7f2fe78bSCy Schubert         n_systems += count;
156*7f2fe78bSCy Schubert     }
157*7f2fe78bSCy Schubert     *vtables_out = vtables;
158*7f2fe78bSCy Schubert     *n_tables_out = n_tables;
159*7f2fe78bSCy Schubert     *n_systems_out = n_systems;
160*7f2fe78bSCy Schubert 
161*7f2fe78bSCy Schubert cleanup:
162*7f2fe78bSCy Schubert     k5_plugin_free_modules(context, plugins);
163*7f2fe78bSCy Schubert }
164*7f2fe78bSCy Schubert 
165*7f2fe78bSCy Schubert /* Make a list of realm names.  The caller should free the list container but
166*7f2fe78bSCy Schubert  * not the list elements (which are aliases into kdc_realmlist). */
167*7f2fe78bSCy Schubert static krb5_error_code
get_realm_names(struct server_handle * handle,const char *** list_out)168*7f2fe78bSCy Schubert get_realm_names(struct server_handle *handle, const char ***list_out)
169*7f2fe78bSCy Schubert {
170*7f2fe78bSCy Schubert     const char **list;
171*7f2fe78bSCy Schubert     int i;
172*7f2fe78bSCy Schubert 
173*7f2fe78bSCy Schubert     list = calloc(handle->kdc_numrealms + 1, sizeof(*list));
174*7f2fe78bSCy Schubert     if (list == NULL)
175*7f2fe78bSCy Schubert         return ENOMEM;
176*7f2fe78bSCy Schubert     for (i = 0; i < handle->kdc_numrealms; i++)
177*7f2fe78bSCy Schubert         list[i] = handle->kdc_realmlist[i]->realm_name;
178*7f2fe78bSCy Schubert     list[i] = NULL;
179*7f2fe78bSCy Schubert     *list_out = list;
180*7f2fe78bSCy Schubert     return 0;
181*7f2fe78bSCy Schubert }
182*7f2fe78bSCy Schubert 
183*7f2fe78bSCy Schubert void
load_preauth_plugins(struct server_handle * handle,krb5_context context,verto_ctx * ctx)184*7f2fe78bSCy Schubert load_preauth_plugins(struct server_handle *handle, krb5_context context,
185*7f2fe78bSCy Schubert                      verto_ctx *ctx)
186*7f2fe78bSCy Schubert {
187*7f2fe78bSCy Schubert     krb5_error_code ret;
188*7f2fe78bSCy Schubert     struct krb5_kdcpreauth_vtable_st *vtables = NULL, *vt;
189*7f2fe78bSCy Schubert     size_t n_systems, n_tables, i, j;
190*7f2fe78bSCy Schubert     krb5_kdcpreauth_moddata moddata;
191*7f2fe78bSCy Schubert     const char **realm_names = NULL, *emsg;
192*7f2fe78bSCy Schubert     preauth_system *sys;
193*7f2fe78bSCy Schubert 
194*7f2fe78bSCy Schubert     /* Get all available kdcpreauth vtables. */
195*7f2fe78bSCy Schubert     get_plugin_vtables(context, &vtables, &n_tables, &n_systems);
196*7f2fe78bSCy Schubert 
197*7f2fe78bSCy Schubert     /* Allocate the list of static and plugin preauth systems. */
198*7f2fe78bSCy Schubert     preauth_systems = calloc(n_systems + 1, sizeof(preauth_system));
199*7f2fe78bSCy Schubert     if (preauth_systems == NULL)
200*7f2fe78bSCy Schubert         goto cleanup;
201*7f2fe78bSCy Schubert 
202*7f2fe78bSCy Schubert     if (get_realm_names(handle, &realm_names))
203*7f2fe78bSCy Schubert         goto cleanup;
204*7f2fe78bSCy Schubert 
205*7f2fe78bSCy Schubert     /* Add the dynamically-loaded mechanisms to the list. */
206*7f2fe78bSCy Schubert     n_systems = 0;
207*7f2fe78bSCy Schubert     for (i = 0; i < n_tables; i++) {
208*7f2fe78bSCy Schubert         /* Try to initialize this module. */
209*7f2fe78bSCy Schubert         vt = &vtables[i];
210*7f2fe78bSCy Schubert         moddata = NULL;
211*7f2fe78bSCy Schubert         if (vt->init) {
212*7f2fe78bSCy Schubert             ret = vt->init(context, &moddata, realm_names);
213*7f2fe78bSCy Schubert             if (ret) {
214*7f2fe78bSCy Schubert                 emsg = krb5_get_error_message(context, ret);
215*7f2fe78bSCy Schubert                 krb5_klog_syslog(LOG_ERR, _("preauth %s failed to "
216*7f2fe78bSCy Schubert                                             "initialize: %s"), vt->name, emsg);
217*7f2fe78bSCy Schubert                 krb5_free_error_message(context, emsg);
218*7f2fe78bSCy Schubert                 continue;
219*7f2fe78bSCy Schubert             }
220*7f2fe78bSCy Schubert         }
221*7f2fe78bSCy Schubert 
222*7f2fe78bSCy Schubert         if (vt->loop) {
223*7f2fe78bSCy Schubert             ret = vt->loop(context, moddata, ctx);
224*7f2fe78bSCy Schubert             if (ret) {
225*7f2fe78bSCy Schubert                 emsg = krb5_get_error_message(context, ret);
226*7f2fe78bSCy Schubert                 krb5_klog_syslog(LOG_ERR, _("preauth %s failed to setup "
227*7f2fe78bSCy Schubert                                             "loop: %s"), vt->name, emsg);
228*7f2fe78bSCy Schubert                 krb5_free_error_message(context, emsg);
229*7f2fe78bSCy Schubert                 if (vt->fini)
230*7f2fe78bSCy Schubert                     vt->fini(context, moddata);
231*7f2fe78bSCy Schubert                 continue;
232*7f2fe78bSCy Schubert             }
233*7f2fe78bSCy Schubert         }
234*7f2fe78bSCy Schubert 
235*7f2fe78bSCy Schubert         /* Add this module to the systems list once for each pa type. */
236*7f2fe78bSCy Schubert         for (j = 0; vt->pa_type_list[j] != 0; j++) {
237*7f2fe78bSCy Schubert             sys = &preauth_systems[n_systems];
238*7f2fe78bSCy Schubert             sys->name = vt->name;
239*7f2fe78bSCy Schubert             sys->type = vt->pa_type_list[j];
240*7f2fe78bSCy Schubert             sys->flags = (vt->flags) ? vt->flags(context, sys->type) : 0;
241*7f2fe78bSCy Schubert             sys->moddata = moddata;
242*7f2fe78bSCy Schubert             sys->init = vt->init;
243*7f2fe78bSCy Schubert             /* Only call fini once for each plugin. */
244*7f2fe78bSCy Schubert             sys->fini = (j == 0) ? vt->fini : NULL;
245*7f2fe78bSCy Schubert             sys->get_edata = vt->edata;
246*7f2fe78bSCy Schubert             sys->verify_padata = vt->verify;
247*7f2fe78bSCy Schubert             sys->return_padata = vt->return_padata;
248*7f2fe78bSCy Schubert             sys->free_modreq = vt->free_modreq;
249*7f2fe78bSCy Schubert             sys->loop = vt->loop;
250*7f2fe78bSCy Schubert             n_systems++;
251*7f2fe78bSCy Schubert         }
252*7f2fe78bSCy Schubert     }
253*7f2fe78bSCy Schubert     n_preauth_systems = n_systems;
254*7f2fe78bSCy Schubert     /* Add the end-of-list marker. */
255*7f2fe78bSCy Schubert     preauth_systems[n_systems].name = "[end]";
256*7f2fe78bSCy Schubert     preauth_systems[n_systems].type = -1;
257*7f2fe78bSCy Schubert 
258*7f2fe78bSCy Schubert cleanup:
259*7f2fe78bSCy Schubert     free(vtables);
260*7f2fe78bSCy Schubert     free(realm_names);
261*7f2fe78bSCy Schubert }
262*7f2fe78bSCy Schubert 
263*7f2fe78bSCy Schubert void
unload_preauth_plugins(krb5_context context)264*7f2fe78bSCy Schubert unload_preauth_plugins(krb5_context context)
265*7f2fe78bSCy Schubert {
266*7f2fe78bSCy Schubert     size_t i;
267*7f2fe78bSCy Schubert 
268*7f2fe78bSCy Schubert     for (i = 0; i < n_preauth_systems; i++) {
269*7f2fe78bSCy Schubert         if (preauth_systems[i].fini)
270*7f2fe78bSCy Schubert             preauth_systems[i].fini(context, preauth_systems[i].moddata);
271*7f2fe78bSCy Schubert     }
272*7f2fe78bSCy Schubert     free(preauth_systems);
273*7f2fe78bSCy Schubert     preauth_systems = NULL;
274*7f2fe78bSCy Schubert     n_preauth_systems = 0;
275*7f2fe78bSCy Schubert }
276*7f2fe78bSCy Schubert 
277*7f2fe78bSCy Schubert /*
278*7f2fe78bSCy Schubert  * The make_padata_context() function creates a space for storing any
279*7f2fe78bSCy Schubert  * request-specific module data which will be needed by return_padata() later.
280*7f2fe78bSCy Schubert  * Each preauth type gets a storage location of its own.
281*7f2fe78bSCy Schubert  */
282*7f2fe78bSCy Schubert struct request_pa_context {
283*7f2fe78bSCy Schubert     int n_contexts;
284*7f2fe78bSCy Schubert     struct {
285*7f2fe78bSCy Schubert         preauth_system *pa_system;
286*7f2fe78bSCy Schubert         krb5_kdcpreauth_modreq modreq;
287*7f2fe78bSCy Schubert     } *contexts;
288*7f2fe78bSCy Schubert };
289*7f2fe78bSCy Schubert 
290*7f2fe78bSCy Schubert static krb5_error_code
make_padata_context(krb5_context context,void ** padata_context)291*7f2fe78bSCy Schubert make_padata_context(krb5_context context, void **padata_context)
292*7f2fe78bSCy Schubert {
293*7f2fe78bSCy Schubert     int i;
294*7f2fe78bSCy Schubert     struct request_pa_context *ret;
295*7f2fe78bSCy Schubert 
296*7f2fe78bSCy Schubert     ret = malloc(sizeof(*ret));
297*7f2fe78bSCy Schubert     if (ret == NULL) {
298*7f2fe78bSCy Schubert         return ENOMEM;
299*7f2fe78bSCy Schubert     }
300*7f2fe78bSCy Schubert 
301*7f2fe78bSCy Schubert     ret->n_contexts = n_preauth_systems;
302*7f2fe78bSCy Schubert     ret->contexts = malloc(sizeof(ret->contexts[0]) * ret->n_contexts);
303*7f2fe78bSCy Schubert     if (ret->contexts == NULL) {
304*7f2fe78bSCy Schubert         free(ret);
305*7f2fe78bSCy Schubert         return ENOMEM;
306*7f2fe78bSCy Schubert     }
307*7f2fe78bSCy Schubert 
308*7f2fe78bSCy Schubert     memset(ret->contexts, 0, sizeof(ret->contexts[0]) * ret->n_contexts);
309*7f2fe78bSCy Schubert 
310*7f2fe78bSCy Schubert     for (i = 0; i < ret->n_contexts; i++) {
311*7f2fe78bSCy Schubert         ret->contexts[i].pa_system = &preauth_systems[i];
312*7f2fe78bSCy Schubert         ret->contexts[i].modreq = NULL;
313*7f2fe78bSCy Schubert     }
314*7f2fe78bSCy Schubert 
315*7f2fe78bSCy Schubert     *padata_context = ret;
316*7f2fe78bSCy Schubert 
317*7f2fe78bSCy Schubert     return 0;
318*7f2fe78bSCy Schubert }
319*7f2fe78bSCy Schubert 
320*7f2fe78bSCy Schubert /*
321*7f2fe78bSCy Schubert  * The free_padata_context function frees any context information pointers
322*7f2fe78bSCy Schubert  * which the check_padata() function created but which weren't already cleaned
323*7f2fe78bSCy Schubert  * up by return_padata().
324*7f2fe78bSCy Schubert  */
325*7f2fe78bSCy Schubert void
free_padata_context(krb5_context kcontext,void * padata_context)326*7f2fe78bSCy Schubert free_padata_context(krb5_context kcontext, void *padata_context)
327*7f2fe78bSCy Schubert {
328*7f2fe78bSCy Schubert     struct request_pa_context *context = padata_context;
329*7f2fe78bSCy Schubert     preauth_system *sys;
330*7f2fe78bSCy Schubert     int i;
331*7f2fe78bSCy Schubert 
332*7f2fe78bSCy Schubert     if (context == NULL)
333*7f2fe78bSCy Schubert         return;
334*7f2fe78bSCy Schubert     for (i = 0; i < context->n_contexts; i++) {
335*7f2fe78bSCy Schubert         sys = context->contexts[i].pa_system;
336*7f2fe78bSCy Schubert         if (!sys->free_modreq || !context->contexts[i].modreq)
337*7f2fe78bSCy Schubert             continue;
338*7f2fe78bSCy Schubert         sys->free_modreq(kcontext, sys->moddata, context->contexts[i].modreq);
339*7f2fe78bSCy Schubert         context->contexts[i].modreq = NULL;
340*7f2fe78bSCy Schubert     }
341*7f2fe78bSCy Schubert 
342*7f2fe78bSCy Schubert     free(context->contexts);
343*7f2fe78bSCy Schubert     free(context);
344*7f2fe78bSCy Schubert }
345*7f2fe78bSCy Schubert 
346*7f2fe78bSCy Schubert static krb5_deltat
max_time_skew(krb5_context context,krb5_kdcpreauth_rock rock)347*7f2fe78bSCy Schubert max_time_skew(krb5_context context, krb5_kdcpreauth_rock rock)
348*7f2fe78bSCy Schubert {
349*7f2fe78bSCy Schubert     return context->clockskew;
350*7f2fe78bSCy Schubert }
351*7f2fe78bSCy Schubert 
352*7f2fe78bSCy Schubert static krb5_error_code
client_keys(krb5_context context,krb5_kdcpreauth_rock rock,krb5_keyblock ** keys_out)353*7f2fe78bSCy Schubert client_keys(krb5_context context, krb5_kdcpreauth_rock rock,
354*7f2fe78bSCy Schubert             krb5_keyblock **keys_out)
355*7f2fe78bSCy Schubert {
356*7f2fe78bSCy Schubert     krb5_kdc_req *request = rock->request;
357*7f2fe78bSCy Schubert     krb5_db_entry *client = rock->client;
358*7f2fe78bSCy Schubert     krb5_keyblock *keys, key;
359*7f2fe78bSCy Schubert     krb5_key_data *entry_key;
360*7f2fe78bSCy Schubert     int i, k;
361*7f2fe78bSCy Schubert 
362*7f2fe78bSCy Schubert     keys = calloc(request->nktypes + 1, sizeof(krb5_keyblock));
363*7f2fe78bSCy Schubert     if (keys == NULL)
364*7f2fe78bSCy Schubert         return ENOMEM;
365*7f2fe78bSCy Schubert 
366*7f2fe78bSCy Schubert     k = 0;
367*7f2fe78bSCy Schubert     for (i = 0; i < request->nktypes; i++) {
368*7f2fe78bSCy Schubert         entry_key = NULL;
369*7f2fe78bSCy Schubert         if (krb5_dbe_find_enctype(context, client, request->ktype[i],
370*7f2fe78bSCy Schubert                                   -1, 0, &entry_key) != 0)
371*7f2fe78bSCy Schubert             continue;
372*7f2fe78bSCy Schubert         if (krb5_dbe_decrypt_key_data(context, NULL, entry_key,
373*7f2fe78bSCy Schubert                                       &key, NULL) != 0)
374*7f2fe78bSCy Schubert             continue;
375*7f2fe78bSCy Schubert         keys[k++] = key;
376*7f2fe78bSCy Schubert     }
377*7f2fe78bSCy Schubert     if (k == 0) {
378*7f2fe78bSCy Schubert         free(keys);
379*7f2fe78bSCy Schubert         return ENOENT;
380*7f2fe78bSCy Schubert     }
381*7f2fe78bSCy Schubert     *keys_out = keys;
382*7f2fe78bSCy Schubert     return 0;
383*7f2fe78bSCy Schubert }
384*7f2fe78bSCy Schubert 
free_keys(krb5_context context,krb5_kdcpreauth_rock rock,krb5_keyblock * keys)385*7f2fe78bSCy Schubert static void free_keys(krb5_context context, krb5_kdcpreauth_rock rock,
386*7f2fe78bSCy Schubert                       krb5_keyblock *keys)
387*7f2fe78bSCy Schubert {
388*7f2fe78bSCy Schubert     krb5_keyblock *k;
389*7f2fe78bSCy Schubert 
390*7f2fe78bSCy Schubert     if (keys == NULL)
391*7f2fe78bSCy Schubert         return;
392*7f2fe78bSCy Schubert     for (k = keys; k->enctype != 0; k++)
393*7f2fe78bSCy Schubert         krb5_free_keyblock_contents(context, k);
394*7f2fe78bSCy Schubert     free(keys);
395*7f2fe78bSCy Schubert }
396*7f2fe78bSCy Schubert 
397*7f2fe78bSCy Schubert static krb5_data *
request_body(krb5_context context,krb5_kdcpreauth_rock rock)398*7f2fe78bSCy Schubert request_body(krb5_context context, krb5_kdcpreauth_rock rock)
399*7f2fe78bSCy Schubert {
400*7f2fe78bSCy Schubert     return rock->inner_body;
401*7f2fe78bSCy Schubert }
402*7f2fe78bSCy Schubert 
403*7f2fe78bSCy Schubert static krb5_keyblock *
fast_armor(krb5_context context,krb5_kdcpreauth_rock rock)404*7f2fe78bSCy Schubert fast_armor(krb5_context context, krb5_kdcpreauth_rock rock)
405*7f2fe78bSCy Schubert {
406*7f2fe78bSCy Schubert     return rock->rstate->armor_key;
407*7f2fe78bSCy Schubert }
408*7f2fe78bSCy Schubert 
409*7f2fe78bSCy Schubert static krb5_error_code
get_string(krb5_context context,krb5_kdcpreauth_rock rock,const char * key,char ** value_out)410*7f2fe78bSCy Schubert get_string(krb5_context context, krb5_kdcpreauth_rock rock, const char *key,
411*7f2fe78bSCy Schubert            char **value_out)
412*7f2fe78bSCy Schubert {
413*7f2fe78bSCy Schubert     return krb5_dbe_get_string(context, rock->client, key, value_out);
414*7f2fe78bSCy Schubert }
415*7f2fe78bSCy Schubert 
416*7f2fe78bSCy Schubert static void
free_string(krb5_context context,krb5_kdcpreauth_rock rock,char * string)417*7f2fe78bSCy Schubert free_string(krb5_context context, krb5_kdcpreauth_rock rock, char *string)
418*7f2fe78bSCy Schubert {
419*7f2fe78bSCy Schubert     krb5_dbe_free_string(context, string);
420*7f2fe78bSCy Schubert }
421*7f2fe78bSCy Schubert 
422*7f2fe78bSCy Schubert static void *
client_entry(krb5_context context,krb5_kdcpreauth_rock rock)423*7f2fe78bSCy Schubert client_entry(krb5_context context, krb5_kdcpreauth_rock rock)
424*7f2fe78bSCy Schubert {
425*7f2fe78bSCy Schubert     return rock->client;
426*7f2fe78bSCy Schubert }
427*7f2fe78bSCy Schubert 
428*7f2fe78bSCy Schubert static verto_ctx *
event_context(krb5_context context,krb5_kdcpreauth_rock rock)429*7f2fe78bSCy Schubert event_context(krb5_context context, krb5_kdcpreauth_rock rock)
430*7f2fe78bSCy Schubert {
431*7f2fe78bSCy Schubert     return rock->vctx;
432*7f2fe78bSCy Schubert }
433*7f2fe78bSCy Schubert 
434*7f2fe78bSCy Schubert static krb5_boolean
have_client_keys(krb5_context context,krb5_kdcpreauth_rock rock)435*7f2fe78bSCy Schubert have_client_keys(krb5_context context, krb5_kdcpreauth_rock rock)
436*7f2fe78bSCy Schubert {
437*7f2fe78bSCy Schubert     krb5_kdc_req *request = rock->request;
438*7f2fe78bSCy Schubert     krb5_key_data *kd;
439*7f2fe78bSCy Schubert     int i;
440*7f2fe78bSCy Schubert 
441*7f2fe78bSCy Schubert     for (i = 0; i < request->nktypes; i++) {
442*7f2fe78bSCy Schubert         if (krb5_dbe_find_enctype(context, rock->client, request->ktype[i],
443*7f2fe78bSCy Schubert                                   -1, 0, &kd) == 0)
444*7f2fe78bSCy Schubert             return TRUE;
445*7f2fe78bSCy Schubert     }
446*7f2fe78bSCy Schubert     return FALSE;
447*7f2fe78bSCy Schubert }
448*7f2fe78bSCy Schubert 
449*7f2fe78bSCy Schubert static const krb5_keyblock *
client_keyblock(krb5_context context,krb5_kdcpreauth_rock rock)450*7f2fe78bSCy Schubert client_keyblock(krb5_context context, krb5_kdcpreauth_rock rock)
451*7f2fe78bSCy Schubert {
452*7f2fe78bSCy Schubert     if (rock->client_keyblock->enctype == ENCTYPE_NULL)
453*7f2fe78bSCy Schubert         return NULL;
454*7f2fe78bSCy Schubert     return rock->client_keyblock;
455*7f2fe78bSCy Schubert }
456*7f2fe78bSCy Schubert 
457*7f2fe78bSCy Schubert static krb5_error_code
add_auth_indicator(krb5_context context,krb5_kdcpreauth_rock rock,const char * indicator)458*7f2fe78bSCy Schubert add_auth_indicator(krb5_context context, krb5_kdcpreauth_rock rock,
459*7f2fe78bSCy Schubert                    const char *indicator)
460*7f2fe78bSCy Schubert {
461*7f2fe78bSCy Schubert     return authind_add(context, indicator, rock->auth_indicators);
462*7f2fe78bSCy Schubert }
463*7f2fe78bSCy Schubert 
464*7f2fe78bSCy Schubert static krb5_boolean
get_cookie(krb5_context context,krb5_kdcpreauth_rock rock,krb5_preauthtype pa_type,krb5_data * out)465*7f2fe78bSCy Schubert get_cookie(krb5_context context, krb5_kdcpreauth_rock rock,
466*7f2fe78bSCy Schubert            krb5_preauthtype pa_type, krb5_data *out)
467*7f2fe78bSCy Schubert {
468*7f2fe78bSCy Schubert     return kdc_fast_search_cookie(rock->rstate, pa_type, out);
469*7f2fe78bSCy Schubert }
470*7f2fe78bSCy Schubert 
471*7f2fe78bSCy Schubert static krb5_error_code
set_cookie(krb5_context context,krb5_kdcpreauth_rock rock,krb5_preauthtype pa_type,const krb5_data * data)472*7f2fe78bSCy Schubert set_cookie(krb5_context context, krb5_kdcpreauth_rock rock,
473*7f2fe78bSCy Schubert            krb5_preauthtype pa_type, const krb5_data *data)
474*7f2fe78bSCy Schubert {
475*7f2fe78bSCy Schubert     return kdc_fast_set_cookie(rock->rstate, pa_type, data);
476*7f2fe78bSCy Schubert }
477*7f2fe78bSCy Schubert 
478*7f2fe78bSCy Schubert static krb5_boolean
match_client(krb5_context context,krb5_kdcpreauth_rock rock,krb5_principal princ)479*7f2fe78bSCy Schubert match_client(krb5_context context, krb5_kdcpreauth_rock rock,
480*7f2fe78bSCy Schubert              krb5_principal princ)
481*7f2fe78bSCy Schubert {
482*7f2fe78bSCy Schubert     krb5_db_entry *ent;
483*7f2fe78bSCy Schubert     krb5_boolean match = FALSE;
484*7f2fe78bSCy Schubert     krb5_principal req_client = rock->request->client;
485*7f2fe78bSCy Schubert     krb5_principal client = rock->client->princ;
486*7f2fe78bSCy Schubert 
487*7f2fe78bSCy Schubert     /* Check for a direct match against the request principal or
488*7f2fe78bSCy Schubert      * the post-canon client principal. */
489*7f2fe78bSCy Schubert     if (krb5_principal_compare_flags(context, princ, req_client,
490*7f2fe78bSCy Schubert                                      KRB5_PRINCIPAL_COMPARE_ENTERPRISE) ||
491*7f2fe78bSCy Schubert         krb5_principal_compare(context, princ, client))
492*7f2fe78bSCy Schubert         return TRUE;
493*7f2fe78bSCy Schubert 
494*7f2fe78bSCy Schubert     if (krb5_db_get_principal(context, princ, KRB5_KDB_FLAG_CLIENT, &ent))
495*7f2fe78bSCy Schubert         return FALSE;
496*7f2fe78bSCy Schubert     match = krb5_principal_compare(context, ent->princ, client);
497*7f2fe78bSCy Schubert     krb5_db_free_principal(context, ent);
498*7f2fe78bSCy Schubert     return match;
499*7f2fe78bSCy Schubert }
500*7f2fe78bSCy Schubert 
501*7f2fe78bSCy Schubert static krb5_principal
client_name(krb5_context context,krb5_kdcpreauth_rock rock)502*7f2fe78bSCy Schubert client_name(krb5_context context, krb5_kdcpreauth_rock rock)
503*7f2fe78bSCy Schubert {
504*7f2fe78bSCy Schubert     return rock->client->princ;
505*7f2fe78bSCy Schubert }
506*7f2fe78bSCy Schubert 
507*7f2fe78bSCy Schubert static void
send_freshness_token(krb5_context context,krb5_kdcpreauth_rock rock)508*7f2fe78bSCy Schubert send_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock)
509*7f2fe78bSCy Schubert {
510*7f2fe78bSCy Schubert     rock->send_freshness_token = TRUE;
511*7f2fe78bSCy Schubert }
512*7f2fe78bSCy Schubert 
513*7f2fe78bSCy Schubert static krb5_error_code
check_freshness_token(krb5_context context,krb5_kdcpreauth_rock rock,const krb5_data * token)514*7f2fe78bSCy Schubert check_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock,
515*7f2fe78bSCy Schubert                       const krb5_data *token)
516*7f2fe78bSCy Schubert {
517*7f2fe78bSCy Schubert     krb5_timestamp token_ts, now;
518*7f2fe78bSCy Schubert     krb5_key_data *kd;
519*7f2fe78bSCy Schubert     krb5_keyblock kb;
520*7f2fe78bSCy Schubert     krb5_kvno token_kvno;
521*7f2fe78bSCy Schubert     krb5_checksum cksum;
522*7f2fe78bSCy Schubert     krb5_data d;
523*7f2fe78bSCy Schubert     uint8_t *token_cksum;
524*7f2fe78bSCy Schubert     size_t token_cksum_len;
525*7f2fe78bSCy Schubert     krb5_boolean valid = FALSE;
526*7f2fe78bSCy Schubert     char ckbuf[4];
527*7f2fe78bSCy Schubert 
528*7f2fe78bSCy Schubert     memset(&kb, 0, sizeof(kb));
529*7f2fe78bSCy Schubert 
530*7f2fe78bSCy Schubert     if (krb5_timeofday(context, &now) != 0)
531*7f2fe78bSCy Schubert         goto cleanup;
532*7f2fe78bSCy Schubert 
533*7f2fe78bSCy Schubert     if (token->length <= 8)
534*7f2fe78bSCy Schubert         goto cleanup;
535*7f2fe78bSCy Schubert     token_ts = load_32_be(token->data);
536*7f2fe78bSCy Schubert     token_kvno = load_32_be(token->data + 4);
537*7f2fe78bSCy Schubert     token_cksum = (uint8_t *)token->data + 8;
538*7f2fe78bSCy Schubert     token_cksum_len = token->length - 8;
539*7f2fe78bSCy Schubert 
540*7f2fe78bSCy Schubert     /* Check if the token timestamp is too old. */
541*7f2fe78bSCy Schubert     if (ts_after(now, ts_incr(token_ts, FRESHNESS_LIFETIME)))
542*7f2fe78bSCy Schubert         goto cleanup;
543*7f2fe78bSCy Schubert 
544*7f2fe78bSCy Schubert     /* Fetch and decrypt the local krbtgt key of the token's kvno. */
545*7f2fe78bSCy Schubert     if (krb5_dbe_find_enctype(context, rock->local_tgt, -1, -1, token_kvno,
546*7f2fe78bSCy Schubert                               &kd) != 0)
547*7f2fe78bSCy Schubert         goto cleanup;
548*7f2fe78bSCy Schubert     if (krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL) != 0)
549*7f2fe78bSCy Schubert         goto cleanup;
550*7f2fe78bSCy Schubert 
551*7f2fe78bSCy Schubert     /* Verify the token checksum against the current KDC time.  The checksum
552*7f2fe78bSCy Schubert      * must use the mandatory checksum type of the krbtgt key's enctype. */
553*7f2fe78bSCy Schubert     store_32_be(token_ts, ckbuf);
554*7f2fe78bSCy Schubert     d = make_data(ckbuf, sizeof(ckbuf));
555*7f2fe78bSCy Schubert     cksum.magic = KV5M_CHECKSUM;
556*7f2fe78bSCy Schubert     cksum.checksum_type = 0;
557*7f2fe78bSCy Schubert     cksum.length = token_cksum_len;
558*7f2fe78bSCy Schubert     cksum.contents = token_cksum;
559*7f2fe78bSCy Schubert     (void)krb5_c_verify_checksum(context, &kb, KRB5_KEYUSAGE_PA_AS_FRESHNESS,
560*7f2fe78bSCy Schubert                                  &d, &cksum, &valid);
561*7f2fe78bSCy Schubert 
562*7f2fe78bSCy Schubert cleanup:
563*7f2fe78bSCy Schubert     krb5_free_keyblock_contents(context, &kb);
564*7f2fe78bSCy Schubert     return valid ? 0 : KRB5KDC_ERR_PREAUTH_EXPIRED;
565*7f2fe78bSCy Schubert }
566*7f2fe78bSCy Schubert 
567*7f2fe78bSCy Schubert static krb5_error_code
replace_reply_key(krb5_context context,krb5_kdcpreauth_rock rock,const krb5_keyblock * key,krb5_boolean is_strengthen)568*7f2fe78bSCy Schubert replace_reply_key(krb5_context context, krb5_kdcpreauth_rock rock,
569*7f2fe78bSCy Schubert                   const krb5_keyblock *key, krb5_boolean is_strengthen)
570*7f2fe78bSCy Schubert {
571*7f2fe78bSCy Schubert     krb5_keyblock copy;
572*7f2fe78bSCy Schubert 
573*7f2fe78bSCy Schubert     if (krb5_copy_keyblock_contents(context, key, &copy) != 0)
574*7f2fe78bSCy Schubert         return ENOMEM;
575*7f2fe78bSCy Schubert     krb5_free_keyblock_contents(context, rock->client_keyblock);
576*7f2fe78bSCy Schubert     *rock->client_keyblock = copy;
577*7f2fe78bSCy Schubert     if (!is_strengthen)
578*7f2fe78bSCy Schubert         rock->replaced_reply_key = TRUE;
579*7f2fe78bSCy Schubert     return 0;
580*7f2fe78bSCy Schubert }
581*7f2fe78bSCy Schubert 
582*7f2fe78bSCy Schubert static struct krb5_kdcpreauth_callbacks_st callbacks = {
583*7f2fe78bSCy Schubert     6,
584*7f2fe78bSCy Schubert     max_time_skew,
585*7f2fe78bSCy Schubert     client_keys,
586*7f2fe78bSCy Schubert     free_keys,
587*7f2fe78bSCy Schubert     request_body,
588*7f2fe78bSCy Schubert     fast_armor,
589*7f2fe78bSCy Schubert     get_string,
590*7f2fe78bSCy Schubert     free_string,
591*7f2fe78bSCy Schubert     client_entry,
592*7f2fe78bSCy Schubert     event_context,
593*7f2fe78bSCy Schubert     have_client_keys,
594*7f2fe78bSCy Schubert     client_keyblock,
595*7f2fe78bSCy Schubert     add_auth_indicator,
596*7f2fe78bSCy Schubert     get_cookie,
597*7f2fe78bSCy Schubert     set_cookie,
598*7f2fe78bSCy Schubert     match_client,
599*7f2fe78bSCy Schubert     client_name,
600*7f2fe78bSCy Schubert     send_freshness_token,
601*7f2fe78bSCy Schubert     check_freshness_token,
602*7f2fe78bSCy Schubert     replace_reply_key
603*7f2fe78bSCy Schubert };
604*7f2fe78bSCy Schubert 
605*7f2fe78bSCy Schubert static krb5_error_code
find_pa_system(int type,preauth_system ** preauth)606*7f2fe78bSCy Schubert find_pa_system(int type, preauth_system **preauth)
607*7f2fe78bSCy Schubert {
608*7f2fe78bSCy Schubert     preauth_system *ap;
609*7f2fe78bSCy Schubert 
610*7f2fe78bSCy Schubert     if (preauth_systems == NULL)
611*7f2fe78bSCy Schubert         return KRB5_PREAUTH_BAD_TYPE;
612*7f2fe78bSCy Schubert     ap = preauth_systems;
613*7f2fe78bSCy Schubert     while ((ap->type != -1) && (ap->type != type))
614*7f2fe78bSCy Schubert         ap++;
615*7f2fe78bSCy Schubert     if (ap->type == -1)
616*7f2fe78bSCy Schubert         return(KRB5_PREAUTH_BAD_TYPE);
617*7f2fe78bSCy Schubert     *preauth = ap;
618*7f2fe78bSCy Schubert     return 0;
619*7f2fe78bSCy Schubert }
620*7f2fe78bSCy Schubert 
621*7f2fe78bSCy Schubert /* Find a pointer to the request-specific module data for pa_sys. */
622*7f2fe78bSCy Schubert static krb5_error_code
find_modreq(preauth_system * pa_sys,struct request_pa_context * context,krb5_kdcpreauth_modreq ** modreq_out)623*7f2fe78bSCy Schubert find_modreq(preauth_system *pa_sys, struct request_pa_context *context,
624*7f2fe78bSCy Schubert             krb5_kdcpreauth_modreq **modreq_out)
625*7f2fe78bSCy Schubert {
626*7f2fe78bSCy Schubert     int i;
627*7f2fe78bSCy Schubert 
628*7f2fe78bSCy Schubert     *modreq_out = NULL;
629*7f2fe78bSCy Schubert     if (context == NULL)
630*7f2fe78bSCy Schubert         return KRB5KRB_ERR_GENERIC;
631*7f2fe78bSCy Schubert 
632*7f2fe78bSCy Schubert     for (i = 0; i < context->n_contexts; i++) {
633*7f2fe78bSCy Schubert         if (context->contexts[i].pa_system == pa_sys) {
634*7f2fe78bSCy Schubert             *modreq_out = &context->contexts[i].modreq;
635*7f2fe78bSCy Schubert             return 0;
636*7f2fe78bSCy Schubert         }
637*7f2fe78bSCy Schubert     }
638*7f2fe78bSCy Schubert 
639*7f2fe78bSCy Schubert     return KRB5KRB_ERR_GENERIC;
640*7f2fe78bSCy Schubert }
641*7f2fe78bSCy Schubert 
642*7f2fe78bSCy Schubert /*
643*7f2fe78bSCy Schubert  * Create a list of indices into the preauth_systems array, sorted by order of
644*7f2fe78bSCy Schubert  * preference.
645*7f2fe78bSCy Schubert  */
646*7f2fe78bSCy Schubert static krb5_boolean
pa_list_includes(krb5_pa_data ** pa_data,krb5_preauthtype pa_type)647*7f2fe78bSCy Schubert pa_list_includes(krb5_pa_data **pa_data, krb5_preauthtype pa_type)
648*7f2fe78bSCy Schubert {
649*7f2fe78bSCy Schubert     while (*pa_data != NULL) {
650*7f2fe78bSCy Schubert         if ((*pa_data)->pa_type == pa_type)
651*7f2fe78bSCy Schubert             return TRUE;
652*7f2fe78bSCy Schubert         pa_data++;
653*7f2fe78bSCy Schubert     }
654*7f2fe78bSCy Schubert     return FALSE;
655*7f2fe78bSCy Schubert }
656*7f2fe78bSCy Schubert static void
sort_pa_order(krb5_context context,krb5_kdc_req * request,int * pa_order)657*7f2fe78bSCy Schubert sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order)
658*7f2fe78bSCy Schubert {
659*7f2fe78bSCy Schubert     size_t i, j, k, n_repliers, n_key_replacers;
660*7f2fe78bSCy Schubert 
661*7f2fe78bSCy Schubert     /* First, set up the default order. */
662*7f2fe78bSCy Schubert     i = 0;
663*7f2fe78bSCy Schubert     for (j = 0; j < n_preauth_systems; j++) {
664*7f2fe78bSCy Schubert         if (preauth_systems[j].return_padata != NULL)
665*7f2fe78bSCy Schubert             pa_order[i++] = j;
666*7f2fe78bSCy Schubert     }
667*7f2fe78bSCy Schubert     n_repliers = i;
668*7f2fe78bSCy Schubert     pa_order[n_repliers] = -1;
669*7f2fe78bSCy Schubert 
670*7f2fe78bSCy Schubert     /* Reorder so that PA_REPLACES_KEY modules are listed first. */
671*7f2fe78bSCy Schubert     for (i = 0; i < n_repliers; i++) {
672*7f2fe78bSCy Schubert         /* If this module replaces the key, then it's okay to leave it where it
673*7f2fe78bSCy Schubert          * is in the order. */
674*7f2fe78bSCy Schubert         if (preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY)
675*7f2fe78bSCy Schubert             continue;
676*7f2fe78bSCy Schubert         /* If not, search for a module which does, and swap in the first one we
677*7f2fe78bSCy Schubert          * find. */
678*7f2fe78bSCy Schubert         for (j = i + 1; j < n_repliers; j++) {
679*7f2fe78bSCy Schubert             if (preauth_systems[pa_order[j]].flags & PA_REPLACES_KEY) {
680*7f2fe78bSCy Schubert                 k = pa_order[j];
681*7f2fe78bSCy Schubert                 pa_order[j] = pa_order[i];
682*7f2fe78bSCy Schubert                 pa_order[i] = k;
683*7f2fe78bSCy Schubert                 break;
684*7f2fe78bSCy Schubert             }
685*7f2fe78bSCy Schubert         }
686*7f2fe78bSCy Schubert         /* If we didn't find one, we have moved all of the key-replacing
687*7f2fe78bSCy Schubert          * modules, and i is the count of those modules. */
688*7f2fe78bSCy Schubert         if (j == n_repliers)
689*7f2fe78bSCy Schubert             break;
690*7f2fe78bSCy Schubert     }
691*7f2fe78bSCy Schubert     n_key_replacers = i;
692*7f2fe78bSCy Schubert 
693*7f2fe78bSCy Schubert     if (request->padata != NULL) {
694*7f2fe78bSCy Schubert         /* Now reorder the subset of modules which replace the key,
695*7f2fe78bSCy Schubert          * bubbling those which handle pa_data types provided by the
696*7f2fe78bSCy Schubert          * client ahead of the others.
697*7f2fe78bSCy Schubert          */
698*7f2fe78bSCy Schubert         for (i = 0; i < n_key_replacers; i++) {
699*7f2fe78bSCy Schubert             if (pa_list_includes(request->padata,
700*7f2fe78bSCy Schubert                                  preauth_systems[pa_order[i]].type))
701*7f2fe78bSCy Schubert                 continue;
702*7f2fe78bSCy Schubert             for (j = i + 1; j < n_key_replacers; j++) {
703*7f2fe78bSCy Schubert                 if (pa_list_includes(request->padata,
704*7f2fe78bSCy Schubert                                      preauth_systems[pa_order[j]].type)) {
705*7f2fe78bSCy Schubert                     k = pa_order[j];
706*7f2fe78bSCy Schubert                     pa_order[j] = pa_order[i];
707*7f2fe78bSCy Schubert                     pa_order[i] = k;
708*7f2fe78bSCy Schubert                     break;
709*7f2fe78bSCy Schubert                 }
710*7f2fe78bSCy Schubert             }
711*7f2fe78bSCy Schubert         }
712*7f2fe78bSCy Schubert     }
713*7f2fe78bSCy Schubert #ifdef DEBUG
714*7f2fe78bSCy Schubert     krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:");
715*7f2fe78bSCy Schubert     for (i = 0; i < n_preauth_systems; i++) {
716*7f2fe78bSCy Schubert         if (preauth_systems[i].return_padata != NULL)
717*7f2fe78bSCy Schubert             krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", preauth_systems[i].name,
718*7f2fe78bSCy Schubert                              preauth_systems[i].type);
719*7f2fe78bSCy Schubert     }
720*7f2fe78bSCy Schubert     krb5_klog_syslog(LOG_DEBUG, "sorted preauth mechanism list:");
721*7f2fe78bSCy Schubert     for (i = 0; pa_order[i] != -1; i++) {
722*7f2fe78bSCy Schubert         krb5_klog_syslog(LOG_DEBUG, "... %s(%d)",
723*7f2fe78bSCy Schubert                          preauth_systems[pa_order[i]].name,
724*7f2fe78bSCy Schubert                          preauth_systems[pa_order[i]].type);
725*7f2fe78bSCy Schubert     }
726*7f2fe78bSCy Schubert #endif
727*7f2fe78bSCy Schubert }
728*7f2fe78bSCy Schubert 
missing_required_preauth(krb5_db_entry * client,krb5_db_entry * server,krb5_enc_tkt_part * enc_tkt_reply)729*7f2fe78bSCy Schubert const char *missing_required_preauth(krb5_db_entry *client,
730*7f2fe78bSCy Schubert                                      krb5_db_entry *server,
731*7f2fe78bSCy Schubert                                      krb5_enc_tkt_part *enc_tkt_reply)
732*7f2fe78bSCy Schubert {
733*7f2fe78bSCy Schubert #ifdef DEBUG
734*7f2fe78bSCy Schubert     krb5_klog_syslog (
735*7f2fe78bSCy Schubert         LOG_DEBUG,
736*7f2fe78bSCy Schubert         "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth",
737*7f2fe78bSCy Schubert         isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ",
738*7f2fe78bSCy Schubert         isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ",
739*7f2fe78bSCy Schubert         isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ",
740*7f2fe78bSCy Schubert         isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no ");
741*7f2fe78bSCy Schubert #endif
742*7f2fe78bSCy Schubert 
743*7f2fe78bSCy Schubert     if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
744*7f2fe78bSCy Schubert         !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
745*7f2fe78bSCy Schubert         return "NEEDED_PREAUTH";
746*7f2fe78bSCy Schubert 
747*7f2fe78bSCy Schubert     if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
748*7f2fe78bSCy Schubert         !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
749*7f2fe78bSCy Schubert         return "NEEDED_HW_PREAUTH";
750*7f2fe78bSCy Schubert 
751*7f2fe78bSCy Schubert     return 0;
752*7f2fe78bSCy Schubert }
753*7f2fe78bSCy Schubert 
754*7f2fe78bSCy Schubert /* Return true if request's enctypes indicate support for etype-info2. */
755*7f2fe78bSCy Schubert static krb5_boolean
requires_info2(const krb5_kdc_req * request)756*7f2fe78bSCy Schubert requires_info2(const krb5_kdc_req *request)
757*7f2fe78bSCy Schubert {
758*7f2fe78bSCy Schubert     int i;
759*7f2fe78bSCy Schubert 
760*7f2fe78bSCy Schubert     for (i = 0; i < request->nktypes; i++) {
761*7f2fe78bSCy Schubert         if (enctype_requires_etype_info_2(request->ktype[i]))
762*7f2fe78bSCy Schubert             return TRUE;
763*7f2fe78bSCy Schubert     }
764*7f2fe78bSCy Schubert     return FALSE;
765*7f2fe78bSCy Schubert }
766*7f2fe78bSCy Schubert 
767*7f2fe78bSCy Schubert /* Add PA-ETYPE-INFO2 and possibly PA-ETYPE-INFO entries to pa_list as
768*7f2fe78bSCy Schubert  * appropriate for the request and client principal. */
769*7f2fe78bSCy Schubert static krb5_error_code
add_etype_info(krb5_context context,krb5_kdcpreauth_rock rock,krb5_pa_data *** pa_list)770*7f2fe78bSCy Schubert add_etype_info(krb5_context context, krb5_kdcpreauth_rock rock,
771*7f2fe78bSCy Schubert                krb5_pa_data ***pa_list)
772*7f2fe78bSCy Schubert {
773*7f2fe78bSCy Schubert     krb5_error_code ret;
774*7f2fe78bSCy Schubert     krb5_data *der;
775*7f2fe78bSCy Schubert 
776*7f2fe78bSCy Schubert     if (rock->client_key == NULL)
777*7f2fe78bSCy Schubert         return 0;
778*7f2fe78bSCy Schubert 
779*7f2fe78bSCy Schubert     if (!requires_info2(rock->request)) {
780*7f2fe78bSCy Schubert         /* Include PA-ETYPE-INFO only for old clients. */
781*7f2fe78bSCy Schubert         ret = make_etype_info(context, FALSE, rock->client->princ,
782*7f2fe78bSCy Schubert                               rock->client_key, rock->client_keyblock->enctype,
783*7f2fe78bSCy Schubert                               &der);
784*7f2fe78bSCy Schubert         if (ret)
785*7f2fe78bSCy Schubert             return ret;
786*7f2fe78bSCy Schubert         ret = k5_add_pa_data_from_data(pa_list, KRB5_PADATA_ETYPE_INFO, der);
787*7f2fe78bSCy Schubert         krb5_free_data(context, der);
788*7f2fe78bSCy Schubert         if (ret)
789*7f2fe78bSCy Schubert             return ret;
790*7f2fe78bSCy Schubert     }
791*7f2fe78bSCy Schubert 
792*7f2fe78bSCy Schubert     /* Always include PA-ETYPE-INFO2. */
793*7f2fe78bSCy Schubert     ret = make_etype_info(context, TRUE, rock->client->princ, rock->client_key,
794*7f2fe78bSCy Schubert                           rock->client_keyblock->enctype, &der);
795*7f2fe78bSCy Schubert     if (ret)
796*7f2fe78bSCy Schubert         return ret;
797*7f2fe78bSCy Schubert     ret = k5_add_pa_data_from_data(pa_list, KRB5_PADATA_ETYPE_INFO2, der);
798*7f2fe78bSCy Schubert     krb5_free_data(context, der);
799*7f2fe78bSCy Schubert     return ret;
800*7f2fe78bSCy Schubert }
801*7f2fe78bSCy Schubert 
802*7f2fe78bSCy Schubert /* Add PW-SALT entries to pa_list as appropriate for the request and client
803*7f2fe78bSCy Schubert  * principal. */
804*7f2fe78bSCy Schubert static krb5_error_code
add_pw_salt(krb5_context context,krb5_kdcpreauth_rock rock,krb5_pa_data *** pa_list)805*7f2fe78bSCy Schubert add_pw_salt(krb5_context context, krb5_kdcpreauth_rock rock,
806*7f2fe78bSCy Schubert             krb5_pa_data ***pa_list)
807*7f2fe78bSCy Schubert {
808*7f2fe78bSCy Schubert     krb5_error_code ret;
809*7f2fe78bSCy Schubert     krb5_data *salt = NULL;
810*7f2fe78bSCy Schubert     krb5_int16 salttype;
811*7f2fe78bSCy Schubert 
812*7f2fe78bSCy Schubert     /* Only include this pa-data for old clients. */
813*7f2fe78bSCy Schubert     if (rock->client_key == NULL || requires_info2(rock->request))
814*7f2fe78bSCy Schubert         return 0;
815*7f2fe78bSCy Schubert 
816*7f2fe78bSCy Schubert     ret = krb5_dbe_compute_salt(context, rock->client_key,
817*7f2fe78bSCy Schubert                                 rock->request->client, &salttype, &salt);
818*7f2fe78bSCy Schubert     if (ret)
819*7f2fe78bSCy Schubert         return 0;
820*7f2fe78bSCy Schubert 
821*7f2fe78bSCy Schubert     ret = k5_add_pa_data_from_data(pa_list, KRB5_PADATA_PW_SALT, salt);
822*7f2fe78bSCy Schubert     krb5_free_data(context, salt);
823*7f2fe78bSCy Schubert     return ret;
824*7f2fe78bSCy Schubert }
825*7f2fe78bSCy Schubert 
826*7f2fe78bSCy Schubert static krb5_error_code
add_freshness_token(krb5_context context,krb5_kdcpreauth_rock rock,krb5_pa_data *** pa_list)827*7f2fe78bSCy Schubert add_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock,
828*7f2fe78bSCy Schubert                     krb5_pa_data ***pa_list)
829*7f2fe78bSCy Schubert {
830*7f2fe78bSCy Schubert     krb5_error_code ret;
831*7f2fe78bSCy Schubert     krb5_timestamp now;
832*7f2fe78bSCy Schubert     krb5_keyblock kb;
833*7f2fe78bSCy Schubert     krb5_checksum cksum;
834*7f2fe78bSCy Schubert     krb5_data d;
835*7f2fe78bSCy Schubert     krb5_pa_data *pa = NULL;
836*7f2fe78bSCy Schubert     char ckbuf[4];
837*7f2fe78bSCy Schubert 
838*7f2fe78bSCy Schubert     memset(&cksum, 0, sizeof(cksum));
839*7f2fe78bSCy Schubert     memset(&kb, 0, sizeof(kb));
840*7f2fe78bSCy Schubert 
841*7f2fe78bSCy Schubert     if (!rock->send_freshness_token)
842*7f2fe78bSCy Schubert         return 0;
843*7f2fe78bSCy Schubert     if (krb5int_find_pa_data(context, rock->request->padata,
844*7f2fe78bSCy Schubert                              KRB5_PADATA_AS_FRESHNESS) == NULL)
845*7f2fe78bSCy Schubert         return 0;
846*7f2fe78bSCy Schubert 
847*7f2fe78bSCy Schubert     /* Compute a checksum over the current KDC time. */
848*7f2fe78bSCy Schubert     ret = krb5_timeofday(context, &now);
849*7f2fe78bSCy Schubert     if (ret)
850*7f2fe78bSCy Schubert         goto cleanup;
851*7f2fe78bSCy Schubert     store_32_be(now, ckbuf);
852*7f2fe78bSCy Schubert     d = make_data(ckbuf, sizeof(ckbuf));
853*7f2fe78bSCy Schubert     ret = krb5_c_make_checksum(context, 0, rock->local_tgt_key,
854*7f2fe78bSCy Schubert                                KRB5_KEYUSAGE_PA_AS_FRESHNESS, &d, &cksum);
855*7f2fe78bSCy Schubert 
856*7f2fe78bSCy Schubert     /* Compose a freshness token from the time, krbtgt kvno, and checksum. */
857*7f2fe78bSCy Schubert     ret = k5_alloc_pa_data(KRB5_PADATA_AS_FRESHNESS, 8 + cksum.length, &pa);
858*7f2fe78bSCy Schubert     if (ret)
859*7f2fe78bSCy Schubert         goto cleanup;
860*7f2fe78bSCy Schubert     store_32_be(now, pa->contents);
861*7f2fe78bSCy Schubert     store_32_be(current_kvno(rock->local_tgt), pa->contents + 4);
862*7f2fe78bSCy Schubert     memcpy(pa->contents + 8, cksum.contents, cksum.length);
863*7f2fe78bSCy Schubert 
864*7f2fe78bSCy Schubert     ret = k5_add_pa_data_element(pa_list, &pa);
865*7f2fe78bSCy Schubert 
866*7f2fe78bSCy Schubert cleanup:
867*7f2fe78bSCy Schubert     krb5_free_keyblock_contents(context, &kb);
868*7f2fe78bSCy Schubert     krb5_free_checksum_contents(context, &cksum);
869*7f2fe78bSCy Schubert     k5_free_pa_data_element(pa);
870*7f2fe78bSCy Schubert     return ret;
871*7f2fe78bSCy Schubert }
872*7f2fe78bSCy Schubert 
873*7f2fe78bSCy Schubert struct hint_state {
874*7f2fe78bSCy Schubert     kdc_hint_respond_fn respond;
875*7f2fe78bSCy Schubert     void *arg;
876*7f2fe78bSCy Schubert     krb5_context context;
877*7f2fe78bSCy Schubert 
878*7f2fe78bSCy Schubert     krb5_kdcpreauth_rock rock;
879*7f2fe78bSCy Schubert     krb5_kdc_req *request;
880*7f2fe78bSCy Schubert     krb5_pa_data ***e_data_out;
881*7f2fe78bSCy Schubert 
882*7f2fe78bSCy Schubert     int hw_only;
883*7f2fe78bSCy Schubert     preauth_system *ap;
884*7f2fe78bSCy Schubert     krb5_pa_data **pa_data;
885*7f2fe78bSCy Schubert     krb5_preauthtype pa_type;
886*7f2fe78bSCy Schubert };
887*7f2fe78bSCy Schubert 
888*7f2fe78bSCy Schubert static void
hint_list_finish(struct hint_state * state,krb5_error_code code)889*7f2fe78bSCy Schubert hint_list_finish(struct hint_state *state, krb5_error_code code)
890*7f2fe78bSCy Schubert {
891*7f2fe78bSCy Schubert     krb5_context context = state->context;
892*7f2fe78bSCy Schubert     kdc_hint_respond_fn oldrespond = state->respond;
893*7f2fe78bSCy Schubert     void *oldarg = state->arg;
894*7f2fe78bSCy Schubert 
895*7f2fe78bSCy Schubert     /* Add a freshness token if a preauth module requested it and the client
896*7f2fe78bSCy Schubert      * request indicates support for it. */
897*7f2fe78bSCy Schubert     if (!code)
898*7f2fe78bSCy Schubert         code = add_freshness_token(context, state->rock, &state->pa_data);
899*7f2fe78bSCy Schubert 
900*7f2fe78bSCy Schubert     if (!code) {
901*7f2fe78bSCy Schubert         if (state->pa_data == NULL) {
902*7f2fe78bSCy Schubert             krb5_klog_syslog(LOG_INFO,
903*7f2fe78bSCy Schubert                              _("%spreauth required but hint list is empty"),
904*7f2fe78bSCy Schubert                              state->hw_only ? "hw" : "");
905*7f2fe78bSCy Schubert         }
906*7f2fe78bSCy Schubert 
907*7f2fe78bSCy Schubert         *state->e_data_out = state->pa_data;
908*7f2fe78bSCy Schubert         state->pa_data = NULL;
909*7f2fe78bSCy Schubert     }
910*7f2fe78bSCy Schubert 
911*7f2fe78bSCy Schubert     krb5_free_pa_data(context, state->pa_data);
912*7f2fe78bSCy Schubert     free(state);
913*7f2fe78bSCy Schubert     (*oldrespond)(oldarg);
914*7f2fe78bSCy Schubert }
915*7f2fe78bSCy Schubert 
916*7f2fe78bSCy Schubert static void
917*7f2fe78bSCy Schubert hint_list_next(struct hint_state *arg);
918*7f2fe78bSCy Schubert 
919*7f2fe78bSCy Schubert static void
finish_get_edata(void * arg,krb5_error_code code,krb5_pa_data * pa)920*7f2fe78bSCy Schubert finish_get_edata(void *arg, krb5_error_code code, krb5_pa_data *pa)
921*7f2fe78bSCy Schubert {
922*7f2fe78bSCy Schubert     krb5_error_code ret;
923*7f2fe78bSCy Schubert     struct hint_state *state = arg;
924*7f2fe78bSCy Schubert 
925*7f2fe78bSCy Schubert     if (code == 0) {
926*7f2fe78bSCy Schubert         if (pa == NULL) {
927*7f2fe78bSCy Schubert             ret = k5_alloc_pa_data(state->pa_type, 0, &pa);
928*7f2fe78bSCy Schubert             if (ret)
929*7f2fe78bSCy Schubert                 goto error;
930*7f2fe78bSCy Schubert         }
931*7f2fe78bSCy Schubert         ret = k5_add_pa_data_element(&state->pa_data, &pa);
932*7f2fe78bSCy Schubert         k5_free_pa_data_element(pa);
933*7f2fe78bSCy Schubert         if (ret)
934*7f2fe78bSCy Schubert             goto error;
935*7f2fe78bSCy Schubert     }
936*7f2fe78bSCy Schubert 
937*7f2fe78bSCy Schubert     state->ap++;
938*7f2fe78bSCy Schubert     hint_list_next(state);
939*7f2fe78bSCy Schubert     return;
940*7f2fe78bSCy Schubert 
941*7f2fe78bSCy Schubert error:
942*7f2fe78bSCy Schubert     hint_list_finish(state, ret);
943*7f2fe78bSCy Schubert }
944*7f2fe78bSCy Schubert 
945*7f2fe78bSCy Schubert static void
hint_list_next(struct hint_state * state)946*7f2fe78bSCy Schubert hint_list_next(struct hint_state *state)
947*7f2fe78bSCy Schubert {
948*7f2fe78bSCy Schubert     krb5_context context = state->context;
949*7f2fe78bSCy Schubert     preauth_system *ap = state->ap;
950*7f2fe78bSCy Schubert 
951*7f2fe78bSCy Schubert     if (ap->type == -1) {
952*7f2fe78bSCy Schubert         hint_list_finish(state, 0);
953*7f2fe78bSCy Schubert         return;
954*7f2fe78bSCy Schubert     }
955*7f2fe78bSCy Schubert 
956*7f2fe78bSCy Schubert     if (state->hw_only && !(ap->flags & PA_HARDWARE))
957*7f2fe78bSCy Schubert         goto next;
958*7f2fe78bSCy Schubert     if (ap->flags & PA_PSEUDO)
959*7f2fe78bSCy Schubert         goto next;
960*7f2fe78bSCy Schubert 
961*7f2fe78bSCy Schubert     state->pa_type = ap->type;
962*7f2fe78bSCy Schubert     if (ap->get_edata) {
963*7f2fe78bSCy Schubert         ap->get_edata(context, state->request, &callbacks, state->rock,
964*7f2fe78bSCy Schubert                       ap->moddata, ap->type, finish_get_edata, state);
965*7f2fe78bSCy Schubert     } else
966*7f2fe78bSCy Schubert         finish_get_edata(state, 0, NULL);
967*7f2fe78bSCy Schubert     return;
968*7f2fe78bSCy Schubert 
969*7f2fe78bSCy Schubert next:
970*7f2fe78bSCy Schubert     state->ap++;
971*7f2fe78bSCy Schubert     hint_list_next(state);
972*7f2fe78bSCy Schubert }
973*7f2fe78bSCy Schubert 
974*7f2fe78bSCy Schubert void
get_preauth_hint_list(krb5_kdc_req * request,krb5_kdcpreauth_rock rock,krb5_pa_data *** e_data_out,kdc_hint_respond_fn respond,void * arg)975*7f2fe78bSCy Schubert get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
976*7f2fe78bSCy Schubert                       krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond,
977*7f2fe78bSCy Schubert                       void *arg)
978*7f2fe78bSCy Schubert {
979*7f2fe78bSCy Schubert     krb5_context context = rock->rstate->realm_data->realm_context;
980*7f2fe78bSCy Schubert     struct hint_state *state;
981*7f2fe78bSCy Schubert 
982*7f2fe78bSCy Schubert     *e_data_out = NULL;
983*7f2fe78bSCy Schubert 
984*7f2fe78bSCy Schubert     /* Allocate our state. */
985*7f2fe78bSCy Schubert     state = calloc(1, sizeof(*state));
986*7f2fe78bSCy Schubert     if (state == NULL)
987*7f2fe78bSCy Schubert         goto error;
988*7f2fe78bSCy Schubert     state->hw_only = isflagset(rock->client->attributes,
989*7f2fe78bSCy Schubert                                KRB5_KDB_REQUIRES_HW_AUTH);
990*7f2fe78bSCy Schubert     state->respond = respond;
991*7f2fe78bSCy Schubert     state->arg = arg;
992*7f2fe78bSCy Schubert     state->request = request;
993*7f2fe78bSCy Schubert     state->rock = rock;
994*7f2fe78bSCy Schubert     state->context = context;
995*7f2fe78bSCy Schubert     state->e_data_out = e_data_out;
996*7f2fe78bSCy Schubert     state->pa_data = NULL;
997*7f2fe78bSCy Schubert     state->ap = preauth_systems;
998*7f2fe78bSCy Schubert 
999*7f2fe78bSCy Schubert     /* Add an empty PA-FX-FAST element to advertise FAST support. */
1000*7f2fe78bSCy Schubert     if (k5_add_empty_pa_data(&state->pa_data, KRB5_PADATA_FX_FAST) != 0)
1001*7f2fe78bSCy Schubert         goto error;
1002*7f2fe78bSCy Schubert 
1003*7f2fe78bSCy Schubert     if (add_etype_info(context, rock, &state->pa_data) != 0)
1004*7f2fe78bSCy Schubert         goto error;
1005*7f2fe78bSCy Schubert 
1006*7f2fe78bSCy Schubert     hint_list_next(state);
1007*7f2fe78bSCy Schubert     return;
1008*7f2fe78bSCy Schubert 
1009*7f2fe78bSCy Schubert error:
1010*7f2fe78bSCy Schubert     if (state != NULL)
1011*7f2fe78bSCy Schubert         krb5_free_pa_data(context, state->pa_data);
1012*7f2fe78bSCy Schubert     free(state);
1013*7f2fe78bSCy Schubert     (*respond)(arg);
1014*7f2fe78bSCy Schubert }
1015*7f2fe78bSCy Schubert 
1016*7f2fe78bSCy Schubert /*
1017*7f2fe78bSCy Schubert  * Add authorization data returned from preauth modules to the ticket
1018*7f2fe78bSCy Schubert  * It is assumed that ad is a "null-terminated" array of krb5_authdata ptrs
1019*7f2fe78bSCy Schubert  */
1020*7f2fe78bSCy Schubert static krb5_error_code
add_authorization_data(krb5_enc_tkt_part * enc_tkt_part,krb5_authdata ** ad)1021*7f2fe78bSCy Schubert add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad)
1022*7f2fe78bSCy Schubert {
1023*7f2fe78bSCy Schubert     krb5_authdata **newad;
1024*7f2fe78bSCy Schubert     int oldones, newones;
1025*7f2fe78bSCy Schubert     int i;
1026*7f2fe78bSCy Schubert 
1027*7f2fe78bSCy Schubert     if (enc_tkt_part == NULL || ad == NULL)
1028*7f2fe78bSCy Schubert         return EINVAL;
1029*7f2fe78bSCy Schubert 
1030*7f2fe78bSCy Schubert     for (newones = 0; ad[newones] != NULL; newones++);
1031*7f2fe78bSCy Schubert     if (newones == 0)
1032*7f2fe78bSCy Schubert         return 0;   /* nothing to add */
1033*7f2fe78bSCy Schubert 
1034*7f2fe78bSCy Schubert     if (enc_tkt_part->authorization_data == NULL)
1035*7f2fe78bSCy Schubert         oldones = 0;
1036*7f2fe78bSCy Schubert     else
1037*7f2fe78bSCy Schubert         for (oldones = 0;
1038*7f2fe78bSCy Schubert              enc_tkt_part->authorization_data[oldones] != NULL; oldones++);
1039*7f2fe78bSCy Schubert 
1040*7f2fe78bSCy Schubert     newad = malloc((oldones + newones + 1) * sizeof(krb5_authdata *));
1041*7f2fe78bSCy Schubert     if (newad == NULL)
1042*7f2fe78bSCy Schubert         return ENOMEM;
1043*7f2fe78bSCy Schubert 
1044*7f2fe78bSCy Schubert     /* Copy any existing pointers */
1045*7f2fe78bSCy Schubert     for (i = 0; i < oldones; i++)
1046*7f2fe78bSCy Schubert         newad[i] = enc_tkt_part->authorization_data[i];
1047*7f2fe78bSCy Schubert 
1048*7f2fe78bSCy Schubert     /* Add the new ones */
1049*7f2fe78bSCy Schubert     for (i = 0; i < newones; i++)
1050*7f2fe78bSCy Schubert         newad[oldones+i] = ad[i];
1051*7f2fe78bSCy Schubert 
1052*7f2fe78bSCy Schubert     /* Terminate the new list */
1053*7f2fe78bSCy Schubert     newad[oldones+i] = NULL;
1054*7f2fe78bSCy Schubert 
1055*7f2fe78bSCy Schubert     /* Free any existing list */
1056*7f2fe78bSCy Schubert     if (enc_tkt_part->authorization_data != NULL)
1057*7f2fe78bSCy Schubert         free(enc_tkt_part->authorization_data);
1058*7f2fe78bSCy Schubert 
1059*7f2fe78bSCy Schubert     /* Install our new list */
1060*7f2fe78bSCy Schubert     enc_tkt_part->authorization_data = newad;
1061*7f2fe78bSCy Schubert 
1062*7f2fe78bSCy Schubert     return 0;
1063*7f2fe78bSCy Schubert }
1064*7f2fe78bSCy Schubert 
1065*7f2fe78bSCy Schubert struct padata_state {
1066*7f2fe78bSCy Schubert     kdc_preauth_respond_fn respond;
1067*7f2fe78bSCy Schubert     void *arg;
1068*7f2fe78bSCy Schubert     kdc_realm_t *realm;
1069*7f2fe78bSCy Schubert 
1070*7f2fe78bSCy Schubert     krb5_kdcpreauth_modreq *modreq_ptr;
1071*7f2fe78bSCy Schubert     krb5_pa_data **padata;
1072*7f2fe78bSCy Schubert     int pa_found;
1073*7f2fe78bSCy Schubert     krb5_context context;
1074*7f2fe78bSCy Schubert     krb5_kdcpreauth_rock rock;
1075*7f2fe78bSCy Schubert     krb5_data *req_pkt;
1076*7f2fe78bSCy Schubert     krb5_kdc_req *request;
1077*7f2fe78bSCy Schubert     krb5_enc_tkt_part *enc_tkt_reply;
1078*7f2fe78bSCy Schubert     void **padata_context;
1079*7f2fe78bSCy Schubert 
1080*7f2fe78bSCy Schubert     preauth_system *pa_sys;
1081*7f2fe78bSCy Schubert     krb5_pa_data **pa_e_data;
1082*7f2fe78bSCy Schubert     krb5_boolean typed_e_data_flag;
1083*7f2fe78bSCy Schubert     int pa_ok;
1084*7f2fe78bSCy Schubert     krb5_error_code saved_code;
1085*7f2fe78bSCy Schubert 
1086*7f2fe78bSCy Schubert     krb5_pa_data ***e_data_out;
1087*7f2fe78bSCy Schubert     krb5_boolean *typed_e_data_out;
1088*7f2fe78bSCy Schubert };
1089*7f2fe78bSCy Schubert 
1090*7f2fe78bSCy Schubert /* Return code if it is 0 or one of the codes we pass through to the client.
1091*7f2fe78bSCy Schubert  * Otherwise return KRB5KDC_ERR_PREAUTH_FAILED. */
1092*7f2fe78bSCy Schubert static krb5_error_code
filter_preauth_error(krb5_error_code code)1093*7f2fe78bSCy Schubert filter_preauth_error(krb5_error_code code)
1094*7f2fe78bSCy Schubert {
1095*7f2fe78bSCy Schubert     /* The following switch statement allows us
1096*7f2fe78bSCy Schubert      * to return some preauth system errors back to the client.
1097*7f2fe78bSCy Schubert      */
1098*7f2fe78bSCy Schubert     switch(code) {
1099*7f2fe78bSCy Schubert     case 0:
1100*7f2fe78bSCy Schubert     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
1101*7f2fe78bSCy Schubert     case KRB5KRB_AP_ERR_SKEW:
1102*7f2fe78bSCy Schubert     case KRB5KDC_ERR_PREAUTH_REQUIRED:
1103*7f2fe78bSCy Schubert     case KRB5KDC_ERR_ETYPE_NOSUPP:
1104*7f2fe78bSCy Schubert         /* rfc 4556 */
1105*7f2fe78bSCy Schubert     case KRB5KDC_ERR_CLIENT_NOT_TRUSTED:
1106*7f2fe78bSCy Schubert     case KRB5KDC_ERR_INVALID_SIG:
1107*7f2fe78bSCy Schubert     case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
1108*7f2fe78bSCy Schubert     case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
1109*7f2fe78bSCy Schubert     case KRB5KDC_ERR_INVALID_CERTIFICATE:
1110*7f2fe78bSCy Schubert     case KRB5KDC_ERR_REVOKED_CERTIFICATE:
1111*7f2fe78bSCy Schubert     case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN:
1112*7f2fe78bSCy Schubert     case KRB5KDC_ERR_CLIENT_NAME_MISMATCH:
1113*7f2fe78bSCy Schubert     case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE:
1114*7f2fe78bSCy Schubert     case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED:
1115*7f2fe78bSCy Schubert     case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED:
1116*7f2fe78bSCy Schubert     case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED:
1117*7f2fe78bSCy Schubert     case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED:
1118*7f2fe78bSCy Schubert         /* earlier drafts of what became rfc 4556 */
1119*7f2fe78bSCy Schubert     case KRB5KDC_ERR_CERTIFICATE_MISMATCH:
1120*7f2fe78bSCy Schubert     case KRB5KDC_ERR_KDC_NOT_TRUSTED:
1121*7f2fe78bSCy Schubert     case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE:
1122*7f2fe78bSCy Schubert         /* This value is shared with
1123*7f2fe78bSCy Schubert          *     KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
1124*7f2fe78bSCy Schubert         /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
1125*7f2fe78bSCy Schubert     case KRB5KDC_ERR_DISCARD:
1126*7f2fe78bSCy Schubert         /* pkinit alg-agility */
1127*7f2fe78bSCy Schubert     case KRB5KDC_ERR_NO_ACCEPTABLE_KDF:
1128*7f2fe78bSCy Schubert         /* rfc 6113 */
1129*7f2fe78bSCy Schubert     case KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED:
1130*7f2fe78bSCy Schubert         return code;
1131*7f2fe78bSCy Schubert     default:
1132*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
1133*7f2fe78bSCy Schubert     }
1134*7f2fe78bSCy Schubert }
1135*7f2fe78bSCy Schubert 
1136*7f2fe78bSCy Schubert /*
1137*7f2fe78bSCy Schubert  * If the client performed optimistic pre-authentication for a multi-round-trip
1138*7f2fe78bSCy Schubert  * mechanism, it may need key information to complete the exchange, so send it
1139*7f2fe78bSCy Schubert  * a PA-ETYPE-INFO2 element in addition to the pa-data from the module.
1140*7f2fe78bSCy Schubert  */
1141*7f2fe78bSCy Schubert static krb5_error_code
maybe_add_etype_info2(struct padata_state * state,krb5_error_code code)1142*7f2fe78bSCy Schubert maybe_add_etype_info2(struct padata_state *state, krb5_error_code code)
1143*7f2fe78bSCy Schubert {
1144*7f2fe78bSCy Schubert     krb5_error_code ret;
1145*7f2fe78bSCy Schubert     krb5_context context = state->context;
1146*7f2fe78bSCy Schubert     krb5_kdcpreauth_rock rock = state->rock;
1147*7f2fe78bSCy Schubert     krb5_data *der;
1148*7f2fe78bSCy Schubert 
1149*7f2fe78bSCy Schubert     /* Only add key information when requesting another preauth round trip. */
1150*7f2fe78bSCy Schubert     if (code != KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED)
1151*7f2fe78bSCy Schubert         return 0;
1152*7f2fe78bSCy Schubert 
1153*7f2fe78bSCy Schubert     /* Don't try to add key information when there is no key. */
1154*7f2fe78bSCy Schubert     if (rock->client_key == NULL)
1155*7f2fe78bSCy Schubert         return 0;
1156*7f2fe78bSCy Schubert 
1157*7f2fe78bSCy Schubert     /* If the client sent a cookie, it has already seen a KDC response with key
1158*7f2fe78bSCy Schubert      * information. */
1159*7f2fe78bSCy Schubert     if (krb5int_find_pa_data(context, state->request->padata,
1160*7f2fe78bSCy Schubert                              KRB5_PADATA_FX_COOKIE) != NULL)
1161*7f2fe78bSCy Schubert         return 0;
1162*7f2fe78bSCy Schubert 
1163*7f2fe78bSCy Schubert     ret = make_etype_info(context, TRUE, rock->client->princ, rock->client_key,
1164*7f2fe78bSCy Schubert                           rock->client_keyblock->enctype, &der);
1165*7f2fe78bSCy Schubert     if (ret)
1166*7f2fe78bSCy Schubert         return ret;
1167*7f2fe78bSCy Schubert     ret = k5_add_pa_data_from_data(&state->pa_e_data, KRB5_PADATA_ETYPE_INFO2,
1168*7f2fe78bSCy Schubert                                    der);
1169*7f2fe78bSCy Schubert     krb5_free_data(context, der);
1170*7f2fe78bSCy Schubert     return ret;
1171*7f2fe78bSCy Schubert }
1172*7f2fe78bSCy Schubert 
1173*7f2fe78bSCy Schubert /* Release state and respond to the AS-REQ processing code with the result of
1174*7f2fe78bSCy Schubert  * checking pre-authentication data. */
1175*7f2fe78bSCy Schubert static void
finish_check_padata(struct padata_state * state,krb5_error_code code)1176*7f2fe78bSCy Schubert finish_check_padata(struct padata_state *state, krb5_error_code code)
1177*7f2fe78bSCy Schubert {
1178*7f2fe78bSCy Schubert     kdc_preauth_respond_fn respond;
1179*7f2fe78bSCy Schubert     void *arg;
1180*7f2fe78bSCy Schubert 
1181*7f2fe78bSCy Schubert     if (state->pa_ok || !state->pa_found) {
1182*7f2fe78bSCy Schubert         /* Return successfully.  If we didn't match a preauth system, we may
1183*7f2fe78bSCy Schubert          * return PREAUTH_REQUIRED later, but we didn't fail to verify. */
1184*7f2fe78bSCy Schubert         code = 0;
1185*7f2fe78bSCy Schubert         goto cleanup;
1186*7f2fe78bSCy Schubert     }
1187*7f2fe78bSCy Schubert 
1188*7f2fe78bSCy Schubert     /* Add key information to the saved error pa-data if required. */
1189*7f2fe78bSCy Schubert     if (maybe_add_etype_info2(state, code) != 0) {
1190*7f2fe78bSCy Schubert         code = KRB5KDC_ERR_PREAUTH_FAILED;
1191*7f2fe78bSCy Schubert         goto cleanup;
1192*7f2fe78bSCy Schubert     }
1193*7f2fe78bSCy Schubert 
1194*7f2fe78bSCy Schubert     /* Return any saved error pa-data, stealing the pointer from state. */
1195*7f2fe78bSCy Schubert     *state->e_data_out = state->pa_e_data;
1196*7f2fe78bSCy Schubert     *state->typed_e_data_out = state->typed_e_data_flag;
1197*7f2fe78bSCy Schubert     state->pa_e_data = NULL;
1198*7f2fe78bSCy Schubert 
1199*7f2fe78bSCy Schubert cleanup:
1200*7f2fe78bSCy Schubert     /* Discard saved error pa-data if we aren't returning it, free state, and
1201*7f2fe78bSCy Schubert      * respond to the AS-REQ processing code. */
1202*7f2fe78bSCy Schubert     respond = state->respond;
1203*7f2fe78bSCy Schubert     arg = state->arg;
1204*7f2fe78bSCy Schubert     krb5_free_pa_data(state->context, state->pa_e_data);
1205*7f2fe78bSCy Schubert     free(state);
1206*7f2fe78bSCy Schubert     (*respond)(arg, filter_preauth_error(code));
1207*7f2fe78bSCy Schubert }
1208*7f2fe78bSCy Schubert 
1209*7f2fe78bSCy Schubert static void
1210*7f2fe78bSCy Schubert next_padata(struct padata_state *state);
1211*7f2fe78bSCy Schubert 
1212*7f2fe78bSCy Schubert static void
finish_verify_padata(void * arg,krb5_error_code code,krb5_kdcpreauth_modreq modreq,krb5_pa_data ** e_data,krb5_authdata ** authz_data)1213*7f2fe78bSCy Schubert finish_verify_padata(void *arg, krb5_error_code code,
1214*7f2fe78bSCy Schubert                      krb5_kdcpreauth_modreq modreq, krb5_pa_data **e_data,
1215*7f2fe78bSCy Schubert                      krb5_authdata **authz_data)
1216*7f2fe78bSCy Schubert {
1217*7f2fe78bSCy Schubert     struct padata_state *state = arg;
1218*7f2fe78bSCy Schubert     const char *emsg;
1219*7f2fe78bSCy Schubert     krb5_boolean typed_e_data_flag;
1220*7f2fe78bSCy Schubert 
1221*7f2fe78bSCy Schubert     assert(state);
1222*7f2fe78bSCy Schubert     *state->modreq_ptr = modreq;
1223*7f2fe78bSCy Schubert 
1224*7f2fe78bSCy Schubert     if (code) {
1225*7f2fe78bSCy Schubert         emsg = krb5_get_error_message(state->context, code);
1226*7f2fe78bSCy Schubert         krb5_klog_syslog(LOG_INFO, "preauth (%s) verify failure: %s",
1227*7f2fe78bSCy Schubert                          state->pa_sys->name, emsg);
1228*7f2fe78bSCy Schubert         krb5_free_error_message(state->context, emsg);
1229*7f2fe78bSCy Schubert 
1230*7f2fe78bSCy Schubert         /* Ignore authorization data returned from modules that fail */
1231*7f2fe78bSCy Schubert         if (authz_data != NULL) {
1232*7f2fe78bSCy Schubert             krb5_free_authdata(state->context, authz_data);
1233*7f2fe78bSCy Schubert             authz_data = NULL;
1234*7f2fe78bSCy Schubert         }
1235*7f2fe78bSCy Schubert 
1236*7f2fe78bSCy Schubert         typed_e_data_flag = ((state->pa_sys->flags & PA_TYPED_E_DATA) != 0);
1237*7f2fe78bSCy Schubert 
1238*7f2fe78bSCy Schubert         /*
1239*7f2fe78bSCy Schubert          * We'll return edata from either the first PA_REQUIRED module
1240*7f2fe78bSCy Schubert          * that fails, or the first non-PA_REQUIRED module that fails.
1241*7f2fe78bSCy Schubert          * Hang on to edata from the first non-PA_REQUIRED module.
1242*7f2fe78bSCy Schubert          * If we've already got one saved, simply discard this one.
1243*7f2fe78bSCy Schubert          */
1244*7f2fe78bSCy Schubert         if (state->pa_sys->flags & PA_REQUIRED) {
1245*7f2fe78bSCy Schubert             /* free up any previous edata we might have been saving */
1246*7f2fe78bSCy Schubert             if (state->pa_e_data != NULL)
1247*7f2fe78bSCy Schubert                 krb5_free_pa_data(state->context, state->pa_e_data);
1248*7f2fe78bSCy Schubert             state->pa_e_data = e_data;
1249*7f2fe78bSCy Schubert             state->typed_e_data_flag = typed_e_data_flag;
1250*7f2fe78bSCy Schubert 
1251*7f2fe78bSCy Schubert             /* Make sure we use the current retval */
1252*7f2fe78bSCy Schubert             state->pa_ok = 0;
1253*7f2fe78bSCy Schubert             finish_check_padata(state, code);
1254*7f2fe78bSCy Schubert             return;
1255*7f2fe78bSCy Schubert         } else if (state->pa_e_data == NULL) {
1256*7f2fe78bSCy Schubert             /* save the first error code and e-data */
1257*7f2fe78bSCy Schubert             state->pa_e_data = e_data;
1258*7f2fe78bSCy Schubert             state->typed_e_data_flag = typed_e_data_flag;
1259*7f2fe78bSCy Schubert             state->saved_code = code;
1260*7f2fe78bSCy Schubert         } else if (e_data != NULL) {
1261*7f2fe78bSCy Schubert             /* discard this extra e-data from non-PA_REQUIRED module */
1262*7f2fe78bSCy Schubert             krb5_free_pa_data(state->context, e_data);
1263*7f2fe78bSCy Schubert         }
1264*7f2fe78bSCy Schubert     } else {
1265*7f2fe78bSCy Schubert #ifdef DEBUG
1266*7f2fe78bSCy Schubert         krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
1267*7f2fe78bSCy Schubert #endif
1268*7f2fe78bSCy Schubert 
1269*7f2fe78bSCy Schubert         /* Ignore any edata returned on success */
1270*7f2fe78bSCy Schubert         if (e_data != NULL)
1271*7f2fe78bSCy Schubert             krb5_free_pa_data(state->context, e_data);
1272*7f2fe78bSCy Schubert 
1273*7f2fe78bSCy Schubert         /* Add any authorization data to the ticket */
1274*7f2fe78bSCy Schubert         if (authz_data != NULL) {
1275*7f2fe78bSCy Schubert             add_authorization_data(state->enc_tkt_reply, authz_data);
1276*7f2fe78bSCy Schubert             free(authz_data);
1277*7f2fe78bSCy Schubert         }
1278*7f2fe78bSCy Schubert 
1279*7f2fe78bSCy Schubert         state->pa_ok = 1;
1280*7f2fe78bSCy Schubert         if (state->pa_sys->flags & PA_SUFFICIENT) {
1281*7f2fe78bSCy Schubert             finish_check_padata(state, state->saved_code);
1282*7f2fe78bSCy Schubert             return;
1283*7f2fe78bSCy Schubert         }
1284*7f2fe78bSCy Schubert     }
1285*7f2fe78bSCy Schubert 
1286*7f2fe78bSCy Schubert     next_padata(state);
1287*7f2fe78bSCy Schubert }
1288*7f2fe78bSCy Schubert 
1289*7f2fe78bSCy Schubert static void
next_padata(struct padata_state * state)1290*7f2fe78bSCy Schubert next_padata(struct padata_state *state)
1291*7f2fe78bSCy Schubert {
1292*7f2fe78bSCy Schubert     assert(state);
1293*7f2fe78bSCy Schubert     if (!state->padata)
1294*7f2fe78bSCy Schubert         state->padata = state->request->padata;
1295*7f2fe78bSCy Schubert     else
1296*7f2fe78bSCy Schubert         state->padata++;
1297*7f2fe78bSCy Schubert 
1298*7f2fe78bSCy Schubert     if (!*state->padata) {
1299*7f2fe78bSCy Schubert         finish_check_padata(state, state->saved_code);
1300*7f2fe78bSCy Schubert         return;
1301*7f2fe78bSCy Schubert     }
1302*7f2fe78bSCy Schubert 
1303*7f2fe78bSCy Schubert #ifdef DEBUG
1304*7f2fe78bSCy Schubert     krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*state->padata)->pa_type);
1305*7f2fe78bSCy Schubert #endif
1306*7f2fe78bSCy Schubert     if (find_pa_system((*state->padata)->pa_type, &state->pa_sys))
1307*7f2fe78bSCy Schubert         goto next;
1308*7f2fe78bSCy Schubert     if (find_modreq(state->pa_sys, *state->padata_context, &state->modreq_ptr))
1309*7f2fe78bSCy Schubert         goto next;
1310*7f2fe78bSCy Schubert #ifdef DEBUG
1311*7f2fe78bSCy Schubert     krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", state->pa_sys->name);
1312*7f2fe78bSCy Schubert #endif
1313*7f2fe78bSCy Schubert     if (state->pa_sys->verify_padata == 0)
1314*7f2fe78bSCy Schubert         goto next;
1315*7f2fe78bSCy Schubert 
1316*7f2fe78bSCy Schubert     state->pa_found++;
1317*7f2fe78bSCy Schubert     state->pa_sys->verify_padata(state->context, state->req_pkt,
1318*7f2fe78bSCy Schubert                                  state->request, state->enc_tkt_reply,
1319*7f2fe78bSCy Schubert                                  *state->padata, &callbacks, state->rock,
1320*7f2fe78bSCy Schubert                                  state->pa_sys->moddata, finish_verify_padata,
1321*7f2fe78bSCy Schubert                                  state);
1322*7f2fe78bSCy Schubert     return;
1323*7f2fe78bSCy Schubert 
1324*7f2fe78bSCy Schubert next:
1325*7f2fe78bSCy Schubert     next_padata(state);
1326*7f2fe78bSCy Schubert }
1327*7f2fe78bSCy Schubert 
1328*7f2fe78bSCy Schubert /*
1329*7f2fe78bSCy Schubert  * This routine is called to verify the preauthentication information
1330*7f2fe78bSCy Schubert  * for a V5 request.
1331*7f2fe78bSCy Schubert  *
1332*7f2fe78bSCy Schubert  * Returns 0 if the pre-authentication is valid, non-zero to indicate
1333*7f2fe78bSCy Schubert  * an error code of some sort.
1334*7f2fe78bSCy Schubert  */
1335*7f2fe78bSCy Schubert 
1336*7f2fe78bSCy Schubert void
check_padata(krb5_context context,krb5_kdcpreauth_rock rock,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,void ** padata_context,krb5_pa_data *** e_data,krb5_boolean * typed_e_data,kdc_preauth_respond_fn respond,void * arg)1337*7f2fe78bSCy Schubert check_padata(krb5_context context, krb5_kdcpreauth_rock rock,
1338*7f2fe78bSCy Schubert              krb5_data *req_pkt, krb5_kdc_req *request,
1339*7f2fe78bSCy Schubert              krb5_enc_tkt_part *enc_tkt_reply, void **padata_context,
1340*7f2fe78bSCy Schubert              krb5_pa_data ***e_data, krb5_boolean *typed_e_data,
1341*7f2fe78bSCy Schubert              kdc_preauth_respond_fn respond, void *arg)
1342*7f2fe78bSCy Schubert {
1343*7f2fe78bSCy Schubert     struct padata_state *state;
1344*7f2fe78bSCy Schubert 
1345*7f2fe78bSCy Schubert     if (request->padata == 0) {
1346*7f2fe78bSCy Schubert         (*respond)(arg, 0);
1347*7f2fe78bSCy Schubert         return;
1348*7f2fe78bSCy Schubert     }
1349*7f2fe78bSCy Schubert 
1350*7f2fe78bSCy Schubert     if (make_padata_context(context, padata_context) != 0) {
1351*7f2fe78bSCy Schubert         (*respond)(arg, KRB5KRB_ERR_GENERIC);
1352*7f2fe78bSCy Schubert         return;
1353*7f2fe78bSCy Schubert     }
1354*7f2fe78bSCy Schubert 
1355*7f2fe78bSCy Schubert     state = calloc(1, sizeof(*state));
1356*7f2fe78bSCy Schubert     if (state == NULL) {
1357*7f2fe78bSCy Schubert         (*respond)(arg, ENOMEM);
1358*7f2fe78bSCy Schubert         return;
1359*7f2fe78bSCy Schubert     }
1360*7f2fe78bSCy Schubert     state->respond = respond;
1361*7f2fe78bSCy Schubert     state->arg = arg;
1362*7f2fe78bSCy Schubert     state->context = context;
1363*7f2fe78bSCy Schubert     state->rock = rock;
1364*7f2fe78bSCy Schubert     state->req_pkt = req_pkt;
1365*7f2fe78bSCy Schubert     state->request = request;
1366*7f2fe78bSCy Schubert     state->enc_tkt_reply = enc_tkt_reply;
1367*7f2fe78bSCy Schubert     state->padata_context = padata_context;
1368*7f2fe78bSCy Schubert     state->e_data_out = e_data;
1369*7f2fe78bSCy Schubert     state->typed_e_data_out = typed_e_data;
1370*7f2fe78bSCy Schubert     state->realm = rock->rstate->realm_data;
1371*7f2fe78bSCy Schubert 
1372*7f2fe78bSCy Schubert #ifdef DEBUG
1373*7f2fe78bSCy Schubert     krb5_klog_syslog (LOG_DEBUG, "checking padata");
1374*7f2fe78bSCy Schubert #endif
1375*7f2fe78bSCy Schubert 
1376*7f2fe78bSCy Schubert     next_padata(state);
1377*7f2fe78bSCy Schubert }
1378*7f2fe78bSCy Schubert 
1379*7f2fe78bSCy Schubert /* Return true if k1 and k2 have the same type and contents. */
1380*7f2fe78bSCy Schubert static krb5_boolean
keyblock_equal(const krb5_keyblock * k1,const krb5_keyblock * k2)1381*7f2fe78bSCy Schubert keyblock_equal(const krb5_keyblock *k1, const krb5_keyblock *k2)
1382*7f2fe78bSCy Schubert {
1383*7f2fe78bSCy Schubert     if (k1->enctype != k2->enctype)
1384*7f2fe78bSCy Schubert         return FALSE;
1385*7f2fe78bSCy Schubert     if (k1->length != k2->length)
1386*7f2fe78bSCy Schubert         return FALSE;
1387*7f2fe78bSCy Schubert     return memcmp(k1->contents, k2->contents, k1->length) == 0;
1388*7f2fe78bSCy Schubert }
1389*7f2fe78bSCy Schubert 
1390*7f2fe78bSCy Schubert /*
1391*7f2fe78bSCy Schubert  * return_padata creates any necessary preauthentication
1392*7f2fe78bSCy Schubert  * structures which should be returned by the KDC to the client
1393*7f2fe78bSCy Schubert  */
1394*7f2fe78bSCy Schubert krb5_error_code
return_padata(krb5_context context,krb5_kdcpreauth_rock rock,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_keyblock * encrypting_key,void ** padata_context)1395*7f2fe78bSCy Schubert return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
1396*7f2fe78bSCy Schubert               krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
1397*7f2fe78bSCy Schubert               krb5_keyblock *encrypting_key, void **padata_context)
1398*7f2fe78bSCy Schubert {
1399*7f2fe78bSCy Schubert     krb5_error_code             retval;
1400*7f2fe78bSCy Schubert     krb5_pa_data **             padata;
1401*7f2fe78bSCy Schubert     krb5_pa_data **             send_pa_list = NULL;
1402*7f2fe78bSCy Schubert     krb5_pa_data *              send_pa;
1403*7f2fe78bSCy Schubert     krb5_pa_data *              pa = 0;
1404*7f2fe78bSCy Schubert     krb5_pa_data null_item;
1405*7f2fe78bSCy Schubert     preauth_system *            ap;
1406*7f2fe78bSCy Schubert     int *                       pa_order = NULL;
1407*7f2fe78bSCy Schubert     int *                       pa_type;
1408*7f2fe78bSCy Schubert     int                         size = 0;
1409*7f2fe78bSCy Schubert     krb5_kdcpreauth_modreq      *modreq_ptr;
1410*7f2fe78bSCy Schubert     krb5_boolean                key_modified;
1411*7f2fe78bSCy Schubert     krb5_keyblock               original_key;
1412*7f2fe78bSCy Schubert 
1413*7f2fe78bSCy Schubert     memset(&original_key, 0, sizeof(original_key));
1414*7f2fe78bSCy Schubert 
1415*7f2fe78bSCy Schubert     if ((!*padata_context) &&
1416*7f2fe78bSCy Schubert         (make_padata_context(context, padata_context) != 0)) {
1417*7f2fe78bSCy Schubert         return KRB5KRB_ERR_GENERIC;
1418*7f2fe78bSCy Schubert     }
1419*7f2fe78bSCy Schubert 
1420*7f2fe78bSCy Schubert     for (ap = preauth_systems; ap->type != -1; ap++) {
1421*7f2fe78bSCy Schubert         if (ap->return_padata)
1422*7f2fe78bSCy Schubert             size++;
1423*7f2fe78bSCy Schubert     }
1424*7f2fe78bSCy Schubert 
1425*7f2fe78bSCy Schubert     pa_order = k5calloc(size + 1, sizeof(int), &retval);
1426*7f2fe78bSCy Schubert     if (pa_order == NULL)
1427*7f2fe78bSCy Schubert         goto cleanup;
1428*7f2fe78bSCy Schubert     sort_pa_order(context, request, pa_order);
1429*7f2fe78bSCy Schubert 
1430*7f2fe78bSCy Schubert     retval = krb5_copy_keyblock_contents(context, encrypting_key,
1431*7f2fe78bSCy Schubert                                          &original_key);
1432*7f2fe78bSCy Schubert     if (retval)
1433*7f2fe78bSCy Schubert         goto cleanup;
1434*7f2fe78bSCy Schubert     key_modified = FALSE;
1435*7f2fe78bSCy Schubert     null_item.contents = NULL;
1436*7f2fe78bSCy Schubert     null_item.length = 0;
1437*7f2fe78bSCy Schubert 
1438*7f2fe78bSCy Schubert     for (pa_type = pa_order; *pa_type != -1; pa_type++) {
1439*7f2fe78bSCy Schubert         ap = &preauth_systems[*pa_type];
1440*7f2fe78bSCy Schubert         if (key_modified && (ap->flags & PA_REPLACES_KEY))
1441*7f2fe78bSCy Schubert             continue;
1442*7f2fe78bSCy Schubert         if (ap->return_padata == 0)
1443*7f2fe78bSCy Schubert             continue;
1444*7f2fe78bSCy Schubert         if (find_modreq(ap, *padata_context, &modreq_ptr))
1445*7f2fe78bSCy Schubert             continue;
1446*7f2fe78bSCy Schubert         pa = &null_item;
1447*7f2fe78bSCy Schubert         null_item.pa_type = ap->type;
1448*7f2fe78bSCy Schubert         if (request->padata) {
1449*7f2fe78bSCy Schubert             for (padata = request->padata; *padata; padata++) {
1450*7f2fe78bSCy Schubert                 if ((*padata)->pa_type == ap->type) {
1451*7f2fe78bSCy Schubert                     pa = *padata;
1452*7f2fe78bSCy Schubert                     break;
1453*7f2fe78bSCy Schubert                 }
1454*7f2fe78bSCy Schubert             }
1455*7f2fe78bSCy Schubert         }
1456*7f2fe78bSCy Schubert         send_pa = NULL;
1457*7f2fe78bSCy Schubert         retval = ap->return_padata(context, pa, req_pkt, request, reply,
1458*7f2fe78bSCy Schubert                                    encrypting_key, &send_pa, &callbacks, rock,
1459*7f2fe78bSCy Schubert                                    ap->moddata, *modreq_ptr);
1460*7f2fe78bSCy Schubert         if (retval)
1461*7f2fe78bSCy Schubert             goto cleanup;
1462*7f2fe78bSCy Schubert 
1463*7f2fe78bSCy Schubert         if (send_pa != NULL) {
1464*7f2fe78bSCy Schubert             retval = k5_add_pa_data_element(&send_pa_list, &send_pa);
1465*7f2fe78bSCy Schubert             k5_free_pa_data_element(send_pa);
1466*7f2fe78bSCy Schubert             if (retval)
1467*7f2fe78bSCy Schubert                 goto cleanup;
1468*7f2fe78bSCy Schubert         }
1469*7f2fe78bSCy Schubert 
1470*7f2fe78bSCy Schubert         if (!key_modified && !keyblock_equal(&original_key, encrypting_key))
1471*7f2fe78bSCy Schubert             key_modified = TRUE;
1472*7f2fe78bSCy Schubert     }
1473*7f2fe78bSCy Schubert 
1474*7f2fe78bSCy Schubert     /*
1475*7f2fe78bSCy Schubert      * Add etype-info and pw-salt pa-data as needed.  If we replaced the reply
1476*7f2fe78bSCy Schubert      * key, we can't send consistent etype-info; the salt from the client key
1477*7f2fe78bSCy Schubert      * data doesn't correspond to the replaced reply key, and RFC 4120 section
1478*7f2fe78bSCy Schubert      * 5.2.7.5 forbids us from sending etype-info describing the initial reply
1479*7f2fe78bSCy Schubert      * key in an AS-REP if it doesn't have the same enctype as the replaced
1480*7f2fe78bSCy Schubert      * reply key.  For all current and foreseeable preauth mechs, we can assume
1481*7f2fe78bSCy Schubert      * the client received etype-info2 in an earlier step and already computed
1482*7f2fe78bSCy Schubert      * the initial reply key if it needed it.  The client can determine the
1483*7f2fe78bSCy Schubert      * enctype of the replaced reply key from the etype field of the enc-part
1484*7f2fe78bSCy Schubert      * field of the AS-REP.
1485*7f2fe78bSCy Schubert      */
1486*7f2fe78bSCy Schubert     if (!key_modified) {
1487*7f2fe78bSCy Schubert         retval = add_etype_info(context, rock, &send_pa_list);
1488*7f2fe78bSCy Schubert         if (retval)
1489*7f2fe78bSCy Schubert             goto cleanup;
1490*7f2fe78bSCy Schubert         retval = add_pw_salt(context, rock, &send_pa_list);
1491*7f2fe78bSCy Schubert         if (retval)
1492*7f2fe78bSCy Schubert             goto cleanup;
1493*7f2fe78bSCy Schubert     }
1494*7f2fe78bSCy Schubert 
1495*7f2fe78bSCy Schubert     if (send_pa_list != NULL) {
1496*7f2fe78bSCy Schubert         reply->padata = send_pa_list;
1497*7f2fe78bSCy Schubert         send_pa_list = 0;
1498*7f2fe78bSCy Schubert     }
1499*7f2fe78bSCy Schubert 
1500*7f2fe78bSCy Schubert cleanup:
1501*7f2fe78bSCy Schubert     krb5_free_keyblock_contents(context, &original_key);
1502*7f2fe78bSCy Schubert     free(pa_order);
1503*7f2fe78bSCy Schubert     krb5_free_pa_data(context, send_pa_list);
1504*7f2fe78bSCy Schubert 
1505*7f2fe78bSCy Schubert     return (retval);
1506*7f2fe78bSCy Schubert }
1507*7f2fe78bSCy Schubert 
1508*7f2fe78bSCy Schubert static krb5_error_code
_make_etype_info_entry(krb5_context context,krb5_principal client_princ,krb5_key_data * client_key,krb5_enctype etype,krb5_etype_info_entry ** entry_out,int etype_info2)1509*7f2fe78bSCy Schubert _make_etype_info_entry(krb5_context context,
1510*7f2fe78bSCy Schubert                        krb5_principal client_princ, krb5_key_data *client_key,
1511*7f2fe78bSCy Schubert                        krb5_enctype etype, krb5_etype_info_entry **entry_out,
1512*7f2fe78bSCy Schubert                        int etype_info2)
1513*7f2fe78bSCy Schubert {
1514*7f2fe78bSCy Schubert     krb5_error_code retval;
1515*7f2fe78bSCy Schubert     krb5_int16 salttype;
1516*7f2fe78bSCy Schubert     krb5_data *salt = NULL;
1517*7f2fe78bSCy Schubert     krb5_etype_info_entry *entry = NULL;
1518*7f2fe78bSCy Schubert 
1519*7f2fe78bSCy Schubert     *entry_out = NULL;
1520*7f2fe78bSCy Schubert     entry = malloc(sizeof(*entry));
1521*7f2fe78bSCy Schubert     if (entry == NULL)
1522*7f2fe78bSCy Schubert         return ENOMEM;
1523*7f2fe78bSCy Schubert 
1524*7f2fe78bSCy Schubert     entry->magic = KV5M_ETYPE_INFO_ENTRY;
1525*7f2fe78bSCy Schubert     entry->etype = etype;
1526*7f2fe78bSCy Schubert     entry->length = KRB5_ETYPE_NO_SALT;
1527*7f2fe78bSCy Schubert     entry->salt = NULL;
1528*7f2fe78bSCy Schubert     entry->s2kparams = empty_data();
1529*7f2fe78bSCy Schubert     retval = krb5_dbe_compute_salt(context, client_key, client_princ,
1530*7f2fe78bSCy Schubert                                    &salttype, &salt);
1531*7f2fe78bSCy Schubert     if (retval)
1532*7f2fe78bSCy Schubert         goto cleanup;
1533*7f2fe78bSCy Schubert 
1534*7f2fe78bSCy Schubert     entry->length = salt->length;
1535*7f2fe78bSCy Schubert     entry->salt = (unsigned char *)salt->data;
1536*7f2fe78bSCy Schubert     salt->data = NULL;
1537*7f2fe78bSCy Schubert     *entry_out = entry;
1538*7f2fe78bSCy Schubert     entry = NULL;
1539*7f2fe78bSCy Schubert 
1540*7f2fe78bSCy Schubert cleanup:
1541*7f2fe78bSCy Schubert     if (entry != NULL)
1542*7f2fe78bSCy Schubert         krb5_free_data_contents(context, &entry->s2kparams);
1543*7f2fe78bSCy Schubert     free(entry);
1544*7f2fe78bSCy Schubert     krb5_free_data(context, salt);
1545*7f2fe78bSCy Schubert     return retval;
1546*7f2fe78bSCy Schubert }
1547*7f2fe78bSCy Schubert 
1548*7f2fe78bSCy Schubert /* Encode an etype-info or etype-info2 message for client_key with the given
1549*7f2fe78bSCy Schubert  * enctype, using client to compute the salt if necessary. */
1550*7f2fe78bSCy Schubert static krb5_error_code
make_etype_info(krb5_context context,krb5_boolean etype_info2,krb5_principal client,krb5_key_data * client_key,krb5_enctype enctype,krb5_data ** der_out)1551*7f2fe78bSCy Schubert make_etype_info(krb5_context context, krb5_boolean etype_info2,
1552*7f2fe78bSCy Schubert                 krb5_principal client, krb5_key_data *client_key,
1553*7f2fe78bSCy Schubert                 krb5_enctype enctype, krb5_data **der_out)
1554*7f2fe78bSCy Schubert {
1555*7f2fe78bSCy Schubert     krb5_error_code retval;
1556*7f2fe78bSCy Schubert     krb5_etype_info_entry **entry = NULL;
1557*7f2fe78bSCy Schubert 
1558*7f2fe78bSCy Schubert     *der_out = NULL;
1559*7f2fe78bSCy Schubert 
1560*7f2fe78bSCy Schubert     entry = k5calloc(2, sizeof(*entry), &retval);
1561*7f2fe78bSCy Schubert     if (entry == NULL)
1562*7f2fe78bSCy Schubert         goto cleanup;
1563*7f2fe78bSCy Schubert     retval = _make_etype_info_entry(context, client, client_key, enctype,
1564*7f2fe78bSCy Schubert                                     &entry[0], etype_info2);
1565*7f2fe78bSCy Schubert     if (retval != 0)
1566*7f2fe78bSCy Schubert         goto cleanup;
1567*7f2fe78bSCy Schubert 
1568*7f2fe78bSCy Schubert     if (etype_info2)
1569*7f2fe78bSCy Schubert         retval = encode_krb5_etype_info2(entry, der_out);
1570*7f2fe78bSCy Schubert     else
1571*7f2fe78bSCy Schubert         retval = encode_krb5_etype_info(entry, der_out);
1572*7f2fe78bSCy Schubert 
1573*7f2fe78bSCy Schubert cleanup:
1574*7f2fe78bSCy Schubert     krb5_free_etype_info(context, entry);
1575*7f2fe78bSCy Schubert     return retval;
1576*7f2fe78bSCy Schubert }
1577*7f2fe78bSCy Schubert 
1578*7f2fe78bSCy Schubert /*
1579*7f2fe78bSCy Schubert  * Returns TRUE if the PAC should be included
1580*7f2fe78bSCy Schubert  */
1581*7f2fe78bSCy Schubert krb5_boolean
include_pac_p(krb5_context context,krb5_kdc_req * request)1582*7f2fe78bSCy Schubert include_pac_p(krb5_context context, krb5_kdc_req *request)
1583*7f2fe78bSCy Schubert {
1584*7f2fe78bSCy Schubert     krb5_error_code             code;
1585*7f2fe78bSCy Schubert     krb5_pa_data                **padata;
1586*7f2fe78bSCy Schubert     krb5_boolean                retval = TRUE; /* default is to return PAC */
1587*7f2fe78bSCy Schubert     krb5_data                   data;
1588*7f2fe78bSCy Schubert     krb5_pa_pac_req             *req = NULL;
1589*7f2fe78bSCy Schubert 
1590*7f2fe78bSCy Schubert     if (request->padata == NULL) {
1591*7f2fe78bSCy Schubert         return retval;
1592*7f2fe78bSCy Schubert     }
1593*7f2fe78bSCy Schubert 
1594*7f2fe78bSCy Schubert     for (padata = request->padata; *padata != NULL; padata++) {
1595*7f2fe78bSCy Schubert         if ((*padata)->pa_type == KRB5_PADATA_PAC_REQUEST) {
1596*7f2fe78bSCy Schubert             data.data = (char *)(*padata)->contents;
1597*7f2fe78bSCy Schubert             data.length = (*padata)->length;
1598*7f2fe78bSCy Schubert 
1599*7f2fe78bSCy Schubert             code = decode_krb5_pa_pac_req(&data, &req);
1600*7f2fe78bSCy Schubert             if (code == 0) {
1601*7f2fe78bSCy Schubert                 retval = req->include_pac;
1602*7f2fe78bSCy Schubert                 krb5_free_pa_pac_req(context, req);
1603*7f2fe78bSCy Schubert                 req = NULL;
1604*7f2fe78bSCy Schubert             }
1605*7f2fe78bSCy Schubert             break;
1606*7f2fe78bSCy Schubert         }
1607*7f2fe78bSCy Schubert     }
1608*7f2fe78bSCy Schubert 
1609*7f2fe78bSCy Schubert     return retval;
1610*7f2fe78bSCy Schubert }
1611*7f2fe78bSCy Schubert 
1612*7f2fe78bSCy Schubert static krb5_error_code
return_referral_enc_padata(krb5_context context,krb5_enc_kdc_rep_part * reply,krb5_db_entry * server)1613*7f2fe78bSCy Schubert return_referral_enc_padata( krb5_context context,
1614*7f2fe78bSCy Schubert                             krb5_enc_kdc_rep_part *reply,
1615*7f2fe78bSCy Schubert                             krb5_db_entry *server)
1616*7f2fe78bSCy Schubert {
1617*7f2fe78bSCy Schubert     krb5_error_code             code;
1618*7f2fe78bSCy Schubert     krb5_tl_data                tl_data;
1619*7f2fe78bSCy Schubert     krb5_pa_data                *pa;
1620*7f2fe78bSCy Schubert 
1621*7f2fe78bSCy Schubert     tl_data.tl_data_type = KRB5_TL_SVR_REFERRAL_DATA;
1622*7f2fe78bSCy Schubert     code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
1623*7f2fe78bSCy Schubert     if (code || tl_data.tl_data_length == 0)
1624*7f2fe78bSCy Schubert         return 0;
1625*7f2fe78bSCy Schubert 
1626*7f2fe78bSCy Schubert     code = k5_alloc_pa_data(KRB5_PADATA_SVR_REFERRAL_INFO,
1627*7f2fe78bSCy Schubert                             tl_data.tl_data_length, &pa);
1628*7f2fe78bSCy Schubert     if (code)
1629*7f2fe78bSCy Schubert         return code;
1630*7f2fe78bSCy Schubert     memcpy(pa->contents, tl_data.tl_data_contents, tl_data.tl_data_length);
1631*7f2fe78bSCy Schubert     code = k5_add_pa_data_element(&reply->enc_padata, &pa);
1632*7f2fe78bSCy Schubert     k5_free_pa_data_element(pa);
1633*7f2fe78bSCy Schubert     return code;
1634*7f2fe78bSCy Schubert }
1635*7f2fe78bSCy Schubert 
1636*7f2fe78bSCy Schubert krb5_error_code
return_enc_padata(krb5_context context,krb5_data * req_pkt,krb5_kdc_req * request,krb5_keyblock * reply_key,krb5_db_entry * server,krb5_enc_kdc_rep_part * reply_encpart,krb5_boolean is_referral)1637*7f2fe78bSCy Schubert return_enc_padata(krb5_context context, krb5_data *req_pkt,
1638*7f2fe78bSCy Schubert                   krb5_kdc_req *request, krb5_keyblock *reply_key,
1639*7f2fe78bSCy Schubert                   krb5_db_entry *server, krb5_enc_kdc_rep_part *reply_encpart,
1640*7f2fe78bSCy Schubert                   krb5_boolean is_referral)
1641*7f2fe78bSCy Schubert {
1642*7f2fe78bSCy Schubert     krb5_error_code code = 0;
1643*7f2fe78bSCy Schubert     /* This should be initialized and only used for Win2K compat and other
1644*7f2fe78bSCy Schubert      * specific standardized uses such as FAST negotiation. */
1645*7f2fe78bSCy Schubert     if (is_referral) {
1646*7f2fe78bSCy Schubert         code = return_referral_enc_padata(context, reply_encpart, server);
1647*7f2fe78bSCy Schubert         if (code)
1648*7f2fe78bSCy Schubert             return code;
1649*7f2fe78bSCy Schubert     }
1650*7f2fe78bSCy Schubert     code = kdc_handle_protected_negotiation(context, req_pkt, request, reply_key,
1651*7f2fe78bSCy Schubert                                             &reply_encpart->enc_padata);
1652*7f2fe78bSCy Schubert     if (code)
1653*7f2fe78bSCy Schubert         goto cleanup;
1654*7f2fe78bSCy Schubert 
1655*7f2fe78bSCy Schubert     code = kdc_add_pa_pac_options(context, request,
1656*7f2fe78bSCy Schubert                                   &reply_encpart->enc_padata);
1657*7f2fe78bSCy Schubert     if (code)
1658*7f2fe78bSCy Schubert         goto cleanup;
1659*7f2fe78bSCy Schubert 
1660*7f2fe78bSCy Schubert     /*Add potentially other enc_padata providers*/
1661*7f2fe78bSCy Schubert cleanup:
1662*7f2fe78bSCy Schubert     return code;
1663*7f2fe78bSCy Schubert }
1664