10Sstevel@tonic-gate /*
2*7934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate
70Sstevel@tonic-gate /*
8781Sgtb * Copyright 1995, 2003 by the Massachusetts Institute of Technology. All
90Sstevel@tonic-gate * Rights Reserved.
100Sstevel@tonic-gate *
110Sstevel@tonic-gate * Export of this software from the United States of America may
120Sstevel@tonic-gate * require a specific license from the United States Government.
130Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
140Sstevel@tonic-gate * export to obtain such a license before exporting.
150Sstevel@tonic-gate *
160Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
170Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
180Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
190Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
200Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
210Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
220Sstevel@tonic-gate * to distribution of the software without specific, written prior
230Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
240Sstevel@tonic-gate * your software as modified software and not distribute it in such a
250Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
260Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
270Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
280Sstevel@tonic-gate * or implied warranty.
290Sstevel@tonic-gate *
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate * This file contains routines for establishing, verifying, and any other
340Sstevel@tonic-gate * necessary functions, for utilizing the pre-authentication field of the
350Sstevel@tonic-gate * kerberos kdc request, with various hardware/software verification devices.
360Sstevel@tonic-gate */
370Sstevel@tonic-gate
38*7934SMark.Phalan@Sun.COM #include "k5-int.h"
39*7934SMark.Phalan@Sun.COM #include "osconf.h"
40*7934SMark.Phalan@Sun.COM #include <preauth_plugin.h>
41*7934SMark.Phalan@Sun.COM #include "int-proto.h"
42*7934SMark.Phalan@Sun.COM
43*7934SMark.Phalan@Sun.COM #if !defined(_WIN32)
44*7934SMark.Phalan@Sun.COM #include <unistd.h>
45*7934SMark.Phalan@Sun.COM #endif
46*7934SMark.Phalan@Sun.COM
47*7934SMark.Phalan@Sun.COM #if TARGET_OS_MAC
48*7934SMark.Phalan@Sun.COM static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/preauth", NULL }; /* should be a list */
49*7934SMark.Phalan@Sun.COM #else
50*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
51*7934SMark.Phalan@Sun.COM static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL };
52*7934SMark.Phalan@Sun.COM #endif
530Sstevel@tonic-gate
540Sstevel@tonic-gate typedef krb5_error_code (*pa_function)(krb5_context,
550Sstevel@tonic-gate krb5_kdc_req *request,
560Sstevel@tonic-gate krb5_pa_data *in_padata,
570Sstevel@tonic-gate krb5_pa_data **out_padata,
58*7934SMark.Phalan@Sun.COM krb5_data *salt, krb5_data *s2kparams,
590Sstevel@tonic-gate krb5_enctype *etype,
600Sstevel@tonic-gate krb5_keyblock *as_key,
610Sstevel@tonic-gate krb5_prompter_fct prompter_fct,
620Sstevel@tonic-gate void *prompter_data,
630Sstevel@tonic-gate krb5_gic_get_as_key_fct gak_fct,
640Sstevel@tonic-gate void *gak_data);
650Sstevel@tonic-gate
660Sstevel@tonic-gate typedef struct _pa_types_t {
670Sstevel@tonic-gate krb5_preauthtype type;
680Sstevel@tonic-gate pa_function fct;
690Sstevel@tonic-gate int flags;
700Sstevel@tonic-gate } pa_types_t;
710Sstevel@tonic-gate
72*7934SMark.Phalan@Sun.COM /* Create the per-krb5_context context. This means loading the modules
73*7934SMark.Phalan@Sun.COM * if we haven't done that yet (applications which never obtain initial
74*7934SMark.Phalan@Sun.COM * credentials should never hit this routine), breaking up the module's
75*7934SMark.Phalan@Sun.COM * list of support pa_types so that we can iterate over the modules more
76*7934SMark.Phalan@Sun.COM * easily, and copying over the relevant parts of the module's table. */
77*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV
krb5_init_preauth_context(krb5_context kcontext)78*7934SMark.Phalan@Sun.COM krb5_init_preauth_context(krb5_context kcontext)
79*7934SMark.Phalan@Sun.COM {
80*7934SMark.Phalan@Sun.COM int n_modules, n_tables, i, j, k;
81*7934SMark.Phalan@Sun.COM void **tables;
82*7934SMark.Phalan@Sun.COM struct krb5plugin_preauth_client_ftable_v1 *table;
83*7934SMark.Phalan@Sun.COM krb5_preauth_context *context = NULL;
84*7934SMark.Phalan@Sun.COM void *plugin_context;
85*7934SMark.Phalan@Sun.COM krb5_preauthtype pa_type;
86*7934SMark.Phalan@Sun.COM void **rcpp;
87*7934SMark.Phalan@Sun.COM
88*7934SMark.Phalan@Sun.COM /* Only do this once for each krb5_context */
89*7934SMark.Phalan@Sun.COM if (kcontext->preauth_context != NULL)
90*7934SMark.Phalan@Sun.COM return;
91*7934SMark.Phalan@Sun.COM
92*7934SMark.Phalan@Sun.COM /* load the plugins for the current context */
93*7934SMark.Phalan@Sun.COM if (PLUGIN_DIR_OPEN(&kcontext->preauth_plugins) == 0) {
94*7934SMark.Phalan@Sun.COM if (krb5int_open_plugin_dirs(objdirs, NULL,
95*7934SMark.Phalan@Sun.COM &kcontext->preauth_plugins,
96*7934SMark.Phalan@Sun.COM &kcontext->err) != 0) {
97*7934SMark.Phalan@Sun.COM return;
98*7934SMark.Phalan@Sun.COM }
99*7934SMark.Phalan@Sun.COM }
100*7934SMark.Phalan@Sun.COM
101*7934SMark.Phalan@Sun.COM /* pull out the module function tables for all of the modules */
102*7934SMark.Phalan@Sun.COM tables = NULL;
103*7934SMark.Phalan@Sun.COM if (krb5int_get_plugin_dir_data(&kcontext->preauth_plugins,
104*7934SMark.Phalan@Sun.COM "preauthentication_client_1",
105*7934SMark.Phalan@Sun.COM &tables,
106*7934SMark.Phalan@Sun.COM &kcontext->err) != 0) {
107*7934SMark.Phalan@Sun.COM return;
108*7934SMark.Phalan@Sun.COM }
109*7934SMark.Phalan@Sun.COM if (tables == NULL) {
110*7934SMark.Phalan@Sun.COM return;
111*7934SMark.Phalan@Sun.COM }
112*7934SMark.Phalan@Sun.COM
113*7934SMark.Phalan@Sun.COM /* count how many modules we ended up loading, and how many preauth
114*7934SMark.Phalan@Sun.COM * types we may claim to support as a result */
115*7934SMark.Phalan@Sun.COM n_modules = 0;
116*7934SMark.Phalan@Sun.COM for (n_tables = 0;
117*7934SMark.Phalan@Sun.COM (tables != NULL) && (tables[n_tables] != NULL);
118*7934SMark.Phalan@Sun.COM n_tables++) {
119*7934SMark.Phalan@Sun.COM table = tables[n_tables];
120*7934SMark.Phalan@Sun.COM if ((table->pa_type_list != NULL) && (table->process != NULL)) {
121*7934SMark.Phalan@Sun.COM for (j = 0; table->pa_type_list[j] > 0; j++) {
122*7934SMark.Phalan@Sun.COM n_modules++;
123*7934SMark.Phalan@Sun.COM }
124*7934SMark.Phalan@Sun.COM }
125*7934SMark.Phalan@Sun.COM }
126*7934SMark.Phalan@Sun.COM
127*7934SMark.Phalan@Sun.COM /* allocate the space we need */
128*7934SMark.Phalan@Sun.COM context = malloc(sizeof(*context));
129*7934SMark.Phalan@Sun.COM if (context == NULL) {
130*7934SMark.Phalan@Sun.COM krb5int_free_plugin_dir_data(tables);
131*7934SMark.Phalan@Sun.COM return;
132*7934SMark.Phalan@Sun.COM }
133*7934SMark.Phalan@Sun.COM context->modules = malloc(sizeof(context->modules[0]) * n_modules);
134*7934SMark.Phalan@Sun.COM if (context->modules == NULL) {
135*7934SMark.Phalan@Sun.COM krb5int_free_plugin_dir_data(tables);
136*7934SMark.Phalan@Sun.COM free(context);
137*7934SMark.Phalan@Sun.COM return;
138*7934SMark.Phalan@Sun.COM }
139*7934SMark.Phalan@Sun.COM memset(context->modules, 0, sizeof(context->modules[0]) * n_modules);
140*7934SMark.Phalan@Sun.COM context->n_modules = n_modules;
141*7934SMark.Phalan@Sun.COM
142*7934SMark.Phalan@Sun.COM /* fill in the structure */
143*7934SMark.Phalan@Sun.COM k = 0;
144*7934SMark.Phalan@Sun.COM for (i = 0; i < n_tables; i++) {
145*7934SMark.Phalan@Sun.COM table = tables[i];
146*7934SMark.Phalan@Sun.COM if ((table->pa_type_list != NULL) && (table->process != NULL)) {
147*7934SMark.Phalan@Sun.COM plugin_context = NULL;
148*7934SMark.Phalan@Sun.COM if ((table->init != NULL) &&
149*7934SMark.Phalan@Sun.COM ((*table->init)(kcontext, &plugin_context) != 0)) {
150*7934SMark.Phalan@Sun.COM #ifdef DEBUG
151*7934SMark.Phalan@Sun.COM fprintf (stderr, "init err, skipping module \"%s\"\n",
152*7934SMark.Phalan@Sun.COM table->name);
153*7934SMark.Phalan@Sun.COM #endif
154*7934SMark.Phalan@Sun.COM continue;
155*7934SMark.Phalan@Sun.COM }
156*7934SMark.Phalan@Sun.COM
157*7934SMark.Phalan@Sun.COM rcpp = NULL;
158*7934SMark.Phalan@Sun.COM for (j = 0; table->pa_type_list[j] > 0; j++) {
159*7934SMark.Phalan@Sun.COM pa_type = table->pa_type_list[j];
160*7934SMark.Phalan@Sun.COM context->modules[k].pa_type = pa_type;
161*7934SMark.Phalan@Sun.COM context->modules[k].enctypes = table->enctype_list;
162*7934SMark.Phalan@Sun.COM context->modules[k].plugin_context = plugin_context;
163*7934SMark.Phalan@Sun.COM /* Only call client_fini once per plugin */
164*7934SMark.Phalan@Sun.COM if (j == 0)
165*7934SMark.Phalan@Sun.COM context->modules[k].client_fini = table->fini;
166*7934SMark.Phalan@Sun.COM else
167*7934SMark.Phalan@Sun.COM context->modules[k].client_fini = NULL;
168*7934SMark.Phalan@Sun.COM context->modules[k].ftable = table;
169*7934SMark.Phalan@Sun.COM context->modules[k].name = table->name;
170*7934SMark.Phalan@Sun.COM context->modules[k].flags = (*table->flags)(kcontext, pa_type);
171*7934SMark.Phalan@Sun.COM context->modules[k].use_count = 0;
172*7934SMark.Phalan@Sun.COM context->modules[k].client_process = table->process;
173*7934SMark.Phalan@Sun.COM context->modules[k].client_tryagain = table->tryagain;
174*7934SMark.Phalan@Sun.COM if (j == 0)
175*7934SMark.Phalan@Sun.COM context->modules[k].client_supply_gic_opts = table->gic_opts;
176*7934SMark.Phalan@Sun.COM else
177*7934SMark.Phalan@Sun.COM context->modules[k].client_supply_gic_opts = NULL;
178*7934SMark.Phalan@Sun.COM context->modules[k].request_context = NULL;
179*7934SMark.Phalan@Sun.COM /*
180*7934SMark.Phalan@Sun.COM * Only call request_init and request_fini once per plugin.
181*7934SMark.Phalan@Sun.COM * Only the first module within each plugin will ever
182*7934SMark.Phalan@Sun.COM * have request_context filled in. Every module within
183*7934SMark.Phalan@Sun.COM * the plugin will have its request_context_pp pointing
184*7934SMark.Phalan@Sun.COM * to that entry's request_context. That way all the
185*7934SMark.Phalan@Sun.COM * modules within the plugin share the same request_context
186*7934SMark.Phalan@Sun.COM */
187*7934SMark.Phalan@Sun.COM if (j == 0) {
188*7934SMark.Phalan@Sun.COM context->modules[k].client_req_init = table->request_init;
189*7934SMark.Phalan@Sun.COM context->modules[k].client_req_fini = table->request_fini;
190*7934SMark.Phalan@Sun.COM rcpp = &context->modules[k].request_context;
191*7934SMark.Phalan@Sun.COM } else {
192*7934SMark.Phalan@Sun.COM context->modules[k].client_req_init = NULL;
193*7934SMark.Phalan@Sun.COM context->modules[k].client_req_fini = NULL;
194*7934SMark.Phalan@Sun.COM }
195*7934SMark.Phalan@Sun.COM context->modules[k].request_context_pp = rcpp;
196*7934SMark.Phalan@Sun.COM #ifdef DEBUG
197*7934SMark.Phalan@Sun.COM fprintf (stderr, "init module \"%s\", pa_type %d, flag %d\n",
198*7934SMark.Phalan@Sun.COM context->modules[k].name,
199*7934SMark.Phalan@Sun.COM context->modules[k].pa_type,
200*7934SMark.Phalan@Sun.COM context->modules[k].flags);
201*7934SMark.Phalan@Sun.COM #endif
202*7934SMark.Phalan@Sun.COM k++;
203*7934SMark.Phalan@Sun.COM }
204*7934SMark.Phalan@Sun.COM }
205*7934SMark.Phalan@Sun.COM }
206*7934SMark.Phalan@Sun.COM krb5int_free_plugin_dir_data(tables);
207*7934SMark.Phalan@Sun.COM
208*7934SMark.Phalan@Sun.COM /* return the result */
209*7934SMark.Phalan@Sun.COM kcontext->preauth_context = context;
210*7934SMark.Phalan@Sun.COM }
211*7934SMark.Phalan@Sun.COM
212*7934SMark.Phalan@Sun.COM /* Zero the use counts for the modules herein. Usually used before we
213*7934SMark.Phalan@Sun.COM * start processing any data from the server, at which point every module
214*7934SMark.Phalan@Sun.COM * will again be able to take a crack at whatever the server sent. */
215*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV
krb5_clear_preauth_context_use_counts(krb5_context context)216*7934SMark.Phalan@Sun.COM krb5_clear_preauth_context_use_counts(krb5_context context)
217*7934SMark.Phalan@Sun.COM {
218*7934SMark.Phalan@Sun.COM int i;
219*7934SMark.Phalan@Sun.COM if (context->preauth_context != NULL) {
220*7934SMark.Phalan@Sun.COM for (i = 0; i < context->preauth_context->n_modules; i++) {
221*7934SMark.Phalan@Sun.COM context->preauth_context->modules[i].use_count = 0;
222*7934SMark.Phalan@Sun.COM }
223*7934SMark.Phalan@Sun.COM }
224*7934SMark.Phalan@Sun.COM }
225*7934SMark.Phalan@Sun.COM
226*7934SMark.Phalan@Sun.COM /*
227*7934SMark.Phalan@Sun.COM * Give all the preauth plugins a look at the preauth option which
228*7934SMark.Phalan@Sun.COM * has just been set
229*7934SMark.Phalan@Sun.COM */
230*7934SMark.Phalan@Sun.COM krb5_error_code
krb5_preauth_supply_preauth_data(krb5_context context,krb5_gic_opt_ext * opte,const char * attr,const char * value)231*7934SMark.Phalan@Sun.COM krb5_preauth_supply_preauth_data(krb5_context context,
232*7934SMark.Phalan@Sun.COM krb5_gic_opt_ext *opte,
233*7934SMark.Phalan@Sun.COM const char *attr,
234*7934SMark.Phalan@Sun.COM const char *value)
235*7934SMark.Phalan@Sun.COM {
236*7934SMark.Phalan@Sun.COM krb5_error_code retval;
237*7934SMark.Phalan@Sun.COM int i;
238*7934SMark.Phalan@Sun.COM void *pctx;
239*7934SMark.Phalan@Sun.COM const char *emsg = NULL;
240*7934SMark.Phalan@Sun.COM
241*7934SMark.Phalan@Sun.COM if (context->preauth_context == NULL)
242*7934SMark.Phalan@Sun.COM krb5_init_preauth_context(context);
243*7934SMark.Phalan@Sun.COM if (context->preauth_context == NULL) {
244*7934SMark.Phalan@Sun.COM retval = EINVAL;
245*7934SMark.Phalan@Sun.COM krb5int_set_error(&context->err, retval,
246*7934SMark.Phalan@Sun.COM "krb5_preauth_supply_preauth_data: "
247*7934SMark.Phalan@Sun.COM "Unable to initialize preauth context");
248*7934SMark.Phalan@Sun.COM return retval;
249*7934SMark.Phalan@Sun.COM }
250*7934SMark.Phalan@Sun.COM
251*7934SMark.Phalan@Sun.COM /*
252*7934SMark.Phalan@Sun.COM * Go down the list of preauth modules, and supply them with the
253*7934SMark.Phalan@Sun.COM * attribute/value pair.
254*7934SMark.Phalan@Sun.COM */
255*7934SMark.Phalan@Sun.COM for (i = 0; i < context->preauth_context->n_modules; i++) {
256*7934SMark.Phalan@Sun.COM if (context->preauth_context->modules[i].client_supply_gic_opts == NULL)
257*7934SMark.Phalan@Sun.COM continue;
258*7934SMark.Phalan@Sun.COM pctx = context->preauth_context->modules[i].plugin_context;
259*7934SMark.Phalan@Sun.COM retval = (*context->preauth_context->modules[i].client_supply_gic_opts)
260*7934SMark.Phalan@Sun.COM (context, pctx,
261*7934SMark.Phalan@Sun.COM (krb5_get_init_creds_opt *)opte, attr, value);
262*7934SMark.Phalan@Sun.COM if (retval) {
263*7934SMark.Phalan@Sun.COM emsg = krb5_get_error_message(context, retval);
264*7934SMark.Phalan@Sun.COM krb5int_set_error(&context->err, retval, "Preauth plugin %s: %s",
265*7934SMark.Phalan@Sun.COM context->preauth_context->modules[i].name, emsg);
266*7934SMark.Phalan@Sun.COM break;
267*7934SMark.Phalan@Sun.COM }
268*7934SMark.Phalan@Sun.COM }
269*7934SMark.Phalan@Sun.COM return retval;
270*7934SMark.Phalan@Sun.COM }
271*7934SMark.Phalan@Sun.COM
272*7934SMark.Phalan@Sun.COM /* Free the per-krb5_context preauth_context. This means clearing any
273*7934SMark.Phalan@Sun.COM * plugin-specific context which may have been created, and then
274*7934SMark.Phalan@Sun.COM * freeing the context itself. */
275*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV
krb5_free_preauth_context(krb5_context context)276*7934SMark.Phalan@Sun.COM krb5_free_preauth_context(krb5_context context)
277*7934SMark.Phalan@Sun.COM {
278*7934SMark.Phalan@Sun.COM int i;
279*7934SMark.Phalan@Sun.COM void *pctx;
280*7934SMark.Phalan@Sun.COM if (context->preauth_context != NULL) {
281*7934SMark.Phalan@Sun.COM for (i = 0; i < context->preauth_context->n_modules; i++) {
282*7934SMark.Phalan@Sun.COM pctx = context->preauth_context->modules[i].plugin_context;
283*7934SMark.Phalan@Sun.COM if (context->preauth_context->modules[i].client_fini != NULL) {
284*7934SMark.Phalan@Sun.COM (*context->preauth_context->modules[i].client_fini)(context, pctx);
285*7934SMark.Phalan@Sun.COM }
286*7934SMark.Phalan@Sun.COM memset(&context->preauth_context->modules[i], 0,
287*7934SMark.Phalan@Sun.COM sizeof(context->preauth_context->modules[i]));
288*7934SMark.Phalan@Sun.COM }
289*7934SMark.Phalan@Sun.COM if (context->preauth_context->modules != NULL) {
290*7934SMark.Phalan@Sun.COM free(context->preauth_context->modules);
291*7934SMark.Phalan@Sun.COM context->preauth_context->modules = NULL;
292*7934SMark.Phalan@Sun.COM }
293*7934SMark.Phalan@Sun.COM free(context->preauth_context);
294*7934SMark.Phalan@Sun.COM context->preauth_context = NULL;
295*7934SMark.Phalan@Sun.COM }
296*7934SMark.Phalan@Sun.COM }
297*7934SMark.Phalan@Sun.COM
298*7934SMark.Phalan@Sun.COM /* Initialize the per-AS-REQ context. This means calling the client_req_init
299*7934SMark.Phalan@Sun.COM * function to give the plugin a chance to allocate a per-request context. */
300*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV
krb5_preauth_request_context_init(krb5_context context)301*7934SMark.Phalan@Sun.COM krb5_preauth_request_context_init(krb5_context context)
302*7934SMark.Phalan@Sun.COM {
303*7934SMark.Phalan@Sun.COM int i;
304*7934SMark.Phalan@Sun.COM void *rctx, *pctx;
305*7934SMark.Phalan@Sun.COM
306*7934SMark.Phalan@Sun.COM /* Limit this to only one attempt per context? */
307*7934SMark.Phalan@Sun.COM if (context->preauth_context == NULL)
308*7934SMark.Phalan@Sun.COM krb5_init_preauth_context(context);
309*7934SMark.Phalan@Sun.COM if (context->preauth_context != NULL) {
310*7934SMark.Phalan@Sun.COM for (i = 0; i < context->preauth_context->n_modules; i++) {
311*7934SMark.Phalan@Sun.COM pctx = context->preauth_context->modules[i].plugin_context;
312*7934SMark.Phalan@Sun.COM if (context->preauth_context->modules[i].client_req_init != NULL) {
313*7934SMark.Phalan@Sun.COM rctx = context->preauth_context->modules[i].request_context_pp;
314*7934SMark.Phalan@Sun.COM (*context->preauth_context->modules[i].client_req_init) (context, pctx, rctx);
315*7934SMark.Phalan@Sun.COM }
316*7934SMark.Phalan@Sun.COM }
317*7934SMark.Phalan@Sun.COM }
318*7934SMark.Phalan@Sun.COM }
3190Sstevel@tonic-gate
320*7934SMark.Phalan@Sun.COM /* Free the per-AS-REQ context. This means clearing any request-specific
321*7934SMark.Phalan@Sun.COM * context which the plugin may have created. */
322*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV
krb5_preauth_request_context_fini(krb5_context context)323*7934SMark.Phalan@Sun.COM krb5_preauth_request_context_fini(krb5_context context)
324*7934SMark.Phalan@Sun.COM {
325*7934SMark.Phalan@Sun.COM int i;
326*7934SMark.Phalan@Sun.COM void *rctx, *pctx;
327*7934SMark.Phalan@Sun.COM if (context->preauth_context != NULL) {
328*7934SMark.Phalan@Sun.COM for (i = 0; i < context->preauth_context->n_modules; i++) {
329*7934SMark.Phalan@Sun.COM pctx = context->preauth_context->modules[i].plugin_context;
330*7934SMark.Phalan@Sun.COM rctx = context->preauth_context->modules[i].request_context;
331*7934SMark.Phalan@Sun.COM if (rctx != NULL) {
332*7934SMark.Phalan@Sun.COM if (context->preauth_context->modules[i].client_req_fini != NULL) {
333*7934SMark.Phalan@Sun.COM (*context->preauth_context->modules[i].client_req_fini)(context, pctx, rctx);
334*7934SMark.Phalan@Sun.COM }
335*7934SMark.Phalan@Sun.COM context->preauth_context->modules[i].request_context = NULL;
336*7934SMark.Phalan@Sun.COM }
337*7934SMark.Phalan@Sun.COM }
338*7934SMark.Phalan@Sun.COM }
339*7934SMark.Phalan@Sun.COM }
340*7934SMark.Phalan@Sun.COM
341*7934SMark.Phalan@Sun.COM /* Add the named encryption type to the existing list of ktypes. */
342*7934SMark.Phalan@Sun.COM static void
grow_ktypes(krb5_enctype ** out_ktypes,int * out_nktypes,krb5_enctype ktype)343*7934SMark.Phalan@Sun.COM grow_ktypes(krb5_enctype **out_ktypes, int *out_nktypes, krb5_enctype ktype)
344*7934SMark.Phalan@Sun.COM {
345*7934SMark.Phalan@Sun.COM int i;
346*7934SMark.Phalan@Sun.COM krb5_enctype *ktypes;
347*7934SMark.Phalan@Sun.COM for (i = 0; i < *out_nktypes; i++) {
348*7934SMark.Phalan@Sun.COM if ((*out_ktypes)[i] == ktype)
349*7934SMark.Phalan@Sun.COM return;
350*7934SMark.Phalan@Sun.COM }
351*7934SMark.Phalan@Sun.COM ktypes = malloc((*out_nktypes + 2) * sizeof(ktype));
352*7934SMark.Phalan@Sun.COM if (ktypes) {
353*7934SMark.Phalan@Sun.COM for (i = 0; i < *out_nktypes; i++)
354*7934SMark.Phalan@Sun.COM ktypes[i] = (*out_ktypes)[i];
355*7934SMark.Phalan@Sun.COM ktypes[i++] = ktype;
356*7934SMark.Phalan@Sun.COM ktypes[i] = 0;
357*7934SMark.Phalan@Sun.COM free(*out_ktypes);
358*7934SMark.Phalan@Sun.COM *out_ktypes = ktypes;
359*7934SMark.Phalan@Sun.COM *out_nktypes = i;
360*7934SMark.Phalan@Sun.COM }
361*7934SMark.Phalan@Sun.COM }
362*7934SMark.Phalan@Sun.COM
363*7934SMark.Phalan@Sun.COM /*
364*7934SMark.Phalan@Sun.COM * Add the given list of pa_data items to the existing list of items.
365*7934SMark.Phalan@Sun.COM * Factored out here to make reading the do_preauth logic easier to read.
366*7934SMark.Phalan@Sun.COM */
367*7934SMark.Phalan@Sun.COM static int
grow_pa_list(krb5_pa_data *** out_pa_list,int * out_pa_list_size,krb5_pa_data ** addition,int num_addition)368*7934SMark.Phalan@Sun.COM grow_pa_list(krb5_pa_data ***out_pa_list, int *out_pa_list_size,
369*7934SMark.Phalan@Sun.COM krb5_pa_data **addition, int num_addition)
370*7934SMark.Phalan@Sun.COM {
371*7934SMark.Phalan@Sun.COM krb5_pa_data **pa_list;
372*7934SMark.Phalan@Sun.COM int i, j;
373*7934SMark.Phalan@Sun.COM
374*7934SMark.Phalan@Sun.COM if (out_pa_list == NULL || addition == NULL) {
375*7934SMark.Phalan@Sun.COM return EINVAL;
376*7934SMark.Phalan@Sun.COM }
377*7934SMark.Phalan@Sun.COM
378*7934SMark.Phalan@Sun.COM if (*out_pa_list == NULL) {
379*7934SMark.Phalan@Sun.COM /* Allocate room for the new additions and a NULL terminator. */
380*7934SMark.Phalan@Sun.COM pa_list = malloc((num_addition + 1) * sizeof(krb5_pa_data *));
381*7934SMark.Phalan@Sun.COM if (pa_list == NULL)
382*7934SMark.Phalan@Sun.COM return ENOMEM;
383*7934SMark.Phalan@Sun.COM for (i = 0; i < num_addition; i++)
384*7934SMark.Phalan@Sun.COM pa_list[i] = addition[i];
385*7934SMark.Phalan@Sun.COM pa_list[i] = NULL;
386*7934SMark.Phalan@Sun.COM *out_pa_list = pa_list;
387*7934SMark.Phalan@Sun.COM *out_pa_list_size = num_addition;
388*7934SMark.Phalan@Sun.COM } else {
389*7934SMark.Phalan@Sun.COM /*
390*7934SMark.Phalan@Sun.COM * Allocate room for the existing entries plus
391*7934SMark.Phalan@Sun.COM * the new additions and a NULL terminator.
392*7934SMark.Phalan@Sun.COM */
393*7934SMark.Phalan@Sun.COM pa_list = malloc((*out_pa_list_size + num_addition + 1)
394*7934SMark.Phalan@Sun.COM * sizeof(krb5_pa_data *));
395*7934SMark.Phalan@Sun.COM if (pa_list == NULL)
396*7934SMark.Phalan@Sun.COM return ENOMEM;
397*7934SMark.Phalan@Sun.COM for (i = 0; i < *out_pa_list_size; i++)
398*7934SMark.Phalan@Sun.COM pa_list[i] = (*out_pa_list)[i];
399*7934SMark.Phalan@Sun.COM for (j = 0; j < num_addition;)
400*7934SMark.Phalan@Sun.COM pa_list[i++] = addition[j++];
401*7934SMark.Phalan@Sun.COM pa_list[i] = NULL;
402*7934SMark.Phalan@Sun.COM free(*out_pa_list);
403*7934SMark.Phalan@Sun.COM *out_pa_list = pa_list;
404*7934SMark.Phalan@Sun.COM *out_pa_list_size = i;
405*7934SMark.Phalan@Sun.COM }
406*7934SMark.Phalan@Sun.COM return 0;
407*7934SMark.Phalan@Sun.COM }
408*7934SMark.Phalan@Sun.COM
409*7934SMark.Phalan@Sun.COM /*
410*7934SMark.Phalan@Sun.COM * Retrieve a specific piece of information required by the plugin and
411*7934SMark.Phalan@Sun.COM * return it in a new krb5_data item. There are separate request_types
412*7934SMark.Phalan@Sun.COM * to obtain the data and free it.
413*7934SMark.Phalan@Sun.COM *
414*7934SMark.Phalan@Sun.COM * This may require massaging data into a contrived format, but it will
415*7934SMark.Phalan@Sun.COM * hopefully keep us from having to reveal library-internal functions
416*7934SMark.Phalan@Sun.COM * or data to the plugin modules.
417*7934SMark.Phalan@Sun.COM */
418*7934SMark.Phalan@Sun.COM
419*7934SMark.Phalan@Sun.COM static krb5_error_code
client_data_proc(krb5_context kcontext,krb5_preauth_client_rock * rock,krb5_int32 request_type,krb5_data ** retdata)420*7934SMark.Phalan@Sun.COM client_data_proc(krb5_context kcontext,
421*7934SMark.Phalan@Sun.COM krb5_preauth_client_rock *rock,
422*7934SMark.Phalan@Sun.COM krb5_int32 request_type,
423*7934SMark.Phalan@Sun.COM krb5_data **retdata)
424*7934SMark.Phalan@Sun.COM {
425*7934SMark.Phalan@Sun.COM krb5_data *ret;
426*7934SMark.Phalan@Sun.COM char *data;
427*7934SMark.Phalan@Sun.COM
428*7934SMark.Phalan@Sun.COM if (rock->magic != CLIENT_ROCK_MAGIC)
429*7934SMark.Phalan@Sun.COM return EINVAL;
430*7934SMark.Phalan@Sun.COM if (retdata == NULL)
431*7934SMark.Phalan@Sun.COM return EINVAL;
432*7934SMark.Phalan@Sun.COM
433*7934SMark.Phalan@Sun.COM switch (request_type) {
434*7934SMark.Phalan@Sun.COM case krb5plugin_preauth_client_get_etype:
435*7934SMark.Phalan@Sun.COM {
436*7934SMark.Phalan@Sun.COM krb5_enctype *eptr;
437*7934SMark.Phalan@Sun.COM if (rock->as_reply == NULL)
438*7934SMark.Phalan@Sun.COM return ENOENT;
439*7934SMark.Phalan@Sun.COM ret = malloc(sizeof(krb5_data));
440*7934SMark.Phalan@Sun.COM if (ret == NULL)
441*7934SMark.Phalan@Sun.COM return ENOMEM;
442*7934SMark.Phalan@Sun.COM data = malloc(sizeof(krb5_enctype));
443*7934SMark.Phalan@Sun.COM if (data == NULL) {
444*7934SMark.Phalan@Sun.COM free(ret);
445*7934SMark.Phalan@Sun.COM return ENOMEM;
446*7934SMark.Phalan@Sun.COM }
447*7934SMark.Phalan@Sun.COM ret->data = data;
448*7934SMark.Phalan@Sun.COM ret->length = sizeof(krb5_enctype);
449*7934SMark.Phalan@Sun.COM eptr = (krb5_enctype *)data;
450*7934SMark.Phalan@Sun.COM *eptr = rock->as_reply->enc_part.enctype;
451*7934SMark.Phalan@Sun.COM *retdata = ret;
452*7934SMark.Phalan@Sun.COM return 0;
453*7934SMark.Phalan@Sun.COM }
454*7934SMark.Phalan@Sun.COM break;
455*7934SMark.Phalan@Sun.COM case krb5plugin_preauth_client_free_etype:
456*7934SMark.Phalan@Sun.COM ret = *retdata;
457*7934SMark.Phalan@Sun.COM if (ret == NULL)
458*7934SMark.Phalan@Sun.COM return 0;
459*7934SMark.Phalan@Sun.COM if (ret->data)
460*7934SMark.Phalan@Sun.COM free(ret->data);
461*7934SMark.Phalan@Sun.COM free(ret);
462*7934SMark.Phalan@Sun.COM return 0;
463*7934SMark.Phalan@Sun.COM break;
464*7934SMark.Phalan@Sun.COM default:
465*7934SMark.Phalan@Sun.COM return EINVAL;
466*7934SMark.Phalan@Sun.COM }
467*7934SMark.Phalan@Sun.COM }
468*7934SMark.Phalan@Sun.COM
469*7934SMark.Phalan@Sun.COM /* Tweak the request body, for now adding any enctypes which the module claims
470*7934SMark.Phalan@Sun.COM * to add support for to the list, but in the future perhaps doing more
471*7934SMark.Phalan@Sun.COM * involved things. */
472*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV
krb5_preauth_prepare_request(krb5_context kcontext,krb5_gic_opt_ext * opte,krb5_kdc_req * request)473*7934SMark.Phalan@Sun.COM krb5_preauth_prepare_request(krb5_context kcontext,
474*7934SMark.Phalan@Sun.COM krb5_gic_opt_ext *opte,
475*7934SMark.Phalan@Sun.COM krb5_kdc_req *request)
476*7934SMark.Phalan@Sun.COM {
477*7934SMark.Phalan@Sun.COM int i, j;
478*7934SMark.Phalan@Sun.COM
479*7934SMark.Phalan@Sun.COM if (kcontext->preauth_context == NULL) {
480*7934SMark.Phalan@Sun.COM return;
481*7934SMark.Phalan@Sun.COM }
482*7934SMark.Phalan@Sun.COM /* Add the module-specific enctype list to the request, but only if
483*7934SMark.Phalan@Sun.COM * it's something we can safely modify. */
484*7934SMark.Phalan@Sun.COM if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
485*7934SMark.Phalan@Sun.COM for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
486*7934SMark.Phalan@Sun.COM if (kcontext->preauth_context->modules[i].enctypes == NULL)
487*7934SMark.Phalan@Sun.COM continue;
488*7934SMark.Phalan@Sun.COM for (j = 0; kcontext->preauth_context->modules[i].enctypes[j] != 0; j++) {
489*7934SMark.Phalan@Sun.COM grow_ktypes(&request->ktype, &request->nktypes,
490*7934SMark.Phalan@Sun.COM kcontext->preauth_context->modules[i].enctypes[j]);
491*7934SMark.Phalan@Sun.COM }
492*7934SMark.Phalan@Sun.COM }
493*7934SMark.Phalan@Sun.COM }
494*7934SMark.Phalan@Sun.COM }
495*7934SMark.Phalan@Sun.COM
496*7934SMark.Phalan@Sun.COM /* Find the first module which provides for the named preauth type which also
497*7934SMark.Phalan@Sun.COM * hasn't had a chance to run yet (INFO modules don't count, because as a rule
498*7934SMark.Phalan@Sun.COM * they don't generate preauth data), and run it. */
499*7934SMark.Phalan@Sun.COM static krb5_error_code
krb5_run_preauth_plugins(krb5_context kcontext,int module_required_flags,krb5_kdc_req * request,krb5_data * encoded_request_body,krb5_data * encoded_previous_request,krb5_pa_data * in_padata,krb5_prompter_fct prompter,void * prompter_data,preauth_get_as_key_proc gak_fct,krb5_data * salt,krb5_data * s2kparams,void * gak_data,krb5_preauth_client_rock * get_data_rock,krb5_keyblock * as_key,krb5_pa_data *** out_pa_list,int * out_pa_list_size,int * module_ret,int * module_flags,krb5_gic_opt_ext * opte)500*7934SMark.Phalan@Sun.COM krb5_run_preauth_plugins(krb5_context kcontext,
501*7934SMark.Phalan@Sun.COM int module_required_flags,
502*7934SMark.Phalan@Sun.COM krb5_kdc_req *request,
503*7934SMark.Phalan@Sun.COM krb5_data *encoded_request_body,
504*7934SMark.Phalan@Sun.COM krb5_data *encoded_previous_request,
505*7934SMark.Phalan@Sun.COM krb5_pa_data *in_padata,
506*7934SMark.Phalan@Sun.COM krb5_prompter_fct prompter,
507*7934SMark.Phalan@Sun.COM void *prompter_data,
508*7934SMark.Phalan@Sun.COM preauth_get_as_key_proc gak_fct,
509*7934SMark.Phalan@Sun.COM krb5_data *salt,
510*7934SMark.Phalan@Sun.COM krb5_data *s2kparams,
511*7934SMark.Phalan@Sun.COM void *gak_data,
512*7934SMark.Phalan@Sun.COM krb5_preauth_client_rock *get_data_rock,
513*7934SMark.Phalan@Sun.COM krb5_keyblock *as_key,
514*7934SMark.Phalan@Sun.COM krb5_pa_data ***out_pa_list,
515*7934SMark.Phalan@Sun.COM int *out_pa_list_size,
516*7934SMark.Phalan@Sun.COM int *module_ret,
517*7934SMark.Phalan@Sun.COM int *module_flags,
518*7934SMark.Phalan@Sun.COM krb5_gic_opt_ext *opte)
519*7934SMark.Phalan@Sun.COM {
520*7934SMark.Phalan@Sun.COM int i;
521*7934SMark.Phalan@Sun.COM krb5_pa_data **out_pa_data;
522*7934SMark.Phalan@Sun.COM krb5_error_code ret;
523*7934SMark.Phalan@Sun.COM struct _krb5_preauth_context_module *module;
524*7934SMark.Phalan@Sun.COM
525*7934SMark.Phalan@Sun.COM if (kcontext->preauth_context == NULL) {
526*7934SMark.Phalan@Sun.COM return ENOENT;
527*7934SMark.Phalan@Sun.COM }
528*7934SMark.Phalan@Sun.COM /* iterate over all loaded modules */
529*7934SMark.Phalan@Sun.COM for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
530*7934SMark.Phalan@Sun.COM module = &kcontext->preauth_context->modules[i];
531*7934SMark.Phalan@Sun.COM /* skip over those which don't match the preauth type */
532*7934SMark.Phalan@Sun.COM if (module->pa_type != in_padata->pa_type)
533*7934SMark.Phalan@Sun.COM continue;
534*7934SMark.Phalan@Sun.COM /* skip over those which don't match the flags (INFO vs REAL, mainly) */
535*7934SMark.Phalan@Sun.COM if ((module->flags & module_required_flags) == 0)
536*7934SMark.Phalan@Sun.COM continue;
537*7934SMark.Phalan@Sun.COM /* if it's a REAL module, try to call it only once per library call */
538*7934SMark.Phalan@Sun.COM if (module_required_flags & PA_REAL) {
539*7934SMark.Phalan@Sun.COM if (module->use_count > 0) {
540*7934SMark.Phalan@Sun.COM #ifdef DEBUG
541*7934SMark.Phalan@Sun.COM fprintf(stderr, "skipping already-used module \"%s\"(%d)\n",
542*7934SMark.Phalan@Sun.COM module->name, module->pa_type);
543*7934SMark.Phalan@Sun.COM #endif
544*7934SMark.Phalan@Sun.COM continue;
545*7934SMark.Phalan@Sun.COM }
546*7934SMark.Phalan@Sun.COM module->use_count++;
547*7934SMark.Phalan@Sun.COM }
548*7934SMark.Phalan@Sun.COM /* run the module's callback function */
549*7934SMark.Phalan@Sun.COM out_pa_data = NULL;
550*7934SMark.Phalan@Sun.COM #ifdef DEBUG
551*7934SMark.Phalan@Sun.COM fprintf(stderr, "using module \"%s\" (%d), flags = %d\n",
552*7934SMark.Phalan@Sun.COM module->name, module->pa_type, module->flags);
553*7934SMark.Phalan@Sun.COM #endif
554*7934SMark.Phalan@Sun.COM ret = module->client_process(kcontext,
555*7934SMark.Phalan@Sun.COM module->plugin_context,
556*7934SMark.Phalan@Sun.COM *module->request_context_pp,
557*7934SMark.Phalan@Sun.COM (krb5_get_init_creds_opt *)opte,
558*7934SMark.Phalan@Sun.COM client_data_proc,
559*7934SMark.Phalan@Sun.COM get_data_rock,
560*7934SMark.Phalan@Sun.COM request,
561*7934SMark.Phalan@Sun.COM encoded_request_body,
562*7934SMark.Phalan@Sun.COM encoded_previous_request,
563*7934SMark.Phalan@Sun.COM in_padata,
564*7934SMark.Phalan@Sun.COM prompter, prompter_data,
565*7934SMark.Phalan@Sun.COM gak_fct, gak_data, salt, s2kparams,
566*7934SMark.Phalan@Sun.COM as_key,
567*7934SMark.Phalan@Sun.COM &out_pa_data);
568*7934SMark.Phalan@Sun.COM /* Make note of the module's flags and status. */
569*7934SMark.Phalan@Sun.COM *module_flags = module->flags;
570*7934SMark.Phalan@Sun.COM *module_ret = ret;
571*7934SMark.Phalan@Sun.COM /* Save the new preauth data item. */
572*7934SMark.Phalan@Sun.COM if (out_pa_data != NULL) {
573*7934SMark.Phalan@Sun.COM int j;
574*7934SMark.Phalan@Sun.COM for (j = 0; out_pa_data[j] != NULL; j++);
575*7934SMark.Phalan@Sun.COM ret = grow_pa_list(out_pa_list, out_pa_list_size, out_pa_data, j);
576*7934SMark.Phalan@Sun.COM free(out_pa_data);
577*7934SMark.Phalan@Sun.COM if (ret != 0)
578*7934SMark.Phalan@Sun.COM return ret;
579*7934SMark.Phalan@Sun.COM }
580*7934SMark.Phalan@Sun.COM break;
581*7934SMark.Phalan@Sun.COM }
582*7934SMark.Phalan@Sun.COM if (i >= kcontext->preauth_context->n_modules) {
583*7934SMark.Phalan@Sun.COM return ENOENT;
584*7934SMark.Phalan@Sun.COM }
585*7934SMark.Phalan@Sun.COM return 0;
586*7934SMark.Phalan@Sun.COM }
587*7934SMark.Phalan@Sun.COM
5880Sstevel@tonic-gate static
pa_salt(krb5_context context,krb5_kdc_req * request,krb5_pa_data * in_padata,krb5_pa_data ** out_padata,krb5_data * salt,krb5_data * s2kparams,krb5_enctype * etype,krb5_keyblock * as_key,krb5_prompter_fct prompter,void * prompter_data,krb5_gic_get_as_key_fct gak_fct,void * gak_data)5890Sstevel@tonic-gate krb5_error_code pa_salt(krb5_context context,
5900Sstevel@tonic-gate krb5_kdc_req *request,
5910Sstevel@tonic-gate krb5_pa_data *in_padata,
5920Sstevel@tonic-gate krb5_pa_data **out_padata,
593*7934SMark.Phalan@Sun.COM krb5_data *salt, krb5_data *s2kparams,
5940Sstevel@tonic-gate krb5_enctype *etype,
5950Sstevel@tonic-gate krb5_keyblock *as_key,
5960Sstevel@tonic-gate krb5_prompter_fct prompter, void *prompter_data,
5970Sstevel@tonic-gate krb5_gic_get_as_key_fct gak_fct, void *gak_data)
5980Sstevel@tonic-gate {
5990Sstevel@tonic-gate krb5_data tmp;
6000Sstevel@tonic-gate
601*7934SMark.Phalan@Sun.COM /* Solaris Kerberos - resync */
6020Sstevel@tonic-gate tmp.data = (char *)in_padata->contents;
6030Sstevel@tonic-gate tmp.length = in_padata->length;
6040Sstevel@tonic-gate krb5_free_data_contents(context, salt);
6050Sstevel@tonic-gate krb5int_copy_data_contents(context, &tmp, salt);
606*7934SMark.Phalan@Sun.COM
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate if (in_padata->pa_type == KRB5_PADATA_AFS3_SALT)
609*7934SMark.Phalan@Sun.COM salt->length = SALT_TYPE_AFS_LENGTH;
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate return(0);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate /*ARGSUSED*/
6150Sstevel@tonic-gate static
pa_enc_timestamp(krb5_context context,krb5_kdc_req * request,krb5_pa_data * in_padata,krb5_pa_data ** out_padata,krb5_data * salt,krb5_data * s2kparams,krb5_enctype * etype,krb5_keyblock * as_key,krb5_prompter_fct prompter,void * prompter_data,krb5_gic_get_as_key_fct gak_fct,void * gak_data)6160Sstevel@tonic-gate krb5_error_code pa_enc_timestamp(krb5_context context,
6170Sstevel@tonic-gate krb5_kdc_req *request,
6180Sstevel@tonic-gate krb5_pa_data *in_padata,
6190Sstevel@tonic-gate krb5_pa_data **out_padata,
6200Sstevel@tonic-gate krb5_data *salt,
6210Sstevel@tonic-gate krb5_data *s2kparams,
6220Sstevel@tonic-gate krb5_enctype *etype,
6230Sstevel@tonic-gate krb5_keyblock *as_key,
6240Sstevel@tonic-gate krb5_prompter_fct prompter,
6250Sstevel@tonic-gate void *prompter_data,
6260Sstevel@tonic-gate krb5_gic_get_as_key_fct gak_fct,
6270Sstevel@tonic-gate void *gak_data)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate krb5_error_code ret;
6300Sstevel@tonic-gate krb5_pa_enc_ts pa_enc;
6310Sstevel@tonic-gate krb5_data *tmp;
6320Sstevel@tonic-gate krb5_enc_data enc_data;
6330Sstevel@tonic-gate krb5_pa_data *pa;
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate if (as_key->length == 0) {
6360Sstevel@tonic-gate #ifdef DEBUG
637*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
6380Sstevel@tonic-gate if (salt != NULL && salt->data != NULL) {
639*7934SMark.Phalan@Sun.COM fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
6400Sstevel@tonic-gate salt->length);
641*7934SMark.Phalan@Sun.COM if ((int) salt->length > 0)
642*7934SMark.Phalan@Sun.COM fprintf (stderr, " '%.*s'", salt->length, salt->data);
6430Sstevel@tonic-gate fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
6440Sstevel@tonic-gate *etype, request->ktype[0]);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate #endif
647781Sgtb if ((ret = ((*gak_fct)(context, request->client,
648*7934SMark.Phalan@Sun.COM *etype ? *etype : request->ktype[0],
649*7934SMark.Phalan@Sun.COM prompter, prompter_data,
650*7934SMark.Phalan@Sun.COM salt, s2kparams, as_key, gak_data))))
6510Sstevel@tonic-gate return(ret);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /* now get the time of day, and encrypt it accordingly */
6550Sstevel@tonic-gate
656781Sgtb if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec)))
6570Sstevel@tonic-gate return(ret);
6580Sstevel@tonic-gate
659781Sgtb if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp)))
6600Sstevel@tonic-gate return(ret);
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate #ifdef DEBUG
6630Sstevel@tonic-gate fprintf (stderr, "key type %d bytes %02x %02x ...\n",
6640Sstevel@tonic-gate as_key->enctype,
6650Sstevel@tonic-gate as_key->contents[0], as_key->contents[1]);
6660Sstevel@tonic-gate #endif
6670Sstevel@tonic-gate ret = krb5_encrypt_helper(context, as_key,
6680Sstevel@tonic-gate KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
6690Sstevel@tonic-gate tmp, &enc_data);
6700Sstevel@tonic-gate #ifdef DEBUG
6710Sstevel@tonic-gate fprintf (stderr, "enc data { type=%d kvno=%d data=%02x %02x ... }\n",
6720Sstevel@tonic-gate enc_data.enctype, enc_data.kvno,
6730Sstevel@tonic-gate 0xff & enc_data.ciphertext.data[0],
6740Sstevel@tonic-gate 0xff & enc_data.ciphertext.data[1]);
6750Sstevel@tonic-gate #endif
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate krb5_free_data(context, tmp);
6780Sstevel@tonic-gate
6790Sstevel@tonic-gate if (ret) {
6800Sstevel@tonic-gate krb5_xfree(enc_data.ciphertext.data);
6810Sstevel@tonic-gate return(ret);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate ret = encode_krb5_enc_data(&enc_data, &tmp);
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate krb5_xfree(enc_data.ciphertext.data);
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate if (ret)
6890Sstevel@tonic-gate return(ret);
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
6920Sstevel@tonic-gate krb5_free_data(context, tmp);
6930Sstevel@tonic-gate return(ENOMEM);
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate pa->magic = KV5M_PA_DATA;
6970Sstevel@tonic-gate pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
6980Sstevel@tonic-gate pa->length = tmp->length;
6990Sstevel@tonic-gate pa->contents = (krb5_octet *) tmp->data;
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate *out_padata = pa;
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate krb5_xfree(tmp);
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate return(0);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate static
sam_challenge_banner(krb5_int32 sam_type)7090Sstevel@tonic-gate char *sam_challenge_banner(krb5_int32 sam_type)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate char *label;
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate switch (sam_type) {
7140Sstevel@tonic-gate case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */
7150Sstevel@tonic-gate label = "Challenge for Enigma Logic mechanism";
7160Sstevel@tonic-gate break;
7170Sstevel@tonic-gate case PA_SAM_TYPE_DIGI_PATH: /* Digital Pathways */
7180Sstevel@tonic-gate case PA_SAM_TYPE_DIGI_PATH_HEX: /* Digital Pathways */
7190Sstevel@tonic-gate label = "Challenge for Digital Pathways mechanism";
7200Sstevel@tonic-gate break;
7210Sstevel@tonic-gate case PA_SAM_TYPE_ACTIVCARD_DEC: /* Digital Pathways */
7220Sstevel@tonic-gate case PA_SAM_TYPE_ACTIVCARD_HEX: /* Digital Pathways */
7230Sstevel@tonic-gate label = "Challenge for Activcard mechanism";
7240Sstevel@tonic-gate break;
7250Sstevel@tonic-gate case PA_SAM_TYPE_SKEY_K0: /* S/key where KDC has key 0 */
7260Sstevel@tonic-gate label = "Challenge for Enhanced S/Key mechanism";
7270Sstevel@tonic-gate break;
7280Sstevel@tonic-gate case PA_SAM_TYPE_SKEY: /* Traditional S/Key */
7290Sstevel@tonic-gate label = "Challenge for Traditional S/Key mechanism";
7300Sstevel@tonic-gate break;
7310Sstevel@tonic-gate case PA_SAM_TYPE_SECURID: /* Security Dynamics */
7320Sstevel@tonic-gate label = "Challenge for Security Dynamics mechanism";
7330Sstevel@tonic-gate break;
7340Sstevel@tonic-gate case PA_SAM_TYPE_SECURID_PREDICT: /* predictive Security Dynamics */
7350Sstevel@tonic-gate label = "Challenge for Security Dynamics mechanism";
7360Sstevel@tonic-gate break;
7370Sstevel@tonic-gate default:
7380Sstevel@tonic-gate label = "Challenge from authentication server";
7390Sstevel@tonic-gate break;
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate return(label);
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate /* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate #define SAMDATA(kdata, str, maxsize) \
7480Sstevel@tonic-gate (int)((kdata.length)? \
7490Sstevel@tonic-gate ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
7500Sstevel@tonic-gate strlen(str)), \
7510Sstevel@tonic-gate (kdata.length)? \
7520Sstevel@tonic-gate ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate /* XXX Danger! This code is not in sync with the kerberos-password-02
7550Sstevel@tonic-gate draft. This draft cannot be implemented as written. This code is
7560Sstevel@tonic-gate compatible with earlier versions of mit krb5 and cygnus kerbnet. */
7570Sstevel@tonic-gate
7580Sstevel@tonic-gate /*ARGSUSED*/
7590Sstevel@tonic-gate static
pa_sam(krb5_context context,krb5_kdc_req * request,krb5_pa_data * in_padata,krb5_pa_data ** out_padata,krb5_data * salt,krb5_data * s2kparams,krb5_enctype * etype,krb5_keyblock * as_key,krb5_prompter_fct prompter,void * prompter_data,krb5_gic_get_as_key_fct gak_fct,void * gak_data)7600Sstevel@tonic-gate krb5_error_code pa_sam(krb5_context context,
7610Sstevel@tonic-gate krb5_kdc_req *request,
7620Sstevel@tonic-gate krb5_pa_data *in_padata,
7630Sstevel@tonic-gate krb5_pa_data **out_padata,
7640Sstevel@tonic-gate krb5_data *salt,
7650Sstevel@tonic-gate krb5_data *s2kparams,
7660Sstevel@tonic-gate krb5_enctype *etype,
7670Sstevel@tonic-gate krb5_keyblock *as_key,
7680Sstevel@tonic-gate krb5_prompter_fct prompter,
7690Sstevel@tonic-gate void *prompter_data,
7700Sstevel@tonic-gate krb5_gic_get_as_key_fct gak_fct,
7710Sstevel@tonic-gate void *gak_data)
7720Sstevel@tonic-gate {
7730Sstevel@tonic-gate krb5_error_code ret;
7740Sstevel@tonic-gate krb5_data tmpsam;
7750Sstevel@tonic-gate char name[100], banner[100];
7760Sstevel@tonic-gate char prompt[100], response[100];
7770Sstevel@tonic-gate krb5_data response_data;
7780Sstevel@tonic-gate krb5_prompt kprompt;
7790Sstevel@tonic-gate krb5_prompt_type prompt_type;
7800Sstevel@tonic-gate krb5_data defsalt;
7810Sstevel@tonic-gate krb5_sam_challenge *sam_challenge = 0;
7820Sstevel@tonic-gate krb5_sam_response sam_response;
7830Sstevel@tonic-gate /* these two get encrypted and stuffed in to sam_response */
7840Sstevel@tonic-gate krb5_enc_sam_response_enc enc_sam_response_enc;
7850Sstevel@tonic-gate krb5_data * scratch;
7860Sstevel@tonic-gate krb5_pa_data * pa;
787*7934SMark.Phalan@Sun.COM
788*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
7890Sstevel@tonic-gate krb5_enc_data * enc_data;
7900Sstevel@tonic-gate size_t enclen;
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate if (prompter == NULL)
793*7934SMark.Phalan@Sun.COM return EIO;
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate tmpsam.length = in_padata->length;
7960Sstevel@tonic-gate tmpsam.data = (char *) in_padata->contents;
797781Sgtb if ((ret = decode_krb5_sam_challenge(&tmpsam, &sam_challenge)))
7980Sstevel@tonic-gate return(ret);
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
8010Sstevel@tonic-gate krb5_xfree(sam_challenge);
8020Sstevel@tonic-gate return(KRB5_SAM_UNSUPPORTED);
8030Sstevel@tonic-gate }
804*7934SMark.Phalan@Sun.COM
8050Sstevel@tonic-gate /* If we need the password from the user (USE_SAD_AS_KEY not set), */
806*7934SMark.Phalan@Sun.COM /* then get it here. Exception for "old" KDCs with CryptoCard */
807*7934SMark.Phalan@Sun.COM /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd */
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate if (!(sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) ||
8100Sstevel@tonic-gate (sam_challenge->sam_type == PA_SAM_TYPE_CRYPTOCARD)) {
8110Sstevel@tonic-gate
8120Sstevel@tonic-gate /* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
8130Sstevel@tonic-gate /* message from the KDC. If it is not set, pick an enctype that we */
814*7934SMark.Phalan@Sun.COM /* think the KDC will have for us. */
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate if (etype && *etype == 0)
817*7934SMark.Phalan@Sun.COM *etype = ENCTYPE_DES_CBC_CRC;
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate if ((ret = (gak_fct)(context, request->client, *etype, prompter,
8200Sstevel@tonic-gate prompter_data, salt, s2kparams, as_key, gak_data)))
8210Sstevel@tonic-gate return(ret);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate sprintf(name, "%.*s",
8240Sstevel@tonic-gate SAMDATA(sam_challenge->sam_type_name, "SAM Authentication",
8250Sstevel@tonic-gate sizeof(name) - 1));
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate sprintf(banner, "%.*s",
8280Sstevel@tonic-gate SAMDATA(sam_challenge->sam_challenge_label,
8290Sstevel@tonic-gate sam_challenge_banner(sam_challenge->sam_type),
8300Sstevel@tonic-gate sizeof(banner)-1));
8310Sstevel@tonic-gate
8320Sstevel@tonic-gate /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */
8330Sstevel@tonic-gate sprintf(prompt, "%s%.*s%s%.*s",
8340Sstevel@tonic-gate sam_challenge->sam_challenge.length?"Challenge is [":"",
8350Sstevel@tonic-gate SAMDATA(sam_challenge->sam_challenge, "", 20),
8360Sstevel@tonic-gate sam_challenge->sam_challenge.length?"], ":"",
8370Sstevel@tonic-gate SAMDATA(sam_challenge->sam_response_prompt, "passcode", 55));
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate response_data.data = response;
8400Sstevel@tonic-gate response_data.length = sizeof(response);
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate kprompt.prompt = prompt;
843781Sgtb kprompt.hidden = 1;
8440Sstevel@tonic-gate kprompt.reply = &response_data;
8450Sstevel@tonic-gate prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate /* PROMPTER_INVOCATION */
8480Sstevel@tonic-gate krb5int_set_prompt_types(context, &prompt_type);
849781Sgtb if ((ret = ((*prompter)(context, prompter_data, name,
850781Sgtb banner, 1, &kprompt)))) {
8510Sstevel@tonic-gate krb5_xfree(sam_challenge);
8520Sstevel@tonic-gate krb5int_set_prompt_types(context, 0);
8530Sstevel@tonic-gate return(ret);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate krb5int_set_prompt_types(context, 0);
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
8580Sstevel@tonic-gate if (sam_challenge->sam_nonce == 0) {
859781Sgtb if ((ret = krb5_us_timeofday(context,
8600Sstevel@tonic-gate &enc_sam_response_enc.sam_timestamp,
861781Sgtb &enc_sam_response_enc.sam_usec))) {
8620Sstevel@tonic-gate krb5_xfree(sam_challenge);
8630Sstevel@tonic-gate return(ret);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate /* XXX What if more than one flag is set? */
8700Sstevel@tonic-gate if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
8710Sstevel@tonic-gate
872*7934SMark.Phalan@Sun.COM /* Most of this should be taken care of before we get here. We */
8730Sstevel@tonic-gate /* will need the user's password and as_key to encrypt the SAD */
8740Sstevel@tonic-gate /* and we want to preserve ordering of user prompts (first */
8750Sstevel@tonic-gate /* password, then SAM data) so that user's won't be confused. */
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate if (as_key->length) {
8780Sstevel@tonic-gate krb5_free_keyblock_contents(context, as_key);
8790Sstevel@tonic-gate as_key->length = 0;
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate /* generate a salt using the requested principal */
8830Sstevel@tonic-gate
884*7934SMark.Phalan@Sun.COM if ((salt->length == -1 || salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
885781Sgtb if ((ret = krb5_principal2salt(context, request->client,
886781Sgtb &defsalt))) {
8870Sstevel@tonic-gate krb5_xfree(sam_challenge);
8880Sstevel@tonic-gate return(ret);
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate salt = &defsalt;
8920Sstevel@tonic-gate } else {
8930Sstevel@tonic-gate defsalt.length = 0;
8940Sstevel@tonic-gate }
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate /* generate a key using the supplied password */
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
8990Sstevel@tonic-gate (krb5_data *)gak_data, salt, as_key);
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate if (defsalt.length)
9020Sstevel@tonic-gate krb5_xfree(defsalt.data);
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate if (ret) {
9050Sstevel@tonic-gate krb5_xfree(sam_challenge);
9060Sstevel@tonic-gate return(ret);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate /* encrypt the passcode with the key from above */
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate enc_sam_response_enc.sam_sad = response_data;
9120Sstevel@tonic-gate } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate /* process the key as password */
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate if (as_key->length) {
9170Sstevel@tonic-gate krb5_free_keyblock_contents(context, as_key);
9180Sstevel@tonic-gate as_key->length = 0;
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate #if 0
922*7934SMark.Phalan@Sun.COM if ((salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
9230Sstevel@tonic-gate if (ret = krb5_principal2salt(context, request->client,
9240Sstevel@tonic-gate &defsalt)) {
9250Sstevel@tonic-gate krb5_xfree(sam_challenge);
9260Sstevel@tonic-gate return(ret);
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate salt = &defsalt;
9300Sstevel@tonic-gate } else {
9310Sstevel@tonic-gate defsalt.length = 0;
9320Sstevel@tonic-gate }
9330Sstevel@tonic-gate #else
9340Sstevel@tonic-gate defsalt.length = 0;
9350Sstevel@tonic-gate salt = NULL;
9360Sstevel@tonic-gate #endif
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate /* XXX As of the passwords-04 draft, no enctype is specified,
9390Sstevel@tonic-gate the server uses ENCTYPE_DES_CBC_MD5. In the future the
9400Sstevel@tonic-gate server should send a PA-SAM-ETYPE-INFO containing the enctype. */
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
9430Sstevel@tonic-gate &response_data, salt, as_key);
9440Sstevel@tonic-gate
9450Sstevel@tonic-gate if (defsalt.length)
9460Sstevel@tonic-gate krb5_xfree(defsalt.data);
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate if (ret) {
9490Sstevel@tonic-gate krb5_xfree(sam_challenge);
9500Sstevel@tonic-gate return(ret);
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate enc_sam_response_enc.sam_sad.length = 0;
9540Sstevel@tonic-gate } else {
9550Sstevel@tonic-gate /* Eventually, combine SAD with long-term key to get
9560Sstevel@tonic-gate encryption key. */
9570Sstevel@tonic-gate return KRB5_PREAUTH_BAD_TYPE;
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate
9600Sstevel@tonic-gate /* copy things from the challenge */
9610Sstevel@tonic-gate sam_response.sam_nonce = sam_challenge->sam_nonce;
9620Sstevel@tonic-gate sam_response.sam_flags = sam_challenge->sam_flags;
9630Sstevel@tonic-gate sam_response.sam_track_id = sam_challenge->sam_track_id;
9640Sstevel@tonic-gate sam_response.sam_type = sam_challenge->sam_type;
9650Sstevel@tonic-gate sam_response.magic = KV5M_SAM_RESPONSE;
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate krb5_xfree(sam_challenge);
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate /* encode the encoded part of the response */
970781Sgtb if ((ret = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
971*7934SMark.Phalan@Sun.COM &scratch)))
9720Sstevel@tonic-gate return(ret);
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate /*
9750Sstevel@tonic-gate * Solaris Kerberos:
9760Sstevel@tonic-gate * Using new crypto interface now so we can get rid of the
9770Sstevel@tonic-gate * old modules.
9780Sstevel@tonic-gate */
9790Sstevel@tonic-gate if ((ret = krb5_c_encrypt_length(context, as_key->enctype,
9800Sstevel@tonic-gate scratch->length, &enclen))) {
9810Sstevel@tonic-gate krb5_free_data(context, scratch);
9820Sstevel@tonic-gate return(ret);
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate enc_data = &sam_response.sam_enc_nonce_or_ts;
9860Sstevel@tonic-gate enc_data->magic = KV5M_ENC_DATA;
9870Sstevel@tonic-gate enc_data->kvno = 0;
9880Sstevel@tonic-gate enc_data->enctype = as_key->enctype;
9890Sstevel@tonic-gate enc_data->ciphertext.length = enclen;
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate if ((enc_data->ciphertext.data = MALLOC(enclen)) == NULL) {
9920Sstevel@tonic-gate enc_data->ciphertext.length = 0;
9930Sstevel@tonic-gate krb5_free_data(context, scratch);
9940Sstevel@tonic-gate return(ENOMEM);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate if ((ret = krb5_c_encrypt(context, as_key, 0, 0,
9980Sstevel@tonic-gate scratch, enc_data))) {
9990Sstevel@tonic-gate FREE(enc_data->ciphertext.data, enclen);
10000Sstevel@tonic-gate enc_data->ciphertext.data = NULL;
10010Sstevel@tonic-gate enc_data->ciphertext.length = 0;
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate krb5_free_data(context, scratch);
10050Sstevel@tonic-gate
10060Sstevel@tonic-gate if (ret)
10070Sstevel@tonic-gate return(ret);
10080Sstevel@tonic-gate
10090Sstevel@tonic-gate /* sam_enc_key is reserved for future use */
10100Sstevel@tonic-gate sam_response.sam_enc_key.ciphertext.length = 0;
10110Sstevel@tonic-gate
10120Sstevel@tonic-gate if ((pa = malloc(sizeof(krb5_pa_data))) == NULL)
10130Sstevel@tonic-gate return(ENOMEM);
10140Sstevel@tonic-gate
1015781Sgtb if ((ret = encode_krb5_sam_response(&sam_response, &scratch))) {
10160Sstevel@tonic-gate free(pa);
10170Sstevel@tonic-gate return(ret);
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate pa->magic = KV5M_PA_DATA;
10210Sstevel@tonic-gate pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
10220Sstevel@tonic-gate pa->length = scratch->length;
10230Sstevel@tonic-gate pa->contents = (krb5_octet *) scratch->data;
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate *out_padata = pa;
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate return(0);
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate static
pa_sam_2(krb5_context context,krb5_kdc_req * request,krb5_pa_data * in_padata,krb5_pa_data ** out_padata,krb5_data * salt,krb5_data * s2kparams,krb5_enctype * etype,krb5_keyblock * as_key,krb5_prompter_fct prompter,void * prompter_data,krb5_gic_get_as_key_fct gak_fct,void * gak_data)10310Sstevel@tonic-gate krb5_error_code pa_sam_2(krb5_context context,
10320Sstevel@tonic-gate krb5_kdc_req *request,
10330Sstevel@tonic-gate krb5_pa_data *in_padata,
10340Sstevel@tonic-gate krb5_pa_data **out_padata,
10350Sstevel@tonic-gate krb5_data *salt,
10360Sstevel@tonic-gate krb5_data *s2kparams,
10370Sstevel@tonic-gate krb5_enctype *etype,
10380Sstevel@tonic-gate krb5_keyblock *as_key,
10390Sstevel@tonic-gate krb5_prompter_fct prompter,
10400Sstevel@tonic-gate void *prompter_data,
10410Sstevel@tonic-gate krb5_gic_get_as_key_fct gak_fct,
10420Sstevel@tonic-gate void *gak_data) {
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate krb5_error_code retval;
10450Sstevel@tonic-gate krb5_sam_challenge_2 *sc2 = NULL;
10460Sstevel@tonic-gate krb5_sam_challenge_2_body *sc2b = NULL;
10470Sstevel@tonic-gate krb5_data tmp_data;
10480Sstevel@tonic-gate krb5_data response_data;
10490Sstevel@tonic-gate char name[100], banner[100], prompt[100], response[100];
10500Sstevel@tonic-gate krb5_prompt kprompt;
10510Sstevel@tonic-gate krb5_prompt_type prompt_type;
10520Sstevel@tonic-gate krb5_data defsalt;
10530Sstevel@tonic-gate krb5_checksum **cksum;
10540Sstevel@tonic-gate krb5_data *scratch = NULL;
10550Sstevel@tonic-gate krb5_boolean valid_cksum = 0;
10560Sstevel@tonic-gate krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
10570Sstevel@tonic-gate krb5_sam_response_2 sr2;
10580Sstevel@tonic-gate size_t ciph_len;
10590Sstevel@tonic-gate krb5_pa_data *sam_padata;
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate if (prompter == NULL)
10620Sstevel@tonic-gate return KRB5_LIBOS_CANTREADPWD;
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate tmp_data.length = in_padata->length;
10650Sstevel@tonic-gate tmp_data.data = (char *)in_padata->contents;
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2)))
10680Sstevel@tonic-gate return(retval);
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate if (retval)
10730Sstevel@tonic-gate return(retval);
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
10760Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
10770Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
10780Sstevel@tonic-gate return(KRB5_SAM_NO_CHECKSUM);
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
10820Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
10830Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
10840Sstevel@tonic-gate return(KRB5_SAM_UNSUPPORTED);
10850Sstevel@tonic-gate }
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate if (!valid_enctype(sc2b->sam_etype)) {
10880Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
10890Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
10900Sstevel@tonic-gate return(KRB5_SAM_INVALID_ETYPE);
10910Sstevel@tonic-gate }
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate /* All of the above error checks are KDC-specific, that is, they */
10940Sstevel@tonic-gate /* assume a failure in the KDC reply. By returning anything other */
10950Sstevel@tonic-gate /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED, */
10960Sstevel@tonic-gate /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will */
10970Sstevel@tonic-gate /* most likely go on to try the AS_REQ against master KDC */
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
1100*7934SMark.Phalan@Sun.COM /* We will need the password to obtain the key used for */
11010Sstevel@tonic-gate /* the checksum, and encryption of the sam_response. */
11020Sstevel@tonic-gate /* Go ahead and get it now, preserving the ordering of */
11030Sstevel@tonic-gate /* prompts for the user. */
11040Sstevel@tonic-gate
11050Sstevel@tonic-gate retval = (gak_fct)(context, request->client,
11060Sstevel@tonic-gate sc2b->sam_etype, prompter,
11070Sstevel@tonic-gate prompter_data, salt, s2kparams, as_key, gak_data);
11080Sstevel@tonic-gate if (retval) {
11090Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
11100Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
11110Sstevel@tonic-gate return(retval);
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate }
11140Sstevel@tonic-gate
11150Sstevel@tonic-gate sprintf(name, "%.*s",
11160Sstevel@tonic-gate SAMDATA(sc2b->sam_type_name, "SAM Authentication",
11170Sstevel@tonic-gate sizeof(name) - 1));
11180Sstevel@tonic-gate
11190Sstevel@tonic-gate sprintf(banner, "%.*s",
11200Sstevel@tonic-gate SAMDATA(sc2b->sam_challenge_label,
11210Sstevel@tonic-gate sam_challenge_banner(sc2b->sam_type),
11220Sstevel@tonic-gate sizeof(banner)-1));
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate sprintf(prompt, "%s%.*s%s%.*s",
11250Sstevel@tonic-gate sc2b->sam_challenge.length?"Challenge is [":"",
11260Sstevel@tonic-gate SAMDATA(sc2b->sam_challenge, "", 20),
11270Sstevel@tonic-gate sc2b->sam_challenge.length?"], ":"",
11280Sstevel@tonic-gate SAMDATA(sc2b->sam_response_prompt, "passcode", 55));
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate response_data.data = response;
11310Sstevel@tonic-gate response_data.length = sizeof(response);
11320Sstevel@tonic-gate kprompt.prompt = prompt;
11330Sstevel@tonic-gate kprompt.hidden = 1;
11340Sstevel@tonic-gate kprompt.reply = &response_data;
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
11370Sstevel@tonic-gate krb5int_set_prompt_types(context, &prompt_type);
11380Sstevel@tonic-gate
11390Sstevel@tonic-gate if ((retval = ((*prompter)(context, prompter_data, name,
11400Sstevel@tonic-gate banner, 1, &kprompt)))) {
11410Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
11420Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
11430Sstevel@tonic-gate krb5int_set_prompt_types(context, 0);
11440Sstevel@tonic-gate return(retval);
11450Sstevel@tonic-gate }
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate /* Generate salt used by string_to_key() */
11500Sstevel@tonic-gate if ((salt->length == -1) && (salt->data == NULL)) {
1151*7934SMark.Phalan@Sun.COM if ((retval =
1152*7934SMark.Phalan@Sun.COM krb5_principal2salt(context, request->client, &defsalt))) {
11530Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
11540Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
11550Sstevel@tonic-gate return(retval);
11560Sstevel@tonic-gate }
1157*7934SMark.Phalan@Sun.COM salt = &defsalt;
11580Sstevel@tonic-gate } else {
11590Sstevel@tonic-gate defsalt.length = 0;
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate
11620Sstevel@tonic-gate /* Get encryption key to be used for checksum and sam_response */
11630Sstevel@tonic-gate if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
11640Sstevel@tonic-gate /* as_key = string_to_key(password) */
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate if (as_key->length) {
11670Sstevel@tonic-gate krb5_free_keyblock_contents(context, as_key);
11680Sstevel@tonic-gate as_key->length = 0;
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate
1171*7934SMark.Phalan@Sun.COM /* generate a key using the supplied password */
11720Sstevel@tonic-gate retval = krb5_c_string_to_key(context, sc2b->sam_etype,
11730Sstevel@tonic-gate (krb5_data *)gak_data, salt, as_key);
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate if (retval) {
11760Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
11770Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
11780Sstevel@tonic-gate if (defsalt.length) krb5_xfree(defsalt.data);
11790Sstevel@tonic-gate return(retval);
11800Sstevel@tonic-gate }
11810Sstevel@tonic-gate
1182*7934SMark.Phalan@Sun.COM if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
11830Sstevel@tonic-gate /* as_key = combine_key (as_key, string_to_key(SAD)) */
11840Sstevel@tonic-gate krb5_keyblock tmp_kb;
11850Sstevel@tonic-gate
1186*7934SMark.Phalan@Sun.COM retval = krb5_c_string_to_key(context, sc2b->sam_etype,
11870Sstevel@tonic-gate &response_data, salt, &tmp_kb);
11880Sstevel@tonic-gate
1189*7934SMark.Phalan@Sun.COM if (retval) {
11900Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
1191*7934SMark.Phalan@Sun.COM krb5_free_sam_challenge_2_body(context, sc2b);
11920Sstevel@tonic-gate if (defsalt.length) krb5_xfree(defsalt.data);
11930Sstevel@tonic-gate return(retval);
11940Sstevel@tonic-gate }
11950Sstevel@tonic-gate
1196*7934SMark.Phalan@Sun.COM /* This should be a call to the crypto library some day */
11970Sstevel@tonic-gate /* key types should already match the sam_etype */
11980Sstevel@tonic-gate retval = krb5int_c_combine_keys(context, as_key, &tmp_kb, as_key);
11990Sstevel@tonic-gate
1200*7934SMark.Phalan@Sun.COM if (retval) {
12010Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
1202*7934SMark.Phalan@Sun.COM krb5_free_sam_challenge_2_body(context, sc2b);
12030Sstevel@tonic-gate if (defsalt.length) krb5_xfree(defsalt.data);
12040Sstevel@tonic-gate return(retval);
12050Sstevel@tonic-gate }
1206*7934SMark.Phalan@Sun.COM krb5_free_keyblock_contents(context, &tmp_kb);
12070Sstevel@tonic-gate }
1208*7934SMark.Phalan@Sun.COM
1209*7934SMark.Phalan@Sun.COM if (defsalt.length)
12100Sstevel@tonic-gate krb5_xfree(defsalt.data);
12110Sstevel@tonic-gate
12120Sstevel@tonic-gate } else {
12130Sstevel@tonic-gate /* as_key = string_to_key(SAD) */
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate if (as_key->length) {
12160Sstevel@tonic-gate krb5_free_keyblock_contents(context, as_key);
12170Sstevel@tonic-gate as_key->length = 0;
12180Sstevel@tonic-gate }
12190Sstevel@tonic-gate
1220*7934SMark.Phalan@Sun.COM /* generate a key using the supplied password */
12210Sstevel@tonic-gate retval = krb5_c_string_to_key(context, sc2b->sam_etype,
12220Sstevel@tonic-gate &response_data, salt, as_key);
12230Sstevel@tonic-gate
12240Sstevel@tonic-gate if (defsalt.length)
12250Sstevel@tonic-gate krb5_xfree(defsalt.data);
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate if (retval) {
12280Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
12290Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
12300Sstevel@tonic-gate return(retval);
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate /* Now we have a key, verify the checksum on the sam_challenge */
12350Sstevel@tonic-gate
12360Sstevel@tonic-gate cksum = sc2->sam_cksum;
1237*7934SMark.Phalan@Sun.COM
12380Sstevel@tonic-gate while (*cksum) {
12390Sstevel@tonic-gate /* Check this cksum */
12400Sstevel@tonic-gate retval = krb5_c_verify_checksum(context, as_key,
12410Sstevel@tonic-gate KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
12420Sstevel@tonic-gate &sc2->sam_challenge_2_body,
12430Sstevel@tonic-gate *cksum, &valid_cksum);
12440Sstevel@tonic-gate if (retval) {
12450Sstevel@tonic-gate krb5_free_data(context, scratch);
12460Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
12470Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
12480Sstevel@tonic-gate return(retval);
12490Sstevel@tonic-gate }
1250*7934SMark.Phalan@Sun.COM if (valid_cksum)
12510Sstevel@tonic-gate break;
12520Sstevel@tonic-gate cksum++;
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate if (!valid_cksum) {
12560Sstevel@tonic-gate
1257*7934SMark.Phalan@Sun.COM /* If KRB5_SAM_SEND_ENCRYPTED_SAD is set, then password is only */
12580Sstevel@tonic-gate /* source for checksum key. Therefore, a bad checksum means a */
12590Sstevel@tonic-gate /* bad password. Don't give that direct feedback to someone */
12600Sstevel@tonic-gate /* trying to brute-force passwords. */
12610Sstevel@tonic-gate
12620Sstevel@tonic-gate if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD))
12630Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
12640Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
12650Sstevel@tonic-gate /*
1266*7934SMark.Phalan@Sun.COM * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
12670Sstevel@tonic-gate * can interpret that as "password incorrect", which is probably
12680Sstevel@tonic-gate * the best error we can return in this situation.
12690Sstevel@tonic-gate */
12700Sstevel@tonic-gate return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
12710Sstevel@tonic-gate }
1272*7934SMark.Phalan@Sun.COM
12730Sstevel@tonic-gate /* fill in enc_sam_response_enc_2 */
12740Sstevel@tonic-gate enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
12750Sstevel@tonic-gate enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
12760Sstevel@tonic-gate if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
12770Sstevel@tonic-gate enc_sam_response_enc_2.sam_sad = response_data;
12780Sstevel@tonic-gate } else {
12790Sstevel@tonic-gate enc_sam_response_enc_2.sam_sad.data = NULL;
12800Sstevel@tonic-gate enc_sam_response_enc_2.sam_sad.length = 0;
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate
12830Sstevel@tonic-gate /* encode and encrypt enc_sam_response_enc_2 with as_key */
12840Sstevel@tonic-gate retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
12850Sstevel@tonic-gate &scratch);
12860Sstevel@tonic-gate if (retval) {
12870Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
12880Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
12890Sstevel@tonic-gate return(retval);
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate /* Fill in sam_response_2 */
12930Sstevel@tonic-gate memset(&sr2, 0, sizeof(sr2));
12940Sstevel@tonic-gate sr2.sam_type = sc2b->sam_type;
12950Sstevel@tonic-gate sr2.sam_flags = sc2b->sam_flags;
12960Sstevel@tonic-gate sr2.sam_track_id = sc2b->sam_track_id;
12970Sstevel@tonic-gate sr2.sam_nonce = sc2b->sam_nonce;
12980Sstevel@tonic-gate
12990Sstevel@tonic-gate /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded */
13000Sstevel@tonic-gate /* enc_sam_response_enc_2 from above */
13010Sstevel@tonic-gate
13020Sstevel@tonic-gate retval = krb5_c_encrypt_length(context, as_key->enctype, scratch->length,
1303*7934SMark.Phalan@Sun.COM &ciph_len);
13040Sstevel@tonic-gate if (retval) {
13050Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
13060Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
13070Sstevel@tonic-gate return(retval);
13080Sstevel@tonic-gate }
13090Sstevel@tonic-gate sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len;
13100Sstevel@tonic-gate
13110Sstevel@tonic-gate sr2.sam_enc_nonce_or_sad.ciphertext.data =
13120Sstevel@tonic-gate (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
13150Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
13160Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
13170Sstevel@tonic-gate return(ENOMEM);
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate
13200Sstevel@tonic-gate retval = krb5_c_encrypt(context, as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE,
13210Sstevel@tonic-gate NULL, scratch, &sr2.sam_enc_nonce_or_sad);
13220Sstevel@tonic-gate if (retval) {
13230Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
13240Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
13250Sstevel@tonic-gate krb5_free_data(context, scratch);
13260Sstevel@tonic-gate krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
13270Sstevel@tonic-gate return(retval);
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate krb5_free_data(context, scratch);
13300Sstevel@tonic-gate scratch = NULL;
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate /* Encode the sam_response_2 */
13330Sstevel@tonic-gate retval = encode_krb5_sam_response_2(&sr2, &scratch);
13340Sstevel@tonic-gate krb5_free_sam_challenge_2(context, sc2);
13350Sstevel@tonic-gate krb5_free_sam_challenge_2_body(context, sc2b);
13360Sstevel@tonic-gate krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate if (retval) {
13390Sstevel@tonic-gate return (retval);
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate
1342*7934SMark.Phalan@Sun.COM /* Almost there, just need to make padata ! */
13430Sstevel@tonic-gate sam_padata = malloc(sizeof(krb5_pa_data));
13440Sstevel@tonic-gate if (sam_padata == NULL) {
13450Sstevel@tonic-gate krb5_free_data(context, scratch);
13460Sstevel@tonic-gate return(ENOMEM);
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate sam_padata->magic = KV5M_PA_DATA;
13500Sstevel@tonic-gate sam_padata->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
13510Sstevel@tonic-gate sam_padata->length = scratch->length;
13520Sstevel@tonic-gate sam_padata->contents = (krb5_octet *) scratch->data;
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate *out_padata = sam_padata;
13550Sstevel@tonic-gate
13560Sstevel@tonic-gate return(0);
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate
1359*7934SMark.Phalan@Sun.COM static const pa_types_t pa_types[] = {
13600Sstevel@tonic-gate {
13610Sstevel@tonic-gate KRB5_PADATA_PW_SALT,
13620Sstevel@tonic-gate pa_salt,
13630Sstevel@tonic-gate PA_INFO,
13640Sstevel@tonic-gate },
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate KRB5_PADATA_AFS3_SALT,
13670Sstevel@tonic-gate pa_salt,
13680Sstevel@tonic-gate PA_INFO,
13690Sstevel@tonic-gate },
13700Sstevel@tonic-gate {
13710Sstevel@tonic-gate KRB5_PADATA_ENC_TIMESTAMP,
13720Sstevel@tonic-gate pa_enc_timestamp,
13730Sstevel@tonic-gate PA_REAL,
13740Sstevel@tonic-gate },
13750Sstevel@tonic-gate {
1376*7934SMark.Phalan@Sun.COM KRB5_PADATA_SAM_CHALLENGE_2,
13770Sstevel@tonic-gate pa_sam_2,
13780Sstevel@tonic-gate PA_REAL,
13790Sstevel@tonic-gate },
13800Sstevel@tonic-gate {
13810Sstevel@tonic-gate KRB5_PADATA_SAM_CHALLENGE,
13820Sstevel@tonic-gate pa_sam,
13830Sstevel@tonic-gate PA_REAL,
13840Sstevel@tonic-gate },
13850Sstevel@tonic-gate {
13860Sstevel@tonic-gate -1,
13870Sstevel@tonic-gate NULL,
13880Sstevel@tonic-gate 0,
13890Sstevel@tonic-gate },
13900Sstevel@tonic-gate };
13910Sstevel@tonic-gate
1392*7934SMark.Phalan@Sun.COM /*
1393*7934SMark.Phalan@Sun.COM * If one of the modules can adjust its AS_REQ data using the contents of the
1394*7934SMark.Phalan@Sun.COM * err_reply, return 0. If it's the sort of correction which requires that we
1395*7934SMark.Phalan@Sun.COM * ask the user another question, we let the calling application deal with it.
1396*7934SMark.Phalan@Sun.COM */
1397*7934SMark.Phalan@Sun.COM krb5_error_code KRB5_CALLCONV
krb5_do_preauth_tryagain(krb5_context kcontext,krb5_kdc_req * request,krb5_data * encoded_request_body,krb5_data * encoded_previous_request,krb5_pa_data ** padata,krb5_pa_data *** return_padata,krb5_error * err_reply,krb5_data * salt,krb5_data * s2kparams,krb5_enctype * etype,krb5_keyblock * as_key,krb5_prompter_fct prompter,void * prompter_data,krb5_gic_get_as_key_fct gak_fct,void * gak_data,krb5_preauth_client_rock * get_data_rock,krb5_gic_opt_ext * opte)1398*7934SMark.Phalan@Sun.COM krb5_do_preauth_tryagain(krb5_context kcontext,
1399*7934SMark.Phalan@Sun.COM krb5_kdc_req *request,
1400*7934SMark.Phalan@Sun.COM krb5_data *encoded_request_body,
1401*7934SMark.Phalan@Sun.COM krb5_data *encoded_previous_request,
1402*7934SMark.Phalan@Sun.COM krb5_pa_data **padata,
1403*7934SMark.Phalan@Sun.COM krb5_pa_data ***return_padata,
1404*7934SMark.Phalan@Sun.COM krb5_error *err_reply,
1405*7934SMark.Phalan@Sun.COM krb5_data *salt, krb5_data *s2kparams,
1406*7934SMark.Phalan@Sun.COM krb5_enctype *etype,
1407*7934SMark.Phalan@Sun.COM krb5_keyblock *as_key,
1408*7934SMark.Phalan@Sun.COM krb5_prompter_fct prompter, void *prompter_data,
1409*7934SMark.Phalan@Sun.COM krb5_gic_get_as_key_fct gak_fct, void *gak_data,
1410*7934SMark.Phalan@Sun.COM krb5_preauth_client_rock *get_data_rock,
1411*7934SMark.Phalan@Sun.COM krb5_gic_opt_ext *opte)
1412*7934SMark.Phalan@Sun.COM {
1413*7934SMark.Phalan@Sun.COM krb5_error_code ret;
1414*7934SMark.Phalan@Sun.COM krb5_pa_data **out_padata;
1415*7934SMark.Phalan@Sun.COM krb5_preauth_context *context;
1416*7934SMark.Phalan@Sun.COM struct _krb5_preauth_context_module *module;
1417*7934SMark.Phalan@Sun.COM int i, j;
1418*7934SMark.Phalan@Sun.COM int out_pa_list_size = 0;
1419*7934SMark.Phalan@Sun.COM
1420*7934SMark.Phalan@Sun.COM ret = KRB5KRB_ERR_GENERIC;
1421*7934SMark.Phalan@Sun.COM if (kcontext->preauth_context == NULL) {
1422*7934SMark.Phalan@Sun.COM return KRB5KRB_ERR_GENERIC;
1423*7934SMark.Phalan@Sun.COM }
1424*7934SMark.Phalan@Sun.COM context = kcontext->preauth_context;
1425*7934SMark.Phalan@Sun.COM if (context == NULL) {
1426*7934SMark.Phalan@Sun.COM return KRB5KRB_ERR_GENERIC;
1427*7934SMark.Phalan@Sun.COM }
1428*7934SMark.Phalan@Sun.COM
1429*7934SMark.Phalan@Sun.COM for (i = 0; padata[i] != NULL && padata[i]->pa_type != 0; i++) {
1430*7934SMark.Phalan@Sun.COM out_padata = NULL;
1431*7934SMark.Phalan@Sun.COM for (j = 0; j < context->n_modules; j++) {
1432*7934SMark.Phalan@Sun.COM module = &context->modules[j];
1433*7934SMark.Phalan@Sun.COM if (module->pa_type != padata[i]->pa_type) {
1434*7934SMark.Phalan@Sun.COM continue;
1435*7934SMark.Phalan@Sun.COM }
1436*7934SMark.Phalan@Sun.COM if (module->client_tryagain == NULL) {
1437*7934SMark.Phalan@Sun.COM continue;
1438*7934SMark.Phalan@Sun.COM }
1439*7934SMark.Phalan@Sun.COM if ((*module->client_tryagain)(kcontext,
1440*7934SMark.Phalan@Sun.COM module->plugin_context,
1441*7934SMark.Phalan@Sun.COM *module->request_context_pp,
1442*7934SMark.Phalan@Sun.COM (krb5_get_init_creds_opt *)opte,
1443*7934SMark.Phalan@Sun.COM client_data_proc,
1444*7934SMark.Phalan@Sun.COM get_data_rock,
1445*7934SMark.Phalan@Sun.COM request,
1446*7934SMark.Phalan@Sun.COM encoded_request_body,
1447*7934SMark.Phalan@Sun.COM encoded_previous_request,
1448*7934SMark.Phalan@Sun.COM padata[i],
1449*7934SMark.Phalan@Sun.COM err_reply,
1450*7934SMark.Phalan@Sun.COM prompter, prompter_data,
1451*7934SMark.Phalan@Sun.COM gak_fct, gak_data, salt, s2kparams,
1452*7934SMark.Phalan@Sun.COM as_key,
1453*7934SMark.Phalan@Sun.COM &out_padata) == 0) {
1454*7934SMark.Phalan@Sun.COM if (out_padata != NULL) {
1455*7934SMark.Phalan@Sun.COM int k;
1456*7934SMark.Phalan@Sun.COM for (k = 0; out_padata[k] != NULL; k++);
1457*7934SMark.Phalan@Sun.COM grow_pa_list(return_padata, &out_pa_list_size,
1458*7934SMark.Phalan@Sun.COM out_padata, k);
1459*7934SMark.Phalan@Sun.COM free(out_padata);
1460*7934SMark.Phalan@Sun.COM return 0;
1461*7934SMark.Phalan@Sun.COM }
1462*7934SMark.Phalan@Sun.COM }
1463*7934SMark.Phalan@Sun.COM }
1464*7934SMark.Phalan@Sun.COM }
1465*7934SMark.Phalan@Sun.COM return ret;
1466*7934SMark.Phalan@Sun.COM }
1467*7934SMark.Phalan@Sun.COM
1468*7934SMark.Phalan@Sun.COM krb5_error_code KRB5_CALLCONV
krb5_do_preauth(krb5_context context,krb5_kdc_req * request,krb5_data * encoded_request_body,krb5_data * encoded_previous_request,krb5_pa_data ** in_padata,krb5_pa_data *** out_padata,krb5_data * salt,krb5_data * s2kparams,krb5_enctype * etype,krb5_keyblock * as_key,krb5_prompter_fct prompter,void * prompter_data,krb5_gic_get_as_key_fct gak_fct,void * gak_data,krb5_preauth_client_rock * get_data_rock,krb5_gic_opt_ext * opte)14690Sstevel@tonic-gate krb5_do_preauth(krb5_context context,
14700Sstevel@tonic-gate krb5_kdc_req *request,
1471*7934SMark.Phalan@Sun.COM krb5_data *encoded_request_body,
1472*7934SMark.Phalan@Sun.COM krb5_data *encoded_previous_request,
14730Sstevel@tonic-gate krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
14740Sstevel@tonic-gate krb5_data *salt, krb5_data *s2kparams,
14750Sstevel@tonic-gate krb5_enctype *etype,
14760Sstevel@tonic-gate krb5_keyblock *as_key,
14770Sstevel@tonic-gate krb5_prompter_fct prompter, void *prompter_data,
1478*7934SMark.Phalan@Sun.COM krb5_gic_get_as_key_fct gak_fct, void *gak_data,
1479*7934SMark.Phalan@Sun.COM krb5_preauth_client_rock *get_data_rock,
1480*7934SMark.Phalan@Sun.COM krb5_gic_opt_ext *opte)
14810Sstevel@tonic-gate {
14820Sstevel@tonic-gate int h, i, j, out_pa_list_size;
14830Sstevel@tonic-gate int seen_etype_info2 = 0;
14840Sstevel@tonic-gate krb5_pa_data *out_pa = NULL, **out_pa_list = NULL;
14850Sstevel@tonic-gate krb5_data scratch;
14860Sstevel@tonic-gate krb5_etype_info etype_info = NULL;
14870Sstevel@tonic-gate krb5_error_code ret;
14880Sstevel@tonic-gate static const int paorder[] = { PA_INFO, PA_REAL };
14890Sstevel@tonic-gate int realdone;
14900Sstevel@tonic-gate
1491*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
14920Sstevel@tonic-gate KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() start");
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate if (in_padata == NULL) {
14950Sstevel@tonic-gate *out_padata = NULL;
14960Sstevel@tonic-gate return(0);
14970Sstevel@tonic-gate }
14980Sstevel@tonic-gate
14990Sstevel@tonic-gate #ifdef DEBUG
1500*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
15010Sstevel@tonic-gate if (salt && salt->data && salt->length > 0) {
15020Sstevel@tonic-gate fprintf (stderr, "salt len=%d", salt->length);
1503*7934SMark.Phalan@Sun.COM if ((int) salt->length > 0)
15040Sstevel@tonic-gate fprintf (stderr, " '%*s'", salt->length, salt->data);
15050Sstevel@tonic-gate fprintf (stderr, "; preauth data types:");
15060Sstevel@tonic-gate for (i = 0; in_padata[i]; i++) {
15070Sstevel@tonic-gate fprintf (stderr, " %d", in_padata[i]->pa_type);
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate fprintf (stderr, "\n");
15100Sstevel@tonic-gate }
15110Sstevel@tonic-gate #endif
15120Sstevel@tonic-gate
15130Sstevel@tonic-gate out_pa_list = NULL;
15140Sstevel@tonic-gate out_pa_list_size = 0;
15150Sstevel@tonic-gate
15160Sstevel@tonic-gate /* first do all the informational preauths, then the first real one */
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) {
15190Sstevel@tonic-gate realdone = 0;
15200Sstevel@tonic-gate for (i=0; in_padata[i] && !realdone; i++) {
15210Sstevel@tonic-gate int k, l, etype_found, valid_etype_found;
15220Sstevel@tonic-gate /*
15230Sstevel@tonic-gate * This is really gross, but is necessary to prevent
1524*7934SMark.Phalan@Sun.COM * lossage when talking to a 1.0.x KDC, which returns an
15250Sstevel@tonic-gate * erroneous PA-PW-SALT when it returns a KRB-ERROR
15260Sstevel@tonic-gate * requiring additional preauth.
15270Sstevel@tonic-gate */
15280Sstevel@tonic-gate switch (in_padata[i]->pa_type) {
15290Sstevel@tonic-gate case KRB5_PADATA_ETYPE_INFO:
15300Sstevel@tonic-gate case KRB5_PADATA_ETYPE_INFO2:
15310Sstevel@tonic-gate {
15320Sstevel@tonic-gate krb5_preauthtype pa_type = in_padata[i]->pa_type;
15330Sstevel@tonic-gate if (etype_info) {
15340Sstevel@tonic-gate if (seen_etype_info2 || pa_type != KRB5_PADATA_ETYPE_INFO2)
15350Sstevel@tonic-gate continue;
15360Sstevel@tonic-gate if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1537*7934SMark.Phalan@Sun.COM krb5_free_etype_info( context, etype_info);
15380Sstevel@tonic-gate etype_info = NULL;
1539*7934SMark.Phalan@Sun.COM }
15400Sstevel@tonic-gate }
15410Sstevel@tonic-gate
15420Sstevel@tonic-gate scratch.length = in_padata[i]->length;
15430Sstevel@tonic-gate scratch.data = (char *) in_padata[i]->contents;
15440Sstevel@tonic-gate if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1545*7934SMark.Phalan@Sun.COM seen_etype_info2++;
1546*7934SMark.Phalan@Sun.COM ret = decode_krb5_etype_info2(&scratch, &etype_info);
15470Sstevel@tonic-gate }
15480Sstevel@tonic-gate else ret = decode_krb5_etype_info(&scratch, &etype_info);
15490Sstevel@tonic-gate if (ret) {
1550*7934SMark.Phalan@Sun.COM ret = 0; /*Ignore error and etype_info element*/
1551*7934SMark.Phalan@Sun.COM if (etype_info)
1552*7934SMark.Phalan@Sun.COM krb5_free_etype_info( context, etype_info);
1553*7934SMark.Phalan@Sun.COM etype_info = NULL;
1554*7934SMark.Phalan@Sun.COM continue;
15550Sstevel@tonic-gate }
15560Sstevel@tonic-gate if (etype_info[0] == NULL) {
15570Sstevel@tonic-gate krb5_free_etype_info(context, etype_info);
15580Sstevel@tonic-gate etype_info = NULL;
15590Sstevel@tonic-gate break;
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate /*
15620Sstevel@tonic-gate * Select first etype in our request which is also in
15630Sstevel@tonic-gate * etype-info (preferring client request ktype order).
15640Sstevel@tonic-gate */
15650Sstevel@tonic-gate for (etype_found = 0, valid_etype_found = 0, k = 0;
1566*7934SMark.Phalan@Sun.COM !etype_found && k < request->nktypes; k++) {
15670Sstevel@tonic-gate for (l = 0; etype_info[l]; l++) {
15680Sstevel@tonic-gate if (etype_info[l]->etype == request->ktype[k]) {
15690Sstevel@tonic-gate etype_found++;
15700Sstevel@tonic-gate break;
15710Sstevel@tonic-gate }
15720Sstevel@tonic-gate /* check if program has support for this etype for more
15730Sstevel@tonic-gate * precise error reporting.
15740Sstevel@tonic-gate */
15750Sstevel@tonic-gate if (valid_enctype(etype_info[l]->etype))
15760Sstevel@tonic-gate valid_etype_found++;
15770Sstevel@tonic-gate }
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate if (!etype_found) {
1580*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
15810Sstevel@tonic-gate KRB5_LOG(KRB5_ERR, "error !etype_found, "
15820Sstevel@tonic-gate "valid_etype_found = %d",
15830Sstevel@tonic-gate valid_etype_found);
1584*7934SMark.Phalan@Sun.COM if (valid_etype_found) {
15850Sstevel@tonic-gate /* supported enctype but not requested */
1586*7934SMark.Phalan@Sun.COM ret = KRB5_CONFIG_ETYPE_NOSUPP;
1587*7934SMark.Phalan@Sun.COM goto cleanup;
1588*7934SMark.Phalan@Sun.COM }
1589*7934SMark.Phalan@Sun.COM else {
1590*7934SMark.Phalan@Sun.COM /* unsupported enctype */
1591*7934SMark.Phalan@Sun.COM ret = KRB5_PROG_ETYPE_NOSUPP;
1592*7934SMark.Phalan@Sun.COM goto cleanup;
1593*7934SMark.Phalan@Sun.COM }
15940Sstevel@tonic-gate
15950Sstevel@tonic-gate }
15960Sstevel@tonic-gate scratch.data = (char *) etype_info[l]->salt;
15970Sstevel@tonic-gate scratch.length = etype_info[l]->length;
15980Sstevel@tonic-gate krb5_free_data_contents(context, salt);
1599*7934SMark.Phalan@Sun.COM if (scratch.length == KRB5_ETYPE_NO_SALT)
16000Sstevel@tonic-gate salt->data = NULL;
16010Sstevel@tonic-gate else
1602*7934SMark.Phalan@Sun.COM if ((ret = krb5int_copy_data_contents( context, &scratch, salt)) != 0)
1603*7934SMark.Phalan@Sun.COM goto cleanup;
16040Sstevel@tonic-gate *etype = etype_info[l]->etype;
16050Sstevel@tonic-gate krb5_free_data_contents(context, s2kparams);
16060Sstevel@tonic-gate if ((ret = krb5int_copy_data_contents(context,
1607*7934SMark.Phalan@Sun.COM &etype_info[l]->s2kparams,
1608*7934SMark.Phalan@Sun.COM s2kparams)) != 0)
16090Sstevel@tonic-gate goto cleanup;
1610*7934SMark.Phalan@Sun.COM #ifdef DEBUG
1611*7934SMark.Phalan@Sun.COM for (j = 0; etype_info[j]; j++) {
1612*7934SMark.Phalan@Sun.COM krb5_etype_info_entry *e = etype_info[j];
1613*7934SMark.Phalan@Sun.COM fprintf (stderr, "etype info %d: etype %d salt len=%d",
1614*7934SMark.Phalan@Sun.COM j, e->etype, e->length);
1615*7934SMark.Phalan@Sun.COM if (e->length > 0 && e->length != KRB5_ETYPE_NO_SALT)
1616*7934SMark.Phalan@Sun.COM fprintf (stderr, " '%.*s'", e->length, e->salt);
1617*7934SMark.Phalan@Sun.COM fprintf (stderr, "\n");
1618*7934SMark.Phalan@Sun.COM }
1619*7934SMark.Phalan@Sun.COM #endif
16200Sstevel@tonic-gate break;
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate case KRB5_PADATA_PW_SALT:
16230Sstevel@tonic-gate case KRB5_PADATA_AFS3_SALT:
16240Sstevel@tonic-gate if (etype_info)
16250Sstevel@tonic-gate continue;
16260Sstevel@tonic-gate break;
16270Sstevel@tonic-gate default:
16280Sstevel@tonic-gate ;
16290Sstevel@tonic-gate }
1630*7934SMark.Phalan@Sun.COM /* Try the internally-provided preauth type list. */
1631*7934SMark.Phalan@Sun.COM if (!realdone) for (j=0; pa_types[j].type >= 0; j++) {
16320Sstevel@tonic-gate if ((in_padata[i]->pa_type == pa_types[j].type) &&
16330Sstevel@tonic-gate (pa_types[j].flags & paorder[h])) {
1634*7934SMark.Phalan@Sun.COM #ifdef DEBUG
1635*7934SMark.Phalan@Sun.COM fprintf (stderr, "calling internal function for pa_type "
1636*7934SMark.Phalan@Sun.COM "%d, flag %d\n", pa_types[j].type, paorder[h]);
1637*7934SMark.Phalan@Sun.COM #endif
16380Sstevel@tonic-gate out_pa = NULL;
16390Sstevel@tonic-gate
1640781Sgtb if ((ret = ((*pa_types[j].fct)(context, request,
1641*7934SMark.Phalan@Sun.COM in_padata[i], &out_pa,
1642*7934SMark.Phalan@Sun.COM salt, s2kparams, etype, as_key,
1643*7934SMark.Phalan@Sun.COM prompter, prompter_data,
1644*7934SMark.Phalan@Sun.COM gak_fct, gak_data)))) {
1645*7934SMark.Phalan@Sun.COM goto cleanup;
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate
1648*7934SMark.Phalan@Sun.COM ret = grow_pa_list(&out_pa_list, &out_pa_list_size,
1649*7934SMark.Phalan@Sun.COM &out_pa, 1);
1650*7934SMark.Phalan@Sun.COM if (ret != 0) {
1651*7934SMark.Phalan@Sun.COM goto cleanup;
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate if (paorder[h] == PA_REAL)
16540Sstevel@tonic-gate realdone = 1;
16550Sstevel@tonic-gate }
16560Sstevel@tonic-gate }
1657*7934SMark.Phalan@Sun.COM
1658*7934SMark.Phalan@Sun.COM /* Try to use plugins now. */
1659*7934SMark.Phalan@Sun.COM if (!realdone) {
1660*7934SMark.Phalan@Sun.COM krb5_init_preauth_context(context);
1661*7934SMark.Phalan@Sun.COM if (context->preauth_context != NULL) {
1662*7934SMark.Phalan@Sun.COM int module_ret, module_flags;
1663*7934SMark.Phalan@Sun.COM #ifdef DEBUG
1664*7934SMark.Phalan@Sun.COM fprintf (stderr, "trying modules for pa_type %d, flag %d\n",
1665*7934SMark.Phalan@Sun.COM in_padata[i]->pa_type, paorder[h]);
1666*7934SMark.Phalan@Sun.COM #endif
1667*7934SMark.Phalan@Sun.COM ret = krb5_run_preauth_plugins(context,
1668*7934SMark.Phalan@Sun.COM paorder[h],
1669*7934SMark.Phalan@Sun.COM request,
1670*7934SMark.Phalan@Sun.COM encoded_request_body,
1671*7934SMark.Phalan@Sun.COM encoded_previous_request,
1672*7934SMark.Phalan@Sun.COM in_padata[i],
1673*7934SMark.Phalan@Sun.COM prompter,
1674*7934SMark.Phalan@Sun.COM prompter_data,
1675*7934SMark.Phalan@Sun.COM gak_fct,
1676*7934SMark.Phalan@Sun.COM salt, s2kparams,
1677*7934SMark.Phalan@Sun.COM gak_data,
1678*7934SMark.Phalan@Sun.COM get_data_rock,
1679*7934SMark.Phalan@Sun.COM as_key,
1680*7934SMark.Phalan@Sun.COM &out_pa_list,
1681*7934SMark.Phalan@Sun.COM &out_pa_list_size,
1682*7934SMark.Phalan@Sun.COM &module_ret,
1683*7934SMark.Phalan@Sun.COM &module_flags,
1684*7934SMark.Phalan@Sun.COM opte);
1685*7934SMark.Phalan@Sun.COM if (ret == 0) {
1686*7934SMark.Phalan@Sun.COM if (module_ret == 0) {
1687*7934SMark.Phalan@Sun.COM if (paorder[h] == PA_REAL) {
1688*7934SMark.Phalan@Sun.COM realdone = 1;
1689*7934SMark.Phalan@Sun.COM }
1690*7934SMark.Phalan@Sun.COM }
1691*7934SMark.Phalan@Sun.COM }
1692*7934SMark.Phalan@Sun.COM }
1693*7934SMark.Phalan@Sun.COM }
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate }
16960Sstevel@tonic-gate
16970Sstevel@tonic-gate *out_padata = out_pa_list;
16980Sstevel@tonic-gate if (etype_info)
1699*7934SMark.Phalan@Sun.COM krb5_free_etype_info(context, etype_info);
1700*7934SMark.Phalan@Sun.COM
1701*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
17020Sstevel@tonic-gate KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() end");
17030Sstevel@tonic-gate return(0);
1704*7934SMark.Phalan@Sun.COM cleanup:
17050Sstevel@tonic-gate if (out_pa_list) {
1706*7934SMark.Phalan@Sun.COM out_pa_list[out_pa_list_size++] = NULL;
1707*7934SMark.Phalan@Sun.COM krb5_free_pa_data(context, out_pa_list);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate if (etype_info)
1710*7934SMark.Phalan@Sun.COM krb5_free_etype_info(context, etype_info);
17110Sstevel@tonic-gate
1712*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
17130Sstevel@tonic-gate KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() end");
17140Sstevel@tonic-gate return (ret);
17150Sstevel@tonic-gate }
1716