xref: /onnv-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/preauth2.c (revision 7934:6aeeafc994de)
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