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, ©) != 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