17c478bd9Sstevel@tonic-gate /*
2159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
8505d05c7Sgtb  * Copyright 1995, 2003 by the Massachusetts Institute of Technology.  All
97c478bd9Sstevel@tonic-gate  * Rights Reserved.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
127c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
137c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
147c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
177c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
187c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
197c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
207c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
217c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
227c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
237c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
247c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
257c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
267c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
277c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
287c478bd9Sstevel@tonic-gate  * or implied warranty.
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * This file contains routines for establishing, verifying, and any other
34*55fea89dSDan Cross  * necessary functions, for utilizing the pre-authentication field of the
357c478bd9Sstevel@tonic-gate  * kerberos kdc request, with various hardware/software verification devices.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
38159d09a2SMark Phalan #include "k5-int.h"
39159d09a2SMark Phalan #include "osconf.h"
40159d09a2SMark Phalan #include <preauth_plugin.h>
41159d09a2SMark Phalan #include "int-proto.h"
42159d09a2SMark Phalan 
43159d09a2SMark Phalan #if !defined(_WIN32)
44159d09a2SMark Phalan #include <unistd.h>
45159d09a2SMark Phalan #endif
46159d09a2SMark Phalan 
47159d09a2SMark Phalan #if TARGET_OS_MAC
48159d09a2SMark Phalan static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/preauth", NULL }; /* should be a list */
49159d09a2SMark Phalan #else
50159d09a2SMark Phalan /* Solaris Kerberos */
51159d09a2SMark Phalan static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL };
52159d09a2SMark Phalan #endif
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate typedef krb5_error_code (*pa_function)(krb5_context,
557c478bd9Sstevel@tonic-gate 				       krb5_kdc_req *request,
567c478bd9Sstevel@tonic-gate 				       krb5_pa_data *in_padata,
577c478bd9Sstevel@tonic-gate 				       krb5_pa_data **out_padata,
58159d09a2SMark Phalan 				       krb5_data *salt, krb5_data *s2kparams,
597c478bd9Sstevel@tonic-gate 				       krb5_enctype *etype,
607c478bd9Sstevel@tonic-gate 				       krb5_keyblock *as_key,
617c478bd9Sstevel@tonic-gate 				       krb5_prompter_fct prompter_fct,
627c478bd9Sstevel@tonic-gate 				       void *prompter_data,
637c478bd9Sstevel@tonic-gate 				       krb5_gic_get_as_key_fct gak_fct,
647c478bd9Sstevel@tonic-gate 				       void *gak_data);
65*55fea89dSDan Cross 
667c478bd9Sstevel@tonic-gate typedef struct _pa_types_t {
677c478bd9Sstevel@tonic-gate     krb5_preauthtype type;
687c478bd9Sstevel@tonic-gate     pa_function fct;
697c478bd9Sstevel@tonic-gate     int flags;
707c478bd9Sstevel@tonic-gate } pa_types_t;
717c478bd9Sstevel@tonic-gate 
72159d09a2SMark Phalan /* Create the per-krb5_context context. This means loading the modules
73159d09a2SMark Phalan  * if we haven't done that yet (applications which never obtain initial
74159d09a2SMark Phalan  * credentials should never hit this routine), breaking up the module's
75159d09a2SMark Phalan  * list of support pa_types so that we can iterate over the modules more
76159d09a2SMark Phalan  * easily, and copying over the relevant parts of the module's table. */
77159d09a2SMark Phalan void KRB5_CALLCONV
krb5_init_preauth_context(krb5_context kcontext)78159d09a2SMark Phalan krb5_init_preauth_context(krb5_context kcontext)
79159d09a2SMark Phalan {
80159d09a2SMark Phalan     int n_modules, n_tables, i, j, k;
81159d09a2SMark Phalan     void **tables;
82159d09a2SMark Phalan     struct krb5plugin_preauth_client_ftable_v1 *table;
83159d09a2SMark Phalan     krb5_preauth_context *context = NULL;
84159d09a2SMark Phalan     void *plugin_context;
85159d09a2SMark Phalan     krb5_preauthtype pa_type;
86159d09a2SMark Phalan     void **rcpp;
87159d09a2SMark Phalan 
88159d09a2SMark Phalan     /* Only do this once for each krb5_context */
89159d09a2SMark Phalan     if (kcontext->preauth_context != NULL)
90159d09a2SMark Phalan 	return;
91159d09a2SMark Phalan 
92159d09a2SMark Phalan     /* load the plugins for the current context */
93159d09a2SMark Phalan     if (PLUGIN_DIR_OPEN(&kcontext->preauth_plugins) == 0) {
94159d09a2SMark Phalan 	if (krb5int_open_plugin_dirs(objdirs, NULL,
95159d09a2SMark Phalan 				     &kcontext->preauth_plugins,
96159d09a2SMark Phalan 				     &kcontext->err) != 0) {
97159d09a2SMark Phalan 		return;
98159d09a2SMark Phalan 	}
99159d09a2SMark Phalan     }
100159d09a2SMark Phalan 
101159d09a2SMark Phalan     /* pull out the module function tables for all of the modules */
102159d09a2SMark Phalan     tables = NULL;
103159d09a2SMark Phalan     if (krb5int_get_plugin_dir_data(&kcontext->preauth_plugins,
104159d09a2SMark Phalan 				    "preauthentication_client_1",
105159d09a2SMark Phalan 				    &tables,
106159d09a2SMark Phalan 				    &kcontext->err) != 0) {
107159d09a2SMark Phalan 	return;
108159d09a2SMark Phalan     }
109159d09a2SMark Phalan     if (tables == NULL) {
110159d09a2SMark Phalan 	return;
111159d09a2SMark Phalan     }
112159d09a2SMark Phalan 
113159d09a2SMark Phalan     /* count how many modules we ended up loading, and how many preauth
114159d09a2SMark Phalan      * types we may claim to support as a result */
115159d09a2SMark Phalan     n_modules = 0;
116159d09a2SMark Phalan     for (n_tables = 0;
117159d09a2SMark Phalan          (tables != NULL) && (tables[n_tables] != NULL);
118159d09a2SMark Phalan          n_tables++) {
119159d09a2SMark Phalan 	table = tables[n_tables];
120159d09a2SMark Phalan 	if ((table->pa_type_list != NULL) && (table->process != NULL)) {
121159d09a2SMark Phalan 	    for (j = 0; table->pa_type_list[j] > 0; j++) {
122159d09a2SMark Phalan 		n_modules++;
123159d09a2SMark Phalan 	    }
124159d09a2SMark Phalan 	}
125159d09a2SMark Phalan     }
126159d09a2SMark Phalan 
127159d09a2SMark Phalan     /* allocate the space we need */
128159d09a2SMark Phalan     context = malloc(sizeof(*context));
129159d09a2SMark Phalan     if (context == NULL) {
130159d09a2SMark Phalan 	krb5int_free_plugin_dir_data(tables);
131159d09a2SMark Phalan         return;
132159d09a2SMark Phalan     }
133159d09a2SMark Phalan     context->modules = malloc(sizeof(context->modules[0]) * n_modules);
134159d09a2SMark Phalan     if (context->modules == NULL) {
135159d09a2SMark Phalan 	krb5int_free_plugin_dir_data(tables);
136159d09a2SMark Phalan         free(context);
137159d09a2SMark Phalan         return;
138159d09a2SMark Phalan     }
139159d09a2SMark Phalan     memset(context->modules, 0, sizeof(context->modules[0]) * n_modules);
140159d09a2SMark Phalan     context->n_modules = n_modules;
141159d09a2SMark Phalan 
142159d09a2SMark Phalan     /* fill in the structure */
143159d09a2SMark Phalan     k = 0;
144159d09a2SMark Phalan     for (i = 0; i < n_tables; i++) {
145159d09a2SMark Phalan         table = tables[i];
146159d09a2SMark Phalan         if ((table->pa_type_list != NULL) && (table->process != NULL)) {
147159d09a2SMark Phalan 	    plugin_context = NULL;
148159d09a2SMark Phalan 	    if ((table->init != NULL) &&
149159d09a2SMark Phalan 		((*table->init)(kcontext, &plugin_context) != 0)) {
150159d09a2SMark Phalan #ifdef DEBUG
151159d09a2SMark Phalan 		    fprintf (stderr, "init err, skipping module \"%s\"\n",
152159d09a2SMark Phalan 			     table->name);
153159d09a2SMark Phalan #endif
154159d09a2SMark Phalan 		    continue;
155159d09a2SMark Phalan 	    }
156159d09a2SMark Phalan 
157159d09a2SMark Phalan 	    rcpp = NULL;
158159d09a2SMark Phalan 	    for (j = 0; table->pa_type_list[j] > 0; j++) {
159159d09a2SMark Phalan 		pa_type = table->pa_type_list[j];
160159d09a2SMark Phalan 		context->modules[k].pa_type = pa_type;
161159d09a2SMark Phalan 		context->modules[k].enctypes = table->enctype_list;
162159d09a2SMark Phalan 		context->modules[k].plugin_context = plugin_context;
163159d09a2SMark Phalan 		/* Only call client_fini once per plugin */
164159d09a2SMark Phalan 		if (j == 0)
165159d09a2SMark Phalan 		    context->modules[k].client_fini = table->fini;
166159d09a2SMark Phalan 		else
167159d09a2SMark Phalan 		    context->modules[k].client_fini = NULL;
168159d09a2SMark Phalan 		context->modules[k].ftable = table;
169159d09a2SMark Phalan 		context->modules[k].name = table->name;
170159d09a2SMark Phalan 		context->modules[k].flags = (*table->flags)(kcontext, pa_type);
171159d09a2SMark Phalan 		context->modules[k].use_count = 0;
172159d09a2SMark Phalan 		context->modules[k].client_process = table->process;
173159d09a2SMark Phalan 		context->modules[k].client_tryagain = table->tryagain;
174159d09a2SMark Phalan 		if (j == 0)
175159d09a2SMark Phalan 		    context->modules[k].client_supply_gic_opts = table->gic_opts;
176159d09a2SMark Phalan 		else
177159d09a2SMark Phalan 		    context->modules[k].client_supply_gic_opts = NULL;
178159d09a2SMark Phalan 		context->modules[k].request_context = NULL;
179159d09a2SMark Phalan 		/*
180159d09a2SMark Phalan 		 * Only call request_init and request_fini once per plugin.
181159d09a2SMark Phalan 		 * Only the first module within each plugin will ever
182159d09a2SMark Phalan 		 * have request_context filled in.  Every module within
183159d09a2SMark Phalan 		 * the plugin will have its request_context_pp pointing
184159d09a2SMark Phalan 		 * to that entry's request_context.  That way all the
185159d09a2SMark Phalan 		 * modules within the plugin share the same request_context
186159d09a2SMark Phalan 		 */
187159d09a2SMark Phalan 		if (j == 0) {
188159d09a2SMark Phalan 		    context->modules[k].client_req_init = table->request_init;
189159d09a2SMark Phalan 		    context->modules[k].client_req_fini = table->request_fini;
190159d09a2SMark Phalan 		    rcpp = &context->modules[k].request_context;
191159d09a2SMark Phalan 		} else {
192159d09a2SMark Phalan 		    context->modules[k].client_req_init = NULL;
193159d09a2SMark Phalan 		    context->modules[k].client_req_fini = NULL;
194159d09a2SMark Phalan 		}
195159d09a2SMark Phalan 		context->modules[k].request_context_pp = rcpp;
196159d09a2SMark Phalan #ifdef DEBUG
197159d09a2SMark Phalan 		fprintf (stderr, "init module \"%s\", pa_type %d, flag %d\n",
198159d09a2SMark Phalan 			 context->modules[k].name,
199159d09a2SMark Phalan 			 context->modules[k].pa_type,
200159d09a2SMark Phalan 			 context->modules[k].flags);
201159d09a2SMark Phalan #endif
202159d09a2SMark Phalan 		k++;
203159d09a2SMark Phalan 	    }
204159d09a2SMark Phalan 	}
205159d09a2SMark Phalan     }
206159d09a2SMark Phalan     krb5int_free_plugin_dir_data(tables);
207159d09a2SMark Phalan 
208159d09a2SMark Phalan     /* return the result */
209159d09a2SMark Phalan     kcontext->preauth_context = context;
210159d09a2SMark Phalan }
211159d09a2SMark Phalan 
212159d09a2SMark Phalan /* Zero the use counts for the modules herein.  Usually used before we
213159d09a2SMark Phalan  * start processing any data from the server, at which point every module
214159d09a2SMark Phalan  * will again be able to take a crack at whatever the server sent. */
215159d09a2SMark Phalan void KRB5_CALLCONV
krb5_clear_preauth_context_use_counts(krb5_context context)216159d09a2SMark Phalan krb5_clear_preauth_context_use_counts(krb5_context context)
217159d09a2SMark Phalan {
218159d09a2SMark Phalan     int i;
219159d09a2SMark Phalan     if (context->preauth_context != NULL) {
220159d09a2SMark Phalan 	for (i = 0; i < context->preauth_context->n_modules; i++) {
221159d09a2SMark Phalan 	    context->preauth_context->modules[i].use_count = 0;
222159d09a2SMark Phalan 	}
223159d09a2SMark Phalan     }
224159d09a2SMark Phalan }
225159d09a2SMark Phalan 
226159d09a2SMark Phalan /*
227159d09a2SMark Phalan  * Give all the preauth plugins a look at the preauth option which
228159d09a2SMark Phalan  * has just been set
229159d09a2SMark Phalan  */
230159d09a2SMark Phalan krb5_error_code
krb5_preauth_supply_preauth_data(krb5_context context,krb5_gic_opt_ext * opte,const char * attr,const char * value)231159d09a2SMark Phalan krb5_preauth_supply_preauth_data(krb5_context context,
232159d09a2SMark Phalan 				 krb5_gic_opt_ext *opte,
233159d09a2SMark Phalan 				 const char *attr,
234159d09a2SMark Phalan 				 const char *value)
235159d09a2SMark Phalan {
236159d09a2SMark Phalan     krb5_error_code retval;
237159d09a2SMark Phalan     int i;
238159d09a2SMark Phalan     void *pctx;
239159d09a2SMark Phalan     const char *emsg = NULL;
240159d09a2SMark Phalan 
241159d09a2SMark Phalan     if (context->preauth_context == NULL)
242159d09a2SMark Phalan 	krb5_init_preauth_context(context);
243159d09a2SMark Phalan     if (context->preauth_context == NULL) {
244159d09a2SMark Phalan 	retval = EINVAL;
245159d09a2SMark Phalan 	krb5int_set_error(&context->err, retval,
246159d09a2SMark Phalan 		"krb5_preauth_supply_preauth_data: "
247159d09a2SMark Phalan 		"Unable to initialize preauth context");
248159d09a2SMark Phalan 	return retval;
249159d09a2SMark Phalan     }
250159d09a2SMark Phalan 
251159d09a2SMark Phalan     /*
252159d09a2SMark Phalan      * Go down the list of preauth modules, and supply them with the
253159d09a2SMark Phalan      * attribute/value pair.
254159d09a2SMark Phalan      */
255159d09a2SMark Phalan     for (i = 0; i < context->preauth_context->n_modules; i++) {
256159d09a2SMark Phalan 	if (context->preauth_context->modules[i].client_supply_gic_opts == NULL)
257159d09a2SMark Phalan 	    continue;
258159d09a2SMark Phalan 	pctx = context->preauth_context->modules[i].plugin_context;
259159d09a2SMark Phalan 	retval = (*context->preauth_context->modules[i].client_supply_gic_opts)
260159d09a2SMark Phalan 				(context, pctx,
261*55fea89dSDan Cross 				 (krb5_get_init_creds_opt *)opte, attr, value);
262159d09a2SMark Phalan 	if (retval) {
263159d09a2SMark Phalan 	    emsg = krb5_get_error_message(context, retval);
264159d09a2SMark Phalan 	    krb5int_set_error(&context->err, retval, "Preauth plugin %s: %s",
265159d09a2SMark Phalan 			      context->preauth_context->modules[i].name, emsg);
266159d09a2SMark Phalan 	    break;
267159d09a2SMark Phalan 	}
268159d09a2SMark Phalan     }
269159d09a2SMark Phalan     return retval;
270159d09a2SMark Phalan }
271159d09a2SMark Phalan 
272159d09a2SMark Phalan /* Free the per-krb5_context preauth_context. This means clearing any
273159d09a2SMark Phalan  * plugin-specific context which may have been created, and then
274159d09a2SMark Phalan  * freeing the context itself. */
275159d09a2SMark Phalan void KRB5_CALLCONV
krb5_free_preauth_context(krb5_context context)276159d09a2SMark Phalan krb5_free_preauth_context(krb5_context context)
277159d09a2SMark Phalan {
278159d09a2SMark Phalan     int i;
279159d09a2SMark Phalan     void *pctx;
280159d09a2SMark Phalan     if (context->preauth_context != NULL) {
281159d09a2SMark Phalan 	for (i = 0; i < context->preauth_context->n_modules; i++) {
282159d09a2SMark Phalan 	    pctx = context->preauth_context->modules[i].plugin_context;
283159d09a2SMark Phalan 	    if (context->preauth_context->modules[i].client_fini != NULL) {
284159d09a2SMark Phalan 	        (*context->preauth_context->modules[i].client_fini)(context, pctx);
285159d09a2SMark Phalan 	    }
286159d09a2SMark Phalan 	    memset(&context->preauth_context->modules[i], 0,
287159d09a2SMark Phalan 	           sizeof(context->preauth_context->modules[i]));
288159d09a2SMark Phalan 	}
289159d09a2SMark Phalan 	if (context->preauth_context->modules != NULL) {
290159d09a2SMark Phalan 	    free(context->preauth_context->modules);
291159d09a2SMark Phalan 	    context->preauth_context->modules = NULL;
292159d09a2SMark Phalan 	}
293159d09a2SMark Phalan 	free(context->preauth_context);
294159d09a2SMark Phalan 	context->preauth_context = NULL;
295159d09a2SMark Phalan     }
296159d09a2SMark Phalan }
297159d09a2SMark Phalan 
298159d09a2SMark Phalan /* Initialize the per-AS-REQ context. This means calling the client_req_init
299159d09a2SMark Phalan  * function to give the plugin a chance to allocate a per-request context. */
300159d09a2SMark Phalan void KRB5_CALLCONV
krb5_preauth_request_context_init(krb5_context context)301159d09a2SMark Phalan krb5_preauth_request_context_init(krb5_context context)
302159d09a2SMark Phalan {
303159d09a2SMark Phalan     int i;
304159d09a2SMark Phalan     void *rctx, *pctx;
305159d09a2SMark Phalan 
306159d09a2SMark Phalan     /* Limit this to only one attempt per context? */
307159d09a2SMark Phalan     if (context->preauth_context == NULL)
308159d09a2SMark Phalan 	krb5_init_preauth_context(context);
309159d09a2SMark Phalan     if (context->preauth_context != NULL) {
310159d09a2SMark Phalan 	for (i = 0; i < context->preauth_context->n_modules; i++) {
311159d09a2SMark Phalan 	    pctx = context->preauth_context->modules[i].plugin_context;
312159d09a2SMark Phalan 	    if (context->preauth_context->modules[i].client_req_init != NULL) {
313159d09a2SMark Phalan 		rctx = context->preauth_context->modules[i].request_context_pp;
314159d09a2SMark Phalan 		(*context->preauth_context->modules[i].client_req_init) (context, pctx, rctx);
315159d09a2SMark Phalan 	    }
316159d09a2SMark Phalan 	}
317159d09a2SMark Phalan     }
318159d09a2SMark Phalan }
319159d09a2SMark Phalan 
320159d09a2SMark Phalan /* Free the per-AS-REQ context. This means clearing any request-specific
321159d09a2SMark Phalan  * context which the plugin may have created. */
322159d09a2SMark Phalan void KRB5_CALLCONV
krb5_preauth_request_context_fini(krb5_context context)323159d09a2SMark Phalan krb5_preauth_request_context_fini(krb5_context context)
324159d09a2SMark Phalan {
325159d09a2SMark Phalan     int i;
326159d09a2SMark Phalan     void *rctx, *pctx;
327159d09a2SMark Phalan     if (context->preauth_context != NULL) {
328159d09a2SMark Phalan 	for (i = 0; i < context->preauth_context->n_modules; i++) {
329159d09a2SMark Phalan 	    pctx = context->preauth_context->modules[i].plugin_context;
330159d09a2SMark Phalan 	    rctx = context->preauth_context->modules[i].request_context;
331159d09a2SMark Phalan 	    if (rctx != NULL) {
332159d09a2SMark Phalan 		if (context->preauth_context->modules[i].client_req_fini != NULL) {
333159d09a2SMark Phalan 		    (*context->preauth_context->modules[i].client_req_fini)(context, pctx, rctx);
334159d09a2SMark Phalan 		}
335159d09a2SMark Phalan 		context->preauth_context->modules[i].request_context = NULL;
336159d09a2SMark Phalan 	    }
337159d09a2SMark Phalan 	}
338159d09a2SMark Phalan     }
339159d09a2SMark Phalan }
340159d09a2SMark Phalan 
341159d09a2SMark Phalan /* Add the named encryption type to the existing list of ktypes. */
342159d09a2SMark Phalan static void
grow_ktypes(krb5_enctype ** out_ktypes,int * out_nktypes,krb5_enctype ktype)343159d09a2SMark Phalan grow_ktypes(krb5_enctype **out_ktypes, int *out_nktypes, krb5_enctype ktype)
344159d09a2SMark Phalan {
345159d09a2SMark Phalan     int i;
346159d09a2SMark Phalan     krb5_enctype *ktypes;
347159d09a2SMark Phalan     for (i = 0; i < *out_nktypes; i++) {
348159d09a2SMark Phalan 	if ((*out_ktypes)[i] == ktype)
349159d09a2SMark Phalan 	    return;
350159d09a2SMark Phalan     }
351159d09a2SMark Phalan     ktypes = malloc((*out_nktypes + 2) * sizeof(ktype));
352159d09a2SMark Phalan     if (ktypes) {
353159d09a2SMark Phalan 	for (i = 0; i < *out_nktypes; i++)
354159d09a2SMark Phalan 	    ktypes[i] = (*out_ktypes)[i];
355159d09a2SMark Phalan 	ktypes[i++] = ktype;
356159d09a2SMark Phalan 	ktypes[i] = 0;
357159d09a2SMark Phalan 	free(*out_ktypes);
358159d09a2SMark Phalan 	*out_ktypes = ktypes;
359159d09a2SMark Phalan 	*out_nktypes = i;
360159d09a2SMark Phalan     }
361159d09a2SMark Phalan }
362159d09a2SMark Phalan 
363159d09a2SMark Phalan /*
364159d09a2SMark Phalan  * Add the given list of pa_data items to the existing list of items.
365159d09a2SMark Phalan  * Factored out here to make reading the do_preauth logic easier to read.
366159d09a2SMark Phalan  */
367159d09a2SMark Phalan static int
grow_pa_list(krb5_pa_data *** out_pa_list,int * out_pa_list_size,krb5_pa_data ** addition,int num_addition)368159d09a2SMark Phalan grow_pa_list(krb5_pa_data ***out_pa_list, int *out_pa_list_size,
369159d09a2SMark Phalan 	     krb5_pa_data **addition, int num_addition)
370159d09a2SMark Phalan {
371159d09a2SMark Phalan     krb5_pa_data **pa_list;
372159d09a2SMark Phalan     int i, j;
373159d09a2SMark Phalan 
374159d09a2SMark Phalan     if (out_pa_list == NULL || addition == NULL) {
375159d09a2SMark Phalan 	return EINVAL;
376159d09a2SMark Phalan     }
377159d09a2SMark Phalan 
378159d09a2SMark Phalan     if (*out_pa_list == NULL) {
379159d09a2SMark Phalan 	/* Allocate room for the new additions and a NULL terminator. */
380159d09a2SMark Phalan 	pa_list = malloc((num_addition + 1) * sizeof(krb5_pa_data *));
381159d09a2SMark Phalan 	if (pa_list == NULL)
382159d09a2SMark Phalan 	    return ENOMEM;
383159d09a2SMark Phalan 	for (i = 0; i < num_addition; i++)
384159d09a2SMark Phalan 	    pa_list[i] = addition[i];
385159d09a2SMark Phalan 	pa_list[i] = NULL;
386159d09a2SMark Phalan 	*out_pa_list = pa_list;
387159d09a2SMark Phalan 	*out_pa_list_size = num_addition;
388159d09a2SMark Phalan     } else {
389159d09a2SMark Phalan 	/*
390159d09a2SMark Phalan 	 * Allocate room for the existing entries plus
391159d09a2SMark Phalan 	 * the new additions and a NULL terminator.
392159d09a2SMark Phalan 	 */
393159d09a2SMark Phalan 	pa_list = malloc((*out_pa_list_size + num_addition + 1)
394159d09a2SMark Phalan 						* sizeof(krb5_pa_data *));
395159d09a2SMark Phalan 	if (pa_list == NULL)
396159d09a2SMark Phalan 	    return ENOMEM;
397159d09a2SMark Phalan 	for (i = 0; i < *out_pa_list_size; i++)
398159d09a2SMark Phalan 	    pa_list[i] = (*out_pa_list)[i];
399159d09a2SMark Phalan 	for (j = 0; j < num_addition;)
400159d09a2SMark Phalan 	    pa_list[i++] = addition[j++];
401159d09a2SMark Phalan 	pa_list[i] = NULL;
402159d09a2SMark Phalan 	free(*out_pa_list);
403159d09a2SMark Phalan 	*out_pa_list = pa_list;
404159d09a2SMark Phalan 	*out_pa_list_size = i;
405159d09a2SMark Phalan     }
406159d09a2SMark Phalan     return 0;
407159d09a2SMark Phalan }
408159d09a2SMark Phalan 
409159d09a2SMark Phalan /*
410159d09a2SMark Phalan  * Retrieve a specific piece of information required by the plugin and
411159d09a2SMark Phalan  * return it in a new krb5_data item.  There are separate request_types
412159d09a2SMark Phalan  * to obtain the data and free it.
413159d09a2SMark Phalan  *
414159d09a2SMark Phalan  * This may require massaging data into a contrived format, but it will
415159d09a2SMark Phalan  * hopefully keep us from having to reveal library-internal functions
416159d09a2SMark Phalan  * or data to the plugin modules.
417159d09a2SMark Phalan  */
418159d09a2SMark Phalan 
419159d09a2SMark Phalan static krb5_error_code
client_data_proc(krb5_context kcontext,krb5_preauth_client_rock * rock,krb5_int32 request_type,krb5_data ** retdata)420159d09a2SMark Phalan client_data_proc(krb5_context kcontext,
421159d09a2SMark Phalan 		 krb5_preauth_client_rock *rock,
422159d09a2SMark Phalan 		 krb5_int32 request_type,
423159d09a2SMark Phalan 		 krb5_data **retdata)
424159d09a2SMark Phalan {
425159d09a2SMark Phalan     krb5_data *ret;
426159d09a2SMark Phalan     char *data;
427159d09a2SMark Phalan 
428159d09a2SMark Phalan     if (rock->magic != CLIENT_ROCK_MAGIC)
429159d09a2SMark Phalan 	return EINVAL;
430159d09a2SMark Phalan     if (retdata == NULL)
431159d09a2SMark Phalan 	return EINVAL;
432159d09a2SMark Phalan 
433159d09a2SMark Phalan     switch (request_type) {
434159d09a2SMark Phalan     case krb5plugin_preauth_client_get_etype:
435159d09a2SMark Phalan 	{
436159d09a2SMark Phalan 	    krb5_enctype *eptr;
437159d09a2SMark Phalan 	    if (rock->as_reply == NULL)
438159d09a2SMark Phalan 		return ENOENT;
439159d09a2SMark Phalan 	    ret = malloc(sizeof(krb5_data));
440159d09a2SMark Phalan 	    if (ret == NULL)
441159d09a2SMark Phalan 		return ENOMEM;
442159d09a2SMark Phalan 	    data = malloc(sizeof(krb5_enctype));
443159d09a2SMark Phalan 	    if (data == NULL) {
444159d09a2SMark Phalan 		free(ret);
445159d09a2SMark Phalan 		return ENOMEM;
446159d09a2SMark Phalan 	    }
447159d09a2SMark Phalan 	    ret->data = data;
448159d09a2SMark Phalan 	    ret->length = sizeof(krb5_enctype);
449159d09a2SMark Phalan 	    eptr = (krb5_enctype *)data;
450159d09a2SMark Phalan 	    *eptr = rock->as_reply->enc_part.enctype;
451159d09a2SMark Phalan 	    *retdata = ret;
452159d09a2SMark Phalan 	    return 0;
453159d09a2SMark Phalan 	}
454159d09a2SMark Phalan 	break;
455159d09a2SMark Phalan     case krb5plugin_preauth_client_free_etype:
456159d09a2SMark Phalan 	ret = *retdata;
457159d09a2SMark Phalan 	if (ret == NULL)
458159d09a2SMark Phalan 	    return 0;
459159d09a2SMark Phalan 	if (ret->data)
460159d09a2SMark Phalan 	    free(ret->data);
461159d09a2SMark Phalan 	free(ret);
462159d09a2SMark Phalan 	return 0;
463159d09a2SMark Phalan 	break;
464159d09a2SMark Phalan     default:
465159d09a2SMark Phalan 	return EINVAL;
466159d09a2SMark Phalan     }
467159d09a2SMark Phalan }
468159d09a2SMark Phalan 
469159d09a2SMark Phalan /* Tweak the request body, for now adding any enctypes which the module claims
470159d09a2SMark Phalan  * to add support for to the list, but in the future perhaps doing more
471159d09a2SMark Phalan  * involved things. */
472159d09a2SMark Phalan void KRB5_CALLCONV
krb5_preauth_prepare_request(krb5_context kcontext,krb5_gic_opt_ext * opte,krb5_kdc_req * request)473159d09a2SMark Phalan krb5_preauth_prepare_request(krb5_context kcontext,
474159d09a2SMark Phalan 			     krb5_gic_opt_ext *opte,
475159d09a2SMark Phalan 			     krb5_kdc_req *request)
476159d09a2SMark Phalan {
477159d09a2SMark Phalan     int i, j;
478159d09a2SMark Phalan 
479159d09a2SMark Phalan     if (kcontext->preauth_context == NULL) {
480159d09a2SMark Phalan 	return;
481159d09a2SMark Phalan     }
482159d09a2SMark Phalan     /* Add the module-specific enctype list to the request, but only if
483159d09a2SMark Phalan      * it's something we can safely modify. */
484159d09a2SMark Phalan     if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
485159d09a2SMark Phalan 	for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
486159d09a2SMark Phalan 	    if (kcontext->preauth_context->modules[i].enctypes == NULL)
487159d09a2SMark Phalan 		continue;
488159d09a2SMark Phalan 	    for (j = 0; kcontext->preauth_context->modules[i].enctypes[j] != 0; j++) {
489159d09a2SMark Phalan 		grow_ktypes(&request->ktype, &request->nktypes,
490159d09a2SMark Phalan 			    kcontext->preauth_context->modules[i].enctypes[j]);
491159d09a2SMark Phalan 	    }
492159d09a2SMark Phalan 	}
493159d09a2SMark Phalan     }
494159d09a2SMark Phalan }
495159d09a2SMark Phalan 
496159d09a2SMark Phalan /* Find the first module which provides for the named preauth type which also
497159d09a2SMark Phalan  * hasn't had a chance to run yet (INFO modules don't count, because as a rule
498159d09a2SMark Phalan  * they don't generate preauth data), and run it. */
499159d09a2SMark Phalan 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)500159d09a2SMark Phalan krb5_run_preauth_plugins(krb5_context kcontext,
501159d09a2SMark Phalan 			 int module_required_flags,
502159d09a2SMark Phalan 			 krb5_kdc_req *request,
503159d09a2SMark Phalan 			 krb5_data *encoded_request_body,
504159d09a2SMark Phalan 			 krb5_data *encoded_previous_request,
505159d09a2SMark Phalan 			 krb5_pa_data *in_padata,
506159d09a2SMark Phalan 			 krb5_prompter_fct prompter,
507159d09a2SMark Phalan 			 void *prompter_data,
508159d09a2SMark Phalan 			 preauth_get_as_key_proc gak_fct,
509159d09a2SMark Phalan 			 krb5_data *salt,
510159d09a2SMark Phalan 			 krb5_data *s2kparams,
511159d09a2SMark Phalan 			 void *gak_data,
512159d09a2SMark Phalan 			 krb5_preauth_client_rock *get_data_rock,
513159d09a2SMark Phalan 			 krb5_keyblock *as_key,
514159d09a2SMark Phalan 			 krb5_pa_data ***out_pa_list,
515159d09a2SMark Phalan 			 int *out_pa_list_size,
516159d09a2SMark Phalan 			 int *module_ret,
517159d09a2SMark Phalan 			 int *module_flags,
518159d09a2SMark Phalan 			 krb5_gic_opt_ext *opte)
519159d09a2SMark Phalan {
520159d09a2SMark Phalan     int i;
521159d09a2SMark Phalan     krb5_pa_data **out_pa_data;
522159d09a2SMark Phalan     krb5_error_code ret;
523159d09a2SMark Phalan     struct _krb5_preauth_context_module *module;
524159d09a2SMark Phalan 
525159d09a2SMark Phalan     if (kcontext->preauth_context == NULL) {
526159d09a2SMark Phalan 	return ENOENT;
527159d09a2SMark Phalan     }
528159d09a2SMark Phalan     /* iterate over all loaded modules */
529159d09a2SMark Phalan     for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
530159d09a2SMark Phalan 	module = &kcontext->preauth_context->modules[i];
531159d09a2SMark Phalan 	/* skip over those which don't match the preauth type */
532159d09a2SMark Phalan 	if (module->pa_type != in_padata->pa_type)
533159d09a2SMark Phalan 	    continue;
534159d09a2SMark Phalan 	/* skip over those which don't match the flags (INFO vs REAL, mainly) */
535159d09a2SMark Phalan 	if ((module->flags & module_required_flags) == 0)
536159d09a2SMark Phalan 	    continue;
537159d09a2SMark Phalan 	/* if it's a REAL module, try to call it only once per library call */
538159d09a2SMark Phalan 	if (module_required_flags & PA_REAL) {
539159d09a2SMark Phalan 	    if (module->use_count > 0) {
540159d09a2SMark Phalan #ifdef DEBUG
541159d09a2SMark Phalan 		fprintf(stderr, "skipping already-used module \"%s\"(%d)\n",
542159d09a2SMark Phalan 			module->name, module->pa_type);
543159d09a2SMark Phalan #endif
544159d09a2SMark Phalan 		continue;
545159d09a2SMark Phalan 	    }
546159d09a2SMark Phalan 	    module->use_count++;
547159d09a2SMark Phalan 	}
548159d09a2SMark Phalan 	/* run the module's callback function */
549159d09a2SMark Phalan 	out_pa_data = NULL;
550159d09a2SMark Phalan #ifdef DEBUG
551159d09a2SMark Phalan 	fprintf(stderr, "using module \"%s\" (%d), flags = %d\n",
552159d09a2SMark Phalan 		module->name, module->pa_type, module->flags);
553159d09a2SMark Phalan #endif
554159d09a2SMark Phalan 	ret = module->client_process(kcontext,
555159d09a2SMark Phalan 				     module->plugin_context,
556159d09a2SMark Phalan 				     *module->request_context_pp,
557159d09a2SMark Phalan 				     (krb5_get_init_creds_opt *)opte,
558159d09a2SMark Phalan 				     client_data_proc,
559159d09a2SMark Phalan 				     get_data_rock,
560159d09a2SMark Phalan 				     request,
561159d09a2SMark Phalan 				     encoded_request_body,
562159d09a2SMark Phalan 				     encoded_previous_request,
563159d09a2SMark Phalan 				     in_padata,
564159d09a2SMark Phalan 				     prompter, prompter_data,
565159d09a2SMark Phalan 				     gak_fct, gak_data, salt, s2kparams,
566159d09a2SMark Phalan 				     as_key,
567159d09a2SMark Phalan 				     &out_pa_data);
568159d09a2SMark Phalan 	/* Make note of the module's flags and status. */
569159d09a2SMark Phalan 	*module_flags = module->flags;
570159d09a2SMark Phalan 	*module_ret = ret;
571159d09a2SMark Phalan 	/* Save the new preauth data item. */
572159d09a2SMark Phalan 	if (out_pa_data != NULL) {
573159d09a2SMark Phalan 	    int j;
574159d09a2SMark Phalan 	    for (j = 0; out_pa_data[j] != NULL; j++);
575159d09a2SMark Phalan 	    ret = grow_pa_list(out_pa_list, out_pa_list_size, out_pa_data, j);
576159d09a2SMark Phalan 	    free(out_pa_data);
577159d09a2SMark Phalan 	    if (ret != 0)
578159d09a2SMark Phalan 		return ret;
579159d09a2SMark Phalan 	}
580159d09a2SMark Phalan 	break;
581159d09a2SMark Phalan     }
582159d09a2SMark Phalan     if (i >= kcontext->preauth_context->n_modules) {
583159d09a2SMark Phalan 	return ENOENT;
584159d09a2SMark Phalan     }
585159d09a2SMark Phalan     return 0;
586159d09a2SMark Phalan }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@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)5897c478bd9Sstevel@tonic-gate krb5_error_code pa_salt(krb5_context context,
5907c478bd9Sstevel@tonic-gate 			krb5_kdc_req *request,
5917c478bd9Sstevel@tonic-gate 			krb5_pa_data *in_padata,
5927c478bd9Sstevel@tonic-gate 			krb5_pa_data **out_padata,
593159d09a2SMark Phalan 			krb5_data *salt, krb5_data *s2kparams,
5947c478bd9Sstevel@tonic-gate 			krb5_enctype *etype,
5957c478bd9Sstevel@tonic-gate 			krb5_keyblock *as_key,
5967c478bd9Sstevel@tonic-gate 			krb5_prompter_fct prompter, void *prompter_data,
5977c478bd9Sstevel@tonic-gate 			krb5_gic_get_as_key_fct gak_fct, void *gak_data)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate     krb5_data tmp;
6007c478bd9Sstevel@tonic-gate 
601159d09a2SMark Phalan     /* Solaris Kerberos - resync */
6027c478bd9Sstevel@tonic-gate     tmp.data = (char *)in_padata->contents;
6037c478bd9Sstevel@tonic-gate     tmp.length = in_padata->length;
6047c478bd9Sstevel@tonic-gate     krb5_free_data_contents(context, salt);
6057c478bd9Sstevel@tonic-gate     krb5int_copy_data_contents(context, &tmp, salt);
606*55fea89dSDan Cross 
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate     if (in_padata->pa_type == KRB5_PADATA_AFS3_SALT)
609159d09a2SMark Phalan 	salt->length = SALT_TYPE_AFS_LENGTH;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate     return(0);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6157c478bd9Sstevel@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)6167c478bd9Sstevel@tonic-gate krb5_error_code pa_enc_timestamp(krb5_context context,
6177c478bd9Sstevel@tonic-gate 				 krb5_kdc_req *request,
6187c478bd9Sstevel@tonic-gate 				 krb5_pa_data *in_padata,
6197c478bd9Sstevel@tonic-gate 				 krb5_pa_data **out_padata,
6207c478bd9Sstevel@tonic-gate 				 krb5_data *salt,
6217c478bd9Sstevel@tonic-gate 				 krb5_data *s2kparams,
6227c478bd9Sstevel@tonic-gate 				 krb5_enctype *etype,
6237c478bd9Sstevel@tonic-gate 				 krb5_keyblock *as_key,
6247c478bd9Sstevel@tonic-gate 				 krb5_prompter_fct prompter,
6257c478bd9Sstevel@tonic-gate 				 void *prompter_data,
6267c478bd9Sstevel@tonic-gate 				 krb5_gic_get_as_key_fct gak_fct,
6277c478bd9Sstevel@tonic-gate 				 void *gak_data)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate     krb5_error_code ret;
6307c478bd9Sstevel@tonic-gate     krb5_pa_enc_ts pa_enc;
6317c478bd9Sstevel@tonic-gate     krb5_data *tmp;
6327c478bd9Sstevel@tonic-gate     krb5_enc_data enc_data;
6337c478bd9Sstevel@tonic-gate     krb5_pa_data *pa;
634*55fea89dSDan Cross 
6357c478bd9Sstevel@tonic-gate     if (as_key->length == 0) {
6367c478bd9Sstevel@tonic-gate #ifdef DEBUG
637159d09a2SMark Phalan 	/* Solaris Kerberos */
6387c478bd9Sstevel@tonic-gate 	if (salt != NULL && salt->data != NULL) {
639159d09a2SMark Phalan 		fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
6407c478bd9Sstevel@tonic-gate 		 salt->length);
641159d09a2SMark Phalan 	    if ((int) salt->length > 0)
642159d09a2SMark Phalan 	    fprintf (stderr, " '%.*s'", salt->length, salt->data);
6437c478bd9Sstevel@tonic-gate 	    fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
6447c478bd9Sstevel@tonic-gate 		 *etype, request->ktype[0]);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate #endif
647505d05c7Sgtb        if ((ret = ((*gak_fct)(context, request->client,
648159d09a2SMark Phalan 			      *etype ? *etype : request->ktype[0],
649159d09a2SMark Phalan 			      prompter, prompter_data,
650159d09a2SMark Phalan 			      salt, s2kparams, as_key, gak_data))))
6517c478bd9Sstevel@tonic-gate            return(ret);
6527c478bd9Sstevel@tonic-gate     }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate     /* now get the time of day, and encrypt it accordingly */
6557c478bd9Sstevel@tonic-gate 
656505d05c7Sgtb     if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec)))
6577c478bd9Sstevel@tonic-gate 	return(ret);
6587c478bd9Sstevel@tonic-gate 
659505d05c7Sgtb     if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp)))
6607c478bd9Sstevel@tonic-gate 	return(ret);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate #ifdef DEBUG
6637c478bd9Sstevel@tonic-gate     fprintf (stderr, "key type %d bytes %02x %02x ...\n",
6647c478bd9Sstevel@tonic-gate 	     as_key->enctype,
6657c478bd9Sstevel@tonic-gate 	     as_key->contents[0], as_key->contents[1]);
6667c478bd9Sstevel@tonic-gate #endif
6677c478bd9Sstevel@tonic-gate     ret = krb5_encrypt_helper(context, as_key,
6687c478bd9Sstevel@tonic-gate 			      KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
6697c478bd9Sstevel@tonic-gate 			      tmp, &enc_data);
6707c478bd9Sstevel@tonic-gate #ifdef DEBUG
6717c478bd9Sstevel@tonic-gate     fprintf (stderr, "enc data { type=%d kvno=%d data=%02x %02x ... }\n",
6727c478bd9Sstevel@tonic-gate 	     enc_data.enctype, enc_data.kvno,
6737c478bd9Sstevel@tonic-gate 	     0xff & enc_data.ciphertext.data[0],
6747c478bd9Sstevel@tonic-gate 	     0xff & enc_data.ciphertext.data[1]);
6757c478bd9Sstevel@tonic-gate #endif
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate     krb5_free_data(context, tmp);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate     if (ret) {
6807c478bd9Sstevel@tonic-gate 	krb5_xfree(enc_data.ciphertext.data);
6817c478bd9Sstevel@tonic-gate 	return(ret);
6827c478bd9Sstevel@tonic-gate     }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate     ret = encode_krb5_enc_data(&enc_data, &tmp);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate     krb5_xfree(enc_data.ciphertext.data);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate     if (ret)
6897c478bd9Sstevel@tonic-gate 	return(ret);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate     if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
6927c478bd9Sstevel@tonic-gate 	krb5_free_data(context, tmp);
6937c478bd9Sstevel@tonic-gate 	return(ENOMEM);
6947c478bd9Sstevel@tonic-gate     }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate     pa->magic = KV5M_PA_DATA;
6977c478bd9Sstevel@tonic-gate     pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
6987c478bd9Sstevel@tonic-gate     pa->length = tmp->length;
6997c478bd9Sstevel@tonic-gate     pa->contents = (krb5_octet *) tmp->data;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate     *out_padata = pa;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate     krb5_xfree(tmp);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate     return(0);
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate 
708*55fea89dSDan Cross static
sam_challenge_banner(krb5_int32 sam_type)7097c478bd9Sstevel@tonic-gate char *sam_challenge_banner(krb5_int32 sam_type)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate     char *label;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate     switch (sam_type) {
7147c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_ENIGMA:	/* Enigma Logic */
7157c478bd9Sstevel@tonic-gate 	label = "Challenge for Enigma Logic mechanism";
7167c478bd9Sstevel@tonic-gate 	break;
7177c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_DIGI_PATH: /*  Digital Pathways */
7187c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_DIGI_PATH_HEX: /*  Digital Pathways */
7197c478bd9Sstevel@tonic-gate 	label = "Challenge for Digital Pathways mechanism";
7207c478bd9Sstevel@tonic-gate 	break;
7217c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_ACTIVCARD_DEC: /*  Digital Pathways */
7227c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_ACTIVCARD_HEX: /*  Digital Pathways */
7237c478bd9Sstevel@tonic-gate 	label = "Challenge for Activcard mechanism";
7247c478bd9Sstevel@tonic-gate 	break;
7257c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_SKEY_K0:	/*  S/key where  KDC has key 0 */
7267c478bd9Sstevel@tonic-gate 	label = "Challenge for Enhanced S/Key mechanism";
7277c478bd9Sstevel@tonic-gate 	break;
7287c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_SKEY:	/*  Traditional S/Key */
7297c478bd9Sstevel@tonic-gate 	label = "Challenge for Traditional S/Key mechanism";
7307c478bd9Sstevel@tonic-gate 	break;
7317c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_SECURID:	/*  Security Dynamics */
7327c478bd9Sstevel@tonic-gate 	label = "Challenge for Security Dynamics mechanism";
7337c478bd9Sstevel@tonic-gate 	break;
7347c478bd9Sstevel@tonic-gate     case PA_SAM_TYPE_SECURID_PREDICT:	/* predictive Security Dynamics */
7357c478bd9Sstevel@tonic-gate 	label = "Challenge for Security Dynamics mechanism";
7367c478bd9Sstevel@tonic-gate 	break;
7377c478bd9Sstevel@tonic-gate     default:
7387c478bd9Sstevel@tonic-gate 	label = "Challenge from authentication server";
7397c478bd9Sstevel@tonic-gate 	break;
7407c478bd9Sstevel@tonic-gate     }
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate     return(label);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate /* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate #define SAMDATA(kdata, str, maxsize) \
7487c478bd9Sstevel@tonic-gate 	(int)((kdata.length)? \
7497c478bd9Sstevel@tonic-gate 	      ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
7507c478bd9Sstevel@tonic-gate 	      strlen(str)), \
7517c478bd9Sstevel@tonic-gate 	(kdata.length)? \
7527c478bd9Sstevel@tonic-gate 	((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate /* XXX Danger! This code is not in sync with the kerberos-password-02
7557c478bd9Sstevel@tonic-gate    draft.  This draft cannot be implemented as written.  This code is
7567c478bd9Sstevel@tonic-gate    compatible with earlier versions of mit krb5 and cygnus kerbnet. */
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7597c478bd9Sstevel@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)7607c478bd9Sstevel@tonic-gate krb5_error_code pa_sam(krb5_context context,
7617c478bd9Sstevel@tonic-gate 		       krb5_kdc_req *request,
7627c478bd9Sstevel@tonic-gate 		       krb5_pa_data *in_padata,
7637c478bd9Sstevel@tonic-gate 		       krb5_pa_data **out_padata,
7647c478bd9Sstevel@tonic-gate 		       krb5_data *salt,
7657c478bd9Sstevel@tonic-gate 		       krb5_data *s2kparams,
7667c478bd9Sstevel@tonic-gate 		       krb5_enctype *etype,
7677c478bd9Sstevel@tonic-gate 		       krb5_keyblock *as_key,
7687c478bd9Sstevel@tonic-gate 		       krb5_prompter_fct prompter,
7697c478bd9Sstevel@tonic-gate 		       void *prompter_data,
7707c478bd9Sstevel@tonic-gate 		       krb5_gic_get_as_key_fct gak_fct,
7717c478bd9Sstevel@tonic-gate 		       void *gak_data)
7727c478bd9Sstevel@tonic-gate {
7737c478bd9Sstevel@tonic-gate     krb5_error_code		ret;
7747c478bd9Sstevel@tonic-gate     krb5_data			tmpsam;
7757c478bd9Sstevel@tonic-gate     char			name[100], banner[100];
7767c478bd9Sstevel@tonic-gate     char			prompt[100], response[100];
7777c478bd9Sstevel@tonic-gate     krb5_data			response_data;
7787c478bd9Sstevel@tonic-gate     krb5_prompt			kprompt;
7797c478bd9Sstevel@tonic-gate     krb5_prompt_type		prompt_type;
7807c478bd9Sstevel@tonic-gate     krb5_data			defsalt;
7817c478bd9Sstevel@tonic-gate     krb5_sam_challenge		*sam_challenge = 0;
7827c478bd9Sstevel@tonic-gate     krb5_sam_response		sam_response;
7837c478bd9Sstevel@tonic-gate     /* these two get encrypted and stuffed in to sam_response */
7847c478bd9Sstevel@tonic-gate     krb5_enc_sam_response_enc	enc_sam_response_enc;
7857c478bd9Sstevel@tonic-gate     krb5_data *			scratch;
7867c478bd9Sstevel@tonic-gate     krb5_pa_data *		pa;
787159d09a2SMark Phalan 
788159d09a2SMark Phalan     /* Solaris Kerberos */
7897c478bd9Sstevel@tonic-gate     krb5_enc_data *		enc_data;
7907c478bd9Sstevel@tonic-gate     size_t			enclen;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate     if (prompter == NULL)
793159d09a2SMark Phalan 	return EIO;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate     tmpsam.length = in_padata->length;
7967c478bd9Sstevel@tonic-gate     tmpsam.data = (char *) in_padata->contents;
797505d05c7Sgtb     if ((ret = decode_krb5_sam_challenge(&tmpsam, &sam_challenge)))
7987c478bd9Sstevel@tonic-gate 	return(ret);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate     if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
8017c478bd9Sstevel@tonic-gate 	krb5_xfree(sam_challenge);
8027c478bd9Sstevel@tonic-gate 	return(KRB5_SAM_UNSUPPORTED);
8037c478bd9Sstevel@tonic-gate     }
804159d09a2SMark Phalan 
8057c478bd9Sstevel@tonic-gate     /* If we need the password from the user (USE_SAD_AS_KEY not set),	*/
806159d09a2SMark Phalan     /* then get it here.  Exception for "old" KDCs with CryptoCard 	*/
807*55fea89dSDan Cross     /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd	*/
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate     if (!(sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) ||
8107c478bd9Sstevel@tonic-gate 	(sam_challenge->sam_type == PA_SAM_TYPE_CRYPTOCARD)) {
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
8137c478bd9Sstevel@tonic-gate 	/* message from the KDC.  If it is not set, pick an enctype that we */
814159d09a2SMark Phalan 	/* think the KDC will have for us.				    */
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	if (etype && *etype == 0)
817159d09a2SMark Phalan 	   *etype = ENCTYPE_DES_CBC_CRC;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	if ((ret = (gak_fct)(context, request->client, *etype, prompter,
8207c478bd9Sstevel@tonic-gate 			prompter_data, salt, s2kparams, as_key, gak_data)))
8217c478bd9Sstevel@tonic-gate 	   return(ret);
8227c478bd9Sstevel@tonic-gate     }
8237c478bd9Sstevel@tonic-gate     sprintf(name, "%.*s",
8247c478bd9Sstevel@tonic-gate 	    SAMDATA(sam_challenge->sam_type_name, "SAM Authentication",
8257c478bd9Sstevel@tonic-gate 		    sizeof(name) - 1));
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate     sprintf(banner, "%.*s",
8287c478bd9Sstevel@tonic-gate 	    SAMDATA(sam_challenge->sam_challenge_label,
8297c478bd9Sstevel@tonic-gate 		    sam_challenge_banner(sam_challenge->sam_type),
8307c478bd9Sstevel@tonic-gate 		    sizeof(banner)-1));
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate     /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */
8337c478bd9Sstevel@tonic-gate     sprintf(prompt, "%s%.*s%s%.*s",
8347c478bd9Sstevel@tonic-gate 	    sam_challenge->sam_challenge.length?"Challenge is [":"",
8357c478bd9Sstevel@tonic-gate 	    SAMDATA(sam_challenge->sam_challenge, "", 20),
8367c478bd9Sstevel@tonic-gate 	    sam_challenge->sam_challenge.length?"], ":"",
8377c478bd9Sstevel@tonic-gate 	    SAMDATA(sam_challenge->sam_response_prompt, "passcode", 55));
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate     response_data.data = response;
8407c478bd9Sstevel@tonic-gate     response_data.length = sizeof(response);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate     kprompt.prompt = prompt;
843505d05c7Sgtb     kprompt.hidden = 1;
8447c478bd9Sstevel@tonic-gate     kprompt.reply = &response_data;
8457c478bd9Sstevel@tonic-gate     prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate     /* PROMPTER_INVOCATION */
8487c478bd9Sstevel@tonic-gate     krb5int_set_prompt_types(context, &prompt_type);
849505d05c7Sgtb     if ((ret = ((*prompter)(context, prompter_data, name,
850505d05c7Sgtb 			   banner, 1, &kprompt)))) {
8517c478bd9Sstevel@tonic-gate 	krb5_xfree(sam_challenge);
8527c478bd9Sstevel@tonic-gate 	krb5int_set_prompt_types(context, 0);
8537c478bd9Sstevel@tonic-gate 	return(ret);
8547c478bd9Sstevel@tonic-gate     }
8557c478bd9Sstevel@tonic-gate     krb5int_set_prompt_types(context, 0);
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate     enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
8587c478bd9Sstevel@tonic-gate     if (sam_challenge->sam_nonce == 0) {
859*55fea89dSDan Cross 	if ((ret = krb5_us_timeofday(context,
8607c478bd9Sstevel@tonic-gate 				&enc_sam_response_enc.sam_timestamp,
861505d05c7Sgtb 				&enc_sam_response_enc.sam_usec))) {
8627c478bd9Sstevel@tonic-gate 		krb5_xfree(sam_challenge);
8637c478bd9Sstevel@tonic-gate 		return(ret);
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
8677c478bd9Sstevel@tonic-gate     }
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate     /* XXX What if more than one flag is set?  */
8707c478bd9Sstevel@tonic-gate     if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
8717c478bd9Sstevel@tonic-gate 
872159d09a2SMark Phalan 	/* Most of this should be taken care of before we get here.  We	*/
8737c478bd9Sstevel@tonic-gate 	/* will need the user's password and as_key to encrypt the SAD	*/
8747c478bd9Sstevel@tonic-gate 	/* and we want to preserve ordering of user prompts (first	*/
8757c478bd9Sstevel@tonic-gate 	/* password, then SAM data) so that user's won't be confused.	*/
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	if (as_key->length) {
8787c478bd9Sstevel@tonic-gate 	    krb5_free_keyblock_contents(context, as_key);
8797c478bd9Sstevel@tonic-gate 	    as_key->length = 0;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	/* generate a salt using the requested principal */
8837c478bd9Sstevel@tonic-gate 
884159d09a2SMark Phalan 	if ((salt->length == -1 || salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
885505d05c7Sgtb 	    if ((ret = krb5_principal2salt(context, request->client,
886505d05c7Sgtb 					  &defsalt))) {
8877c478bd9Sstevel@tonic-gate 		krb5_xfree(sam_challenge);
8887c478bd9Sstevel@tonic-gate 		return(ret);
8897c478bd9Sstevel@tonic-gate 	    }
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	    salt = &defsalt;
8927c478bd9Sstevel@tonic-gate 	} else {
8937c478bd9Sstevel@tonic-gate 	    defsalt.length = 0;
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	/* generate a key using the supplied password */
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
8997c478bd9Sstevel@tonic-gate 				   (krb5_data *)gak_data, salt, as_key);
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	if (defsalt.length)
9027c478bd9Sstevel@tonic-gate 	    krb5_xfree(defsalt.data);
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	if (ret) {
9057c478bd9Sstevel@tonic-gate 	    krb5_xfree(sam_challenge);
9067c478bd9Sstevel@tonic-gate 	    return(ret);
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	/* encrypt the passcode with the key from above */
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	enc_sam_response_enc.sam_sad = response_data;
9127c478bd9Sstevel@tonic-gate     } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/* process the key as password */
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	if (as_key->length) {
9177c478bd9Sstevel@tonic-gate 	    krb5_free_keyblock_contents(context, as_key);
9187c478bd9Sstevel@tonic-gate 	    as_key->length = 0;
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate #if 0
922159d09a2SMark Phalan 	if ((salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
9237c478bd9Sstevel@tonic-gate 	    if (ret = krb5_principal2salt(context, request->client,
9247c478bd9Sstevel@tonic-gate 					  &defsalt)) {
9257c478bd9Sstevel@tonic-gate 		krb5_xfree(sam_challenge);
9267c478bd9Sstevel@tonic-gate 		return(ret);
9277c478bd9Sstevel@tonic-gate 	    }
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	    salt = &defsalt;
9307c478bd9Sstevel@tonic-gate 	} else {
9317c478bd9Sstevel@tonic-gate 	    defsalt.length = 0;
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate #else
9347c478bd9Sstevel@tonic-gate 	defsalt.length = 0;
9357c478bd9Sstevel@tonic-gate 	salt = NULL;
9367c478bd9Sstevel@tonic-gate #endif
937*55fea89dSDan Cross 
9387c478bd9Sstevel@tonic-gate 	/* XXX As of the passwords-04 draft, no enctype is specified,
9397c478bd9Sstevel@tonic-gate 	   the server uses ENCTYPE_DES_CBC_MD5. In the future the
9407c478bd9Sstevel@tonic-gate 	   server should send a PA-SAM-ETYPE-INFO containing the enctype. */
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
9437c478bd9Sstevel@tonic-gate 				   &response_data, salt, as_key);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	if (defsalt.length)
9467c478bd9Sstevel@tonic-gate 	    krb5_xfree(defsalt.data);
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	if (ret) {
9497c478bd9Sstevel@tonic-gate 	    krb5_xfree(sam_challenge);
9507c478bd9Sstevel@tonic-gate 	    return(ret);
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	enc_sam_response_enc.sam_sad.length = 0;
9547c478bd9Sstevel@tonic-gate     } else {
9557c478bd9Sstevel@tonic-gate 	/* Eventually, combine SAD with long-term key to get
9567c478bd9Sstevel@tonic-gate 	   encryption key.  */
9577c478bd9Sstevel@tonic-gate 	return KRB5_PREAUTH_BAD_TYPE;
9587c478bd9Sstevel@tonic-gate     }
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate     /* copy things from the challenge */
9617c478bd9Sstevel@tonic-gate     sam_response.sam_nonce = sam_challenge->sam_nonce;
9627c478bd9Sstevel@tonic-gate     sam_response.sam_flags = sam_challenge->sam_flags;
9637c478bd9Sstevel@tonic-gate     sam_response.sam_track_id = sam_challenge->sam_track_id;
9647c478bd9Sstevel@tonic-gate     sam_response.sam_type = sam_challenge->sam_type;
9657c478bd9Sstevel@tonic-gate     sam_response.magic = KV5M_SAM_RESPONSE;
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate     krb5_xfree(sam_challenge);
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate     /* encode the encoded part of the response */
970505d05c7Sgtb     if ((ret = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
971159d09a2SMark Phalan 						&scratch)))
9727c478bd9Sstevel@tonic-gate 	return(ret);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate     /*
975*55fea89dSDan Cross      * Solaris Kerberos:
9767c478bd9Sstevel@tonic-gate      * Using new crypto interface now so we can get rid of the
9777c478bd9Sstevel@tonic-gate      * old modules.
9787c478bd9Sstevel@tonic-gate      */
9797c478bd9Sstevel@tonic-gate     if ((ret = krb5_c_encrypt_length(context, as_key->enctype,
9807c478bd9Sstevel@tonic-gate 				scratch->length, &enclen))) {
9817c478bd9Sstevel@tonic-gate 	krb5_free_data(context, scratch);
9827c478bd9Sstevel@tonic-gate 	return(ret);
9837c478bd9Sstevel@tonic-gate     }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate     enc_data = &sam_response.sam_enc_nonce_or_ts;
9867c478bd9Sstevel@tonic-gate     enc_data->magic = KV5M_ENC_DATA;
9877c478bd9Sstevel@tonic-gate     enc_data->kvno = 0;
9887c478bd9Sstevel@tonic-gate     enc_data->enctype = as_key->enctype;
9897c478bd9Sstevel@tonic-gate     enc_data->ciphertext.length = enclen;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate     if ((enc_data->ciphertext.data = MALLOC(enclen)) == NULL) {
9927c478bd9Sstevel@tonic-gate 	enc_data->ciphertext.length = 0;
9937c478bd9Sstevel@tonic-gate 	krb5_free_data(context, scratch);
9947c478bd9Sstevel@tonic-gate 	return(ENOMEM);
9957c478bd9Sstevel@tonic-gate     }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate     if ((ret = krb5_c_encrypt(context, as_key, 0, 0,
9987c478bd9Sstevel@tonic-gate 	scratch, enc_data))) {
9997c478bd9Sstevel@tonic-gate 	FREE(enc_data->ciphertext.data, enclen);
10007c478bd9Sstevel@tonic-gate 	enc_data->ciphertext.data = NULL;
10017c478bd9Sstevel@tonic-gate 	enc_data->ciphertext.length = 0;
10027c478bd9Sstevel@tonic-gate     }
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate     krb5_free_data(context, scratch);
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate     if (ret)
10077c478bd9Sstevel@tonic-gate 	return(ret);
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate     /* sam_enc_key is reserved for future use */
10107c478bd9Sstevel@tonic-gate     sam_response.sam_enc_key.ciphertext.length = 0;
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate     if ((pa = malloc(sizeof(krb5_pa_data))) == NULL)
10137c478bd9Sstevel@tonic-gate 	return(ENOMEM);
10147c478bd9Sstevel@tonic-gate 
1015505d05c7Sgtb     if ((ret = encode_krb5_sam_response(&sam_response, &scratch))) {
10167c478bd9Sstevel@tonic-gate 	free(pa);
10177c478bd9Sstevel@tonic-gate 	return(ret);
10187c478bd9Sstevel@tonic-gate     }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate     pa->magic = KV5M_PA_DATA;
10217c478bd9Sstevel@tonic-gate     pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
10227c478bd9Sstevel@tonic-gate     pa->length = scratch->length;
10237c478bd9Sstevel@tonic-gate     pa->contents = (krb5_octet *) scratch->data;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate     *out_padata = pa;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate     return(0);
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@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)10317c478bd9Sstevel@tonic-gate krb5_error_code pa_sam_2(krb5_context context,
10327c478bd9Sstevel@tonic-gate 				krb5_kdc_req *request,
10337c478bd9Sstevel@tonic-gate 				krb5_pa_data *in_padata,
10347c478bd9Sstevel@tonic-gate 				krb5_pa_data **out_padata,
10357c478bd9Sstevel@tonic-gate 				krb5_data *salt,
10367c478bd9Sstevel@tonic-gate 			 krb5_data *s2kparams,
10377c478bd9Sstevel@tonic-gate 				krb5_enctype *etype,
10387c478bd9Sstevel@tonic-gate 				krb5_keyblock *as_key,
10397c478bd9Sstevel@tonic-gate 				krb5_prompter_fct prompter,
10407c478bd9Sstevel@tonic-gate 				void *prompter_data,
10417c478bd9Sstevel@tonic-gate 				krb5_gic_get_as_key_fct gak_fct,
10427c478bd9Sstevel@tonic-gate 				void *gak_data) {
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate    krb5_error_code retval;
10457c478bd9Sstevel@tonic-gate    krb5_sam_challenge_2 *sc2 = NULL;
10467c478bd9Sstevel@tonic-gate    krb5_sam_challenge_2_body *sc2b = NULL;
10477c478bd9Sstevel@tonic-gate    krb5_data tmp_data;
10487c478bd9Sstevel@tonic-gate    krb5_data response_data;
10497c478bd9Sstevel@tonic-gate    char name[100], banner[100], prompt[100], response[100];
10507c478bd9Sstevel@tonic-gate    krb5_prompt kprompt;
10517c478bd9Sstevel@tonic-gate    krb5_prompt_type prompt_type;
10527c478bd9Sstevel@tonic-gate    krb5_data defsalt;
10537c478bd9Sstevel@tonic-gate    krb5_checksum **cksum;
10547c478bd9Sstevel@tonic-gate    krb5_data *scratch = NULL;
10557c478bd9Sstevel@tonic-gate    krb5_boolean valid_cksum = 0;
10567c478bd9Sstevel@tonic-gate    krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
10577c478bd9Sstevel@tonic-gate    krb5_sam_response_2 sr2;
10587c478bd9Sstevel@tonic-gate    size_t ciph_len;
10597c478bd9Sstevel@tonic-gate    krb5_pa_data *sam_padata;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate    if (prompter == NULL)
10627c478bd9Sstevel@tonic-gate 	return KRB5_LIBOS_CANTREADPWD;
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate    tmp_data.length = in_padata->length;
10657c478bd9Sstevel@tonic-gate    tmp_data.data = (char *)in_padata->contents;
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate    if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2)))
10687c478bd9Sstevel@tonic-gate 	return(retval);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate    retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate    if (retval)
10737c478bd9Sstevel@tonic-gate 	return(retval);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate    if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
10767c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
10777c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
10787c478bd9Sstevel@tonic-gate 	return(KRB5_SAM_NO_CHECKSUM);
10797c478bd9Sstevel@tonic-gate    }
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate    if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
10827c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
10837c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
10847c478bd9Sstevel@tonic-gate 	return(KRB5_SAM_UNSUPPORTED);
10857c478bd9Sstevel@tonic-gate    }
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate    if (!valid_enctype(sc2b->sam_etype)) {
10887c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
10897c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
10907c478bd9Sstevel@tonic-gate 	return(KRB5_SAM_INVALID_ETYPE);
10917c478bd9Sstevel@tonic-gate    }
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate    /* All of the above error checks are KDC-specific, that is, they	*/
10947c478bd9Sstevel@tonic-gate    /* assume a failure in the KDC reply.  By returning anything other	*/
10957c478bd9Sstevel@tonic-gate    /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED,		*/
10967c478bd9Sstevel@tonic-gate    /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will	*/
10977c478bd9Sstevel@tonic-gate    /* most likely go on to try the AS_REQ against master KDC		*/
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate    if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
1100159d09a2SMark Phalan 	/* We will need the password to obtain the key used for	*/
11017c478bd9Sstevel@tonic-gate 	/* the checksum, and encryption of the sam_response.	*/
11027c478bd9Sstevel@tonic-gate 	/* Go ahead and get it now, preserving the ordering of	*/
11037c478bd9Sstevel@tonic-gate 	/* prompts for the user.				*/
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	retval = (gak_fct)(context, request->client,
11067c478bd9Sstevel@tonic-gate 			sc2b->sam_etype, prompter,
11077c478bd9Sstevel@tonic-gate 			prompter_data, salt, s2kparams, as_key, gak_data);
11087c478bd9Sstevel@tonic-gate 	if (retval) {
11097c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2(context, sc2);
11107c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2_body(context, sc2b);
11117c478bd9Sstevel@tonic-gate 	   return(retval);
11127c478bd9Sstevel@tonic-gate 	}
11137c478bd9Sstevel@tonic-gate    }
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate    sprintf(name, "%.*s",
11167c478bd9Sstevel@tonic-gate 	SAMDATA(sc2b->sam_type_name, "SAM Authentication",
11177c478bd9Sstevel@tonic-gate 	sizeof(name) - 1));
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate    sprintf(banner, "%.*s",
11207c478bd9Sstevel@tonic-gate 	SAMDATA(sc2b->sam_challenge_label,
11217c478bd9Sstevel@tonic-gate 	sam_challenge_banner(sc2b->sam_type),
11227c478bd9Sstevel@tonic-gate 	sizeof(banner)-1));
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate    sprintf(prompt, "%s%.*s%s%.*s",
11257c478bd9Sstevel@tonic-gate 	sc2b->sam_challenge.length?"Challenge is [":"",
11267c478bd9Sstevel@tonic-gate 	SAMDATA(sc2b->sam_challenge, "", 20),
11277c478bd9Sstevel@tonic-gate 	sc2b->sam_challenge.length?"], ":"",
11287c478bd9Sstevel@tonic-gate 	SAMDATA(sc2b->sam_response_prompt, "passcode", 55));
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate    response_data.data = response;
11317c478bd9Sstevel@tonic-gate    response_data.length = sizeof(response);
11327c478bd9Sstevel@tonic-gate    kprompt.prompt = prompt;
11337c478bd9Sstevel@tonic-gate    kprompt.hidden = 1;
11347c478bd9Sstevel@tonic-gate    kprompt.reply = &response_data;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate    prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
11377c478bd9Sstevel@tonic-gate    krb5int_set_prompt_types(context, &prompt_type);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate    if ((retval = ((*prompter)(context, prompter_data, name,
11407c478bd9Sstevel@tonic-gate 				banner, 1, &kprompt)))) {
11417c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
11427c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
11437c478bd9Sstevel@tonic-gate 	krb5int_set_prompt_types(context, 0);
11447c478bd9Sstevel@tonic-gate 	return(retval);
11457c478bd9Sstevel@tonic-gate    }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate    krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate    /* Generate salt used by string_to_key() */
11507c478bd9Sstevel@tonic-gate    if ((salt->length == -1) && (salt->data == NULL)) {
1151*55fea89dSDan Cross 	if ((retval =
1152159d09a2SMark Phalan 	     krb5_principal2salt(context, request->client, &defsalt))) {
11537c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2(context, sc2);
11547c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2_body(context, sc2b);
11557c478bd9Sstevel@tonic-gate 	   return(retval);
11567c478bd9Sstevel@tonic-gate 	}
1157159d09a2SMark Phalan 	salt = &defsalt;
11587c478bd9Sstevel@tonic-gate    } else {
11597c478bd9Sstevel@tonic-gate 	defsalt.length = 0;
11607c478bd9Sstevel@tonic-gate    }
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate    /* Get encryption key to be used for checksum and sam_response */
11637c478bd9Sstevel@tonic-gate    if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
11647c478bd9Sstevel@tonic-gate 	/* as_key = string_to_key(password) */
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	if (as_key->length) {
11677c478bd9Sstevel@tonic-gate 	   krb5_free_keyblock_contents(context, as_key);
11687c478bd9Sstevel@tonic-gate 	   as_key->length = 0;
11697c478bd9Sstevel@tonic-gate 	}
11707c478bd9Sstevel@tonic-gate 
1171159d09a2SMark Phalan 	/* generate a key using the supplied password */
11727c478bd9Sstevel@tonic-gate 	retval = krb5_c_string_to_key(context, sc2b->sam_etype,
11737c478bd9Sstevel@tonic-gate                                    (krb5_data *)gak_data, salt, as_key);
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	if (retval) {
11767c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2(context, sc2);
11777c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2_body(context, sc2b);
11787c478bd9Sstevel@tonic-gate 	   if (defsalt.length) krb5_xfree(defsalt.data);
11797c478bd9Sstevel@tonic-gate 	   return(retval);
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 
1182159d09a2SMark Phalan 	if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
11837c478bd9Sstevel@tonic-gate 	   /* as_key = combine_key (as_key, string_to_key(SAD)) */
11847c478bd9Sstevel@tonic-gate 	   krb5_keyblock tmp_kb;
11857c478bd9Sstevel@tonic-gate 
1186159d09a2SMark Phalan 	   retval = krb5_c_string_to_key(context, sc2b->sam_etype,
11877c478bd9Sstevel@tonic-gate 				&response_data, salt, &tmp_kb);
11887c478bd9Sstevel@tonic-gate 
1189159d09a2SMark Phalan 	   if (retval) {
11907c478bd9Sstevel@tonic-gate 		krb5_free_sam_challenge_2(context, sc2);
1191159d09a2SMark Phalan 	        krb5_free_sam_challenge_2_body(context, sc2b);
11927c478bd9Sstevel@tonic-gate 		if (defsalt.length) krb5_xfree(defsalt.data);
11937c478bd9Sstevel@tonic-gate 		return(retval);
11947c478bd9Sstevel@tonic-gate 	   }
11957c478bd9Sstevel@tonic-gate 
1196159d09a2SMark Phalan 	   /* This should be a call to the crypto library some day */
11977c478bd9Sstevel@tonic-gate 	   /* key types should already match the sam_etype */
11987c478bd9Sstevel@tonic-gate 	   retval = krb5int_c_combine_keys(context, as_key, &tmp_kb, as_key);
11997c478bd9Sstevel@tonic-gate 
1200159d09a2SMark Phalan 	   if (retval) {
12017c478bd9Sstevel@tonic-gate 		krb5_free_sam_challenge_2(context, sc2);
1202159d09a2SMark Phalan 	        krb5_free_sam_challenge_2_body(context, sc2b);
12037c478bd9Sstevel@tonic-gate 		if (defsalt.length) krb5_xfree(defsalt.data);
12047c478bd9Sstevel@tonic-gate 		return(retval);
12057c478bd9Sstevel@tonic-gate 	   }
1206159d09a2SMark Phalan 	   krb5_free_keyblock_contents(context, &tmp_kb);
12077c478bd9Sstevel@tonic-gate 	}
1208159d09a2SMark Phalan 
1209159d09a2SMark Phalan 	if (defsalt.length)
12107c478bd9Sstevel@tonic-gate 	   krb5_xfree(defsalt.data);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate    } else {
12137c478bd9Sstevel@tonic-gate 	/* as_key = string_to_key(SAD) */
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	if (as_key->length) {
12167c478bd9Sstevel@tonic-gate 	   krb5_free_keyblock_contents(context, as_key);
12177c478bd9Sstevel@tonic-gate 	   as_key->length = 0;
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate 
1220159d09a2SMark Phalan 	/* generate a key using the supplied password */
12217c478bd9Sstevel@tonic-gate 	retval = krb5_c_string_to_key(context, sc2b->sam_etype,
12227c478bd9Sstevel@tonic-gate 				&response_data, salt, as_key);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	if (defsalt.length)
12257c478bd9Sstevel@tonic-gate 	   krb5_xfree(defsalt.data);
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	if (retval) {
12287c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2(context, sc2);
12297c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2_body(context, sc2b);
12307c478bd9Sstevel@tonic-gate 	   return(retval);
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate    }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate    /* Now we have a key, verify the checksum on the sam_challenge */
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate    cksum = sc2->sam_cksum;
1237*55fea89dSDan Cross 
12387c478bd9Sstevel@tonic-gate    while (*cksum) {
12397c478bd9Sstevel@tonic-gate 	/* Check this cksum */
12407c478bd9Sstevel@tonic-gate 	retval = krb5_c_verify_checksum(context, as_key,
12417c478bd9Sstevel@tonic-gate 			KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
12427c478bd9Sstevel@tonic-gate 			&sc2->sam_challenge_2_body,
12437c478bd9Sstevel@tonic-gate 			*cksum, &valid_cksum);
12447c478bd9Sstevel@tonic-gate 	if (retval) {
12457c478bd9Sstevel@tonic-gate 	   krb5_free_data(context, scratch);
12467c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2(context, sc2);
12477c478bd9Sstevel@tonic-gate 	   krb5_free_sam_challenge_2_body(context, sc2b);
12487c478bd9Sstevel@tonic-gate 	   return(retval);
12497c478bd9Sstevel@tonic-gate 	}
1250159d09a2SMark Phalan 	if (valid_cksum)
12517c478bd9Sstevel@tonic-gate 	   break;
12527c478bd9Sstevel@tonic-gate 	cksum++;
12537c478bd9Sstevel@tonic-gate    }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate    if (!valid_cksum) {
12567c478bd9Sstevel@tonic-gate 
1257159d09a2SMark Phalan 	/* If KRB5_SAM_SEND_ENCRYPTED_SAD is set, then password is only	*/
12587c478bd9Sstevel@tonic-gate 	/* source for checksum key.  Therefore, a bad checksum means a	*/
12597c478bd9Sstevel@tonic-gate 	/* bad password.  Don't give that direct feedback to someone	*/
12607c478bd9Sstevel@tonic-gate 	/* trying to brute-force passwords.				*/
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD))
12637c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
12647c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
12657c478bd9Sstevel@tonic-gate 	/*
1266159d09a2SMark Phalan 	 * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
12677c478bd9Sstevel@tonic-gate 	 * can interpret that as "password incorrect", which is probably
12687c478bd9Sstevel@tonic-gate 	 * the best error we can return in this situation.
12697c478bd9Sstevel@tonic-gate 	 */
12707c478bd9Sstevel@tonic-gate 	return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
12717c478bd9Sstevel@tonic-gate    }
1272*55fea89dSDan Cross 
12737c478bd9Sstevel@tonic-gate    /* fill in enc_sam_response_enc_2 */
12747c478bd9Sstevel@tonic-gate    enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
12757c478bd9Sstevel@tonic-gate    enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
12767c478bd9Sstevel@tonic-gate    if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
12777c478bd9Sstevel@tonic-gate 	enc_sam_response_enc_2.sam_sad = response_data;
12787c478bd9Sstevel@tonic-gate    } else {
12797c478bd9Sstevel@tonic-gate 	enc_sam_response_enc_2.sam_sad.data = NULL;
12807c478bd9Sstevel@tonic-gate 	enc_sam_response_enc_2.sam_sad.length = 0;
12817c478bd9Sstevel@tonic-gate    }
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate    /* encode and encrypt enc_sam_response_enc_2 with as_key */
12847c478bd9Sstevel@tonic-gate    retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
12857c478bd9Sstevel@tonic-gate 		&scratch);
12867c478bd9Sstevel@tonic-gate    if (retval) {
12877c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
12887c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
12897c478bd9Sstevel@tonic-gate 	return(retval);
12907c478bd9Sstevel@tonic-gate    }
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate    /* Fill in sam_response_2 */
12937c478bd9Sstevel@tonic-gate    memset(&sr2, 0, sizeof(sr2));
12947c478bd9Sstevel@tonic-gate    sr2.sam_type = sc2b->sam_type;
12957c478bd9Sstevel@tonic-gate    sr2.sam_flags = sc2b->sam_flags;
12967c478bd9Sstevel@tonic-gate    sr2.sam_track_id = sc2b->sam_track_id;
12977c478bd9Sstevel@tonic-gate    sr2.sam_nonce = sc2b->sam_nonce;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate    /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded	*/
13007c478bd9Sstevel@tonic-gate    /* enc_sam_response_enc_2 from above */
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate    retval = krb5_c_encrypt_length(context, as_key->enctype, scratch->length,
1303159d09a2SMark Phalan 				  &ciph_len);
13047c478bd9Sstevel@tonic-gate    if (retval) {
13057c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
13067c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
13077c478bd9Sstevel@tonic-gate 	return(retval);
13087c478bd9Sstevel@tonic-gate    }
13097c478bd9Sstevel@tonic-gate    sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate    sr2.sam_enc_nonce_or_sad.ciphertext.data =
13127c478bd9Sstevel@tonic-gate 	(char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate    if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
13157c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
13167c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
13177c478bd9Sstevel@tonic-gate 	return(ENOMEM);
13187c478bd9Sstevel@tonic-gate    }
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate    retval = krb5_c_encrypt(context, as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE,
13217c478bd9Sstevel@tonic-gate 		NULL, scratch, &sr2.sam_enc_nonce_or_sad);
13227c478bd9Sstevel@tonic-gate    if (retval) {
13237c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2(context, sc2);
13247c478bd9Sstevel@tonic-gate 	krb5_free_sam_challenge_2_body(context, sc2b);
13257c478bd9Sstevel@tonic-gate 	krb5_free_data(context, scratch);
13267c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
13277c478bd9Sstevel@tonic-gate 	return(retval);
13287c478bd9Sstevel@tonic-gate    }
13297c478bd9Sstevel@tonic-gate    krb5_free_data(context, scratch);
13307c478bd9Sstevel@tonic-gate    scratch = NULL;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate    /* Encode the sam_response_2 */
13337c478bd9Sstevel@tonic-gate    retval = encode_krb5_sam_response_2(&sr2, &scratch);
13347c478bd9Sstevel@tonic-gate    krb5_free_sam_challenge_2(context, sc2);
13357c478bd9Sstevel@tonic-gate    krb5_free_sam_challenge_2_body(context, sc2b);
13367c478bd9Sstevel@tonic-gate    krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate    if (retval) {
13397c478bd9Sstevel@tonic-gate 	return (retval);
13407c478bd9Sstevel@tonic-gate    }
13417c478bd9Sstevel@tonic-gate 
1342159d09a2SMark Phalan    /* Almost there, just need to make padata !  */
13437c478bd9Sstevel@tonic-gate    sam_padata = malloc(sizeof(krb5_pa_data));
13447c478bd9Sstevel@tonic-gate    if (sam_padata == NULL) {
13457c478bd9Sstevel@tonic-gate 	krb5_free_data(context, scratch);
13467c478bd9Sstevel@tonic-gate 	return(ENOMEM);
13477c478bd9Sstevel@tonic-gate    }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate    sam_padata->magic = KV5M_PA_DATA;
13507c478bd9Sstevel@tonic-gate    sam_padata->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
13517c478bd9Sstevel@tonic-gate    sam_padata->length = scratch->length;
13527c478bd9Sstevel@tonic-gate    sam_padata->contents = (krb5_octet *) scratch->data;
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate    *out_padata = sam_padata;
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate    return(0);
13577c478bd9Sstevel@tonic-gate }
13587c478bd9Sstevel@tonic-gate 
1359159d09a2SMark Phalan static const pa_types_t pa_types[] = {
13607c478bd9Sstevel@tonic-gate     {
13617c478bd9Sstevel@tonic-gate 	KRB5_PADATA_PW_SALT,
13627c478bd9Sstevel@tonic-gate 	pa_salt,
13637c478bd9Sstevel@tonic-gate 	PA_INFO,
13647c478bd9Sstevel@tonic-gate     },
13657c478bd9Sstevel@tonic-gate     {
13667c478bd9Sstevel@tonic-gate 	KRB5_PADATA_AFS3_SALT,
13677c478bd9Sstevel@tonic-gate 	pa_salt,
13687c478bd9Sstevel@tonic-gate 	PA_INFO,
13697c478bd9Sstevel@tonic-gate     },
13707c478bd9Sstevel@tonic-gate     {
13717c478bd9Sstevel@tonic-gate 	KRB5_PADATA_ENC_TIMESTAMP,
13727c478bd9Sstevel@tonic-gate 	pa_enc_timestamp,
13737c478bd9Sstevel@tonic-gate 	PA_REAL,
13747c478bd9Sstevel@tonic-gate     },
13757c478bd9Sstevel@tonic-gate     {
1376159d09a2SMark Phalan 	KRB5_PADATA_SAM_CHALLENGE_2,
13777c478bd9Sstevel@tonic-gate 	pa_sam_2,
13787c478bd9Sstevel@tonic-gate 	PA_REAL,
13797c478bd9Sstevel@tonic-gate     },
13807c478bd9Sstevel@tonic-gate     {
13817c478bd9Sstevel@tonic-gate 	KRB5_PADATA_SAM_CHALLENGE,
13827c478bd9Sstevel@tonic-gate 	pa_sam,
13837c478bd9Sstevel@tonic-gate 	PA_REAL,
13847c478bd9Sstevel@tonic-gate     },
13857c478bd9Sstevel@tonic-gate     {
13867c478bd9Sstevel@tonic-gate 	-1,
13877c478bd9Sstevel@tonic-gate 	NULL,
13887c478bd9Sstevel@tonic-gate 	0,
13897c478bd9Sstevel@tonic-gate     },
13907c478bd9Sstevel@tonic-gate };
13917c478bd9Sstevel@tonic-gate 
1392159d09a2SMark Phalan /*
1393159d09a2SMark Phalan  * If one of the modules can adjust its AS_REQ data using the contents of the
1394159d09a2SMark Phalan  * err_reply, return 0.  If it's the sort of correction which requires that we
1395159d09a2SMark Phalan  * ask the user another question, we let the calling application deal with it.
1396159d09a2SMark Phalan  */
1397159d09a2SMark Phalan 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)1398159d09a2SMark Phalan krb5_do_preauth_tryagain(krb5_context kcontext,
1399159d09a2SMark Phalan 			 krb5_kdc_req *request,
1400159d09a2SMark Phalan 			 krb5_data *encoded_request_body,
1401159d09a2SMark Phalan 			 krb5_data *encoded_previous_request,
1402159d09a2SMark Phalan 			 krb5_pa_data **padata,
1403159d09a2SMark Phalan 			 krb5_pa_data ***return_padata,
1404159d09a2SMark Phalan 			 krb5_error *err_reply,
1405159d09a2SMark Phalan 			 krb5_data *salt, krb5_data *s2kparams,
1406159d09a2SMark Phalan 			 krb5_enctype *etype,
1407159d09a2SMark Phalan 			 krb5_keyblock *as_key,
1408159d09a2SMark Phalan 			 krb5_prompter_fct prompter, void *prompter_data,
1409159d09a2SMark Phalan 			 krb5_gic_get_as_key_fct gak_fct, void *gak_data,
1410159d09a2SMark Phalan 			 krb5_preauth_client_rock *get_data_rock,
1411159d09a2SMark Phalan 			 krb5_gic_opt_ext *opte)
1412159d09a2SMark Phalan {
1413159d09a2SMark Phalan     krb5_error_code ret;
1414159d09a2SMark Phalan     krb5_pa_data **out_padata;
1415159d09a2SMark Phalan     krb5_preauth_context *context;
1416159d09a2SMark Phalan     struct _krb5_preauth_context_module *module;
1417159d09a2SMark Phalan     int i, j;
1418159d09a2SMark Phalan     int out_pa_list_size = 0;
1419159d09a2SMark Phalan 
1420159d09a2SMark Phalan     ret = KRB5KRB_ERR_GENERIC;
1421159d09a2SMark Phalan     if (kcontext->preauth_context == NULL) {
1422159d09a2SMark Phalan        return KRB5KRB_ERR_GENERIC;
1423159d09a2SMark Phalan     }
1424159d09a2SMark Phalan     context = kcontext->preauth_context;
1425159d09a2SMark Phalan     if (context == NULL) {
1426159d09a2SMark Phalan        return KRB5KRB_ERR_GENERIC;
1427159d09a2SMark Phalan     }
1428159d09a2SMark Phalan 
1429159d09a2SMark Phalan     for (i = 0; padata[i] != NULL && padata[i]->pa_type != 0; i++) {
1430159d09a2SMark Phalan 	out_padata = NULL;
1431159d09a2SMark Phalan 	for (j = 0; j < context->n_modules; j++) {
1432159d09a2SMark Phalan 	    module = &context->modules[j];
1433159d09a2SMark Phalan 	    if (module->pa_type != padata[i]->pa_type) {
1434159d09a2SMark Phalan 		continue;
1435159d09a2SMark Phalan 	    }
1436159d09a2SMark Phalan 	    if (module->client_tryagain == NULL) {
1437159d09a2SMark Phalan 		continue;
1438159d09a2SMark Phalan 	    }
1439159d09a2SMark Phalan 	    if ((*module->client_tryagain)(kcontext,
1440159d09a2SMark Phalan 					   module->plugin_context,
1441159d09a2SMark Phalan 					   *module->request_context_pp,
1442159d09a2SMark Phalan 					   (krb5_get_init_creds_opt *)opte,
1443159d09a2SMark Phalan 					   client_data_proc,
1444159d09a2SMark Phalan 					   get_data_rock,
1445159d09a2SMark Phalan 					   request,
1446159d09a2SMark Phalan 					   encoded_request_body,
1447159d09a2SMark Phalan 					   encoded_previous_request,
1448159d09a2SMark Phalan 					   padata[i],
1449159d09a2SMark Phalan 					   err_reply,
1450159d09a2SMark Phalan 					   prompter, prompter_data,
1451159d09a2SMark Phalan 					   gak_fct, gak_data, salt, s2kparams,
1452159d09a2SMark Phalan 					   as_key,
1453159d09a2SMark Phalan 					   &out_padata) == 0) {
1454159d09a2SMark Phalan 		if (out_padata != NULL) {
1455159d09a2SMark Phalan 		    int k;
1456159d09a2SMark Phalan 		    for (k = 0; out_padata[k] != NULL; k++);
1457159d09a2SMark Phalan 		    grow_pa_list(return_padata, &out_pa_list_size,
1458159d09a2SMark Phalan 				 out_padata, k);
1459159d09a2SMark Phalan 		    free(out_padata);
1460159d09a2SMark Phalan 		    return 0;
1461159d09a2SMark Phalan 		}
1462159d09a2SMark Phalan 	    }
1463159d09a2SMark Phalan 	}
1464159d09a2SMark Phalan     }
1465159d09a2SMark Phalan     return ret;
1466159d09a2SMark Phalan }
1467159d09a2SMark Phalan 
1468159d09a2SMark Phalan 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)14697c478bd9Sstevel@tonic-gate krb5_do_preauth(krb5_context context,
14707c478bd9Sstevel@tonic-gate 		krb5_kdc_req *request,
1471159d09a2SMark Phalan 		krb5_data *encoded_request_body,
1472159d09a2SMark Phalan 		krb5_data *encoded_previous_request,
14737c478bd9Sstevel@tonic-gate 		krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
14747c478bd9Sstevel@tonic-gate 		krb5_data *salt, krb5_data *s2kparams,
14757c478bd9Sstevel@tonic-gate 		krb5_enctype *etype,
14767c478bd9Sstevel@tonic-gate 		krb5_keyblock *as_key,
14777c478bd9Sstevel@tonic-gate 		krb5_prompter_fct prompter, void *prompter_data,
1478159d09a2SMark Phalan 		krb5_gic_get_as_key_fct gak_fct, void *gak_data,
1479159d09a2SMark Phalan 		krb5_preauth_client_rock *get_data_rock,
1480159d09a2SMark Phalan 		krb5_gic_opt_ext *opte)
14817c478bd9Sstevel@tonic-gate {
14827c478bd9Sstevel@tonic-gate     int h, i, j, out_pa_list_size;
14837c478bd9Sstevel@tonic-gate     int seen_etype_info2 = 0;
14847c478bd9Sstevel@tonic-gate     krb5_pa_data *out_pa = NULL, **out_pa_list = NULL;
14857c478bd9Sstevel@tonic-gate     krb5_data scratch;
14867c478bd9Sstevel@tonic-gate     krb5_etype_info etype_info = NULL;
14877c478bd9Sstevel@tonic-gate     krb5_error_code ret;
14887c478bd9Sstevel@tonic-gate     static const int paorder[] = { PA_INFO, PA_REAL };
14897c478bd9Sstevel@tonic-gate     int realdone;
14907c478bd9Sstevel@tonic-gate 
1491159d09a2SMark Phalan     /* Solaris Kerberos */
14927c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() start");
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate     if (in_padata == NULL) {
14957c478bd9Sstevel@tonic-gate 	*out_padata = NULL;
14967c478bd9Sstevel@tonic-gate 	return(0);
14977c478bd9Sstevel@tonic-gate     }
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate #ifdef DEBUG
1500159d09a2SMark Phalan     /* Solaris Kerberos */
15017c478bd9Sstevel@tonic-gate     if (salt && salt->data && salt->length > 0) {
15027c478bd9Sstevel@tonic-gate     	fprintf (stderr, "salt len=%d", salt->length);
1503159d09a2SMark Phalan 	    if ((int) salt->length > 0)
15047c478bd9Sstevel@tonic-gate 		fprintf (stderr, " '%*s'", salt->length, salt->data);
15057c478bd9Sstevel@tonic-gate 	    fprintf (stderr, "; preauth data types:");
15067c478bd9Sstevel@tonic-gate 	    for (i = 0; in_padata[i]; i++) {
15077c478bd9Sstevel@tonic-gate 		fprintf (stderr, " %d", in_padata[i]->pa_type);
15087c478bd9Sstevel@tonic-gate     	}
15097c478bd9Sstevel@tonic-gate     	fprintf (stderr, "\n");
15107c478bd9Sstevel@tonic-gate     }
15117c478bd9Sstevel@tonic-gate #endif
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate     out_pa_list = NULL;
15147c478bd9Sstevel@tonic-gate     out_pa_list_size = 0;
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate     /* first do all the informational preauths, then the first real one */
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate     for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) {
15197c478bd9Sstevel@tonic-gate 	realdone = 0;
15207c478bd9Sstevel@tonic-gate 	for (i=0; in_padata[i] && !realdone; i++) {
15217c478bd9Sstevel@tonic-gate 	    int k, l, etype_found, valid_etype_found;
15227c478bd9Sstevel@tonic-gate 	    /*
15237c478bd9Sstevel@tonic-gate 	     * This is really gross, but is necessary to prevent
1524159d09a2SMark Phalan 	     * lossage when talking to a 1.0.x KDC, which returns an
15257c478bd9Sstevel@tonic-gate 	     * erroneous PA-PW-SALT when it returns a KRB-ERROR
15267c478bd9Sstevel@tonic-gate 	     * requiring additional preauth.
15277c478bd9Sstevel@tonic-gate 	     */
15287c478bd9Sstevel@tonic-gate 	    switch (in_padata[i]->pa_type) {
15297c478bd9Sstevel@tonic-gate 	    case KRB5_PADATA_ETYPE_INFO:
15307c478bd9Sstevel@tonic-gate 	    case KRB5_PADATA_ETYPE_INFO2:
15317c478bd9Sstevel@tonic-gate 	    {
15327c478bd9Sstevel@tonic-gate 		krb5_preauthtype pa_type = in_padata[i]->pa_type;
15337c478bd9Sstevel@tonic-gate 		if (etype_info) {
15347c478bd9Sstevel@tonic-gate 		    if (seen_etype_info2 || pa_type != KRB5_PADATA_ETYPE_INFO2)
15357c478bd9Sstevel@tonic-gate 			continue;
15367c478bd9Sstevel@tonic-gate 		    if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1537159d09a2SMark Phalan 			krb5_free_etype_info( context, etype_info);
15387c478bd9Sstevel@tonic-gate 			etype_info = NULL;
1539159d09a2SMark Phalan 		    }
15407c478bd9Sstevel@tonic-gate 		}
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 		scratch.length = in_padata[i]->length;
15437c478bd9Sstevel@tonic-gate 		scratch.data = (char *) in_padata[i]->contents;
15447c478bd9Sstevel@tonic-gate 		if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1545159d09a2SMark Phalan 		    seen_etype_info2++;
1546159d09a2SMark Phalan 		    ret = decode_krb5_etype_info2(&scratch, &etype_info);
15477c478bd9Sstevel@tonic-gate 		}
15487c478bd9Sstevel@tonic-gate 		else ret = decode_krb5_etype_info(&scratch, &etype_info);
15497c478bd9Sstevel@tonic-gate 		if (ret) {
1550159d09a2SMark Phalan 		    ret = 0; /*Ignore error and etype_info element*/
1551*55fea89dSDan Cross 		    if (etype_info)
1552159d09a2SMark Phalan 		      krb5_free_etype_info( context, etype_info);
1553159d09a2SMark Phalan 		    etype_info = NULL;
1554159d09a2SMark Phalan 		    continue;
15557c478bd9Sstevel@tonic-gate 		}
15567c478bd9Sstevel@tonic-gate 		if (etype_info[0] == NULL) {
15577c478bd9Sstevel@tonic-gate 		    krb5_free_etype_info(context, etype_info);
15587c478bd9Sstevel@tonic-gate 		    etype_info = NULL;
15597c478bd9Sstevel@tonic-gate 		    break;
15607c478bd9Sstevel@tonic-gate 		}
15617c478bd9Sstevel@tonic-gate 		/*
15627c478bd9Sstevel@tonic-gate 		 * Select first etype in our request which is also in
15637c478bd9Sstevel@tonic-gate 		 * etype-info (preferring client request ktype order).
15647c478bd9Sstevel@tonic-gate 		 */
15657c478bd9Sstevel@tonic-gate 		for (etype_found = 0, valid_etype_found = 0, k = 0;
1566159d09a2SMark Phalan 		     !etype_found && k < request->nktypes; k++) {
15677c478bd9Sstevel@tonic-gate 		    for (l = 0; etype_info[l]; l++) {
15687c478bd9Sstevel@tonic-gate 			if (etype_info[l]->etype == request->ktype[k]) {
15697c478bd9Sstevel@tonic-gate 			    etype_found++;
15707c478bd9Sstevel@tonic-gate 			    break;
15717c478bd9Sstevel@tonic-gate 			}
15727c478bd9Sstevel@tonic-gate 			/* check if program has support for this etype for more
15737c478bd9Sstevel@tonic-gate 			 * precise error reporting.
15747c478bd9Sstevel@tonic-gate 			 */
15757c478bd9Sstevel@tonic-gate 			if (valid_enctype(etype_info[l]->etype))
15767c478bd9Sstevel@tonic-gate 			    valid_etype_found++;
15777c478bd9Sstevel@tonic-gate 		    }
15787c478bd9Sstevel@tonic-gate 		}
15797c478bd9Sstevel@tonic-gate 		if (!etype_found) {
1580159d09a2SMark Phalan 		    /* Solaris Kerberos */
15817c478bd9Sstevel@tonic-gate 		    KRB5_LOG(KRB5_ERR, "error !etype_found, "
15827c478bd9Sstevel@tonic-gate 				"valid_etype_found = %d",
1583*55fea89dSDan Cross 				valid_etype_found);
1584159d09a2SMark Phalan 		  if (valid_etype_found) {
15857c478bd9Sstevel@tonic-gate 			/* supported enctype but not requested */
1586159d09a2SMark Phalan 		    ret =  KRB5_CONFIG_ETYPE_NOSUPP;
1587159d09a2SMark Phalan 		    goto cleanup;
1588159d09a2SMark Phalan 		  }
1589159d09a2SMark Phalan 		  else {
1590159d09a2SMark Phalan 		    /* unsupported enctype */
1591159d09a2SMark Phalan 		    ret =  KRB5_PROG_ETYPE_NOSUPP;
1592159d09a2SMark Phalan 		    goto cleanup;
1593159d09a2SMark Phalan 		  }
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 		}
15967c478bd9Sstevel@tonic-gate 		scratch.data = (char *) etype_info[l]->salt;
15977c478bd9Sstevel@tonic-gate 		scratch.length = etype_info[l]->length;
15987c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, salt);
1599*55fea89dSDan Cross 		if (scratch.length == KRB5_ETYPE_NO_SALT)
16007c478bd9Sstevel@tonic-gate 		  salt->data = NULL;
16017c478bd9Sstevel@tonic-gate 		else
1602159d09a2SMark Phalan 		    if ((ret = krb5int_copy_data_contents( context, &scratch, salt)) != 0)
1603159d09a2SMark Phalan 		  goto cleanup;
16047c478bd9Sstevel@tonic-gate 		*etype = etype_info[l]->etype;
16057c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, s2kparams);
16067c478bd9Sstevel@tonic-gate 		if ((ret = krb5int_copy_data_contents(context,
1607159d09a2SMark Phalan 						      &etype_info[l]->s2kparams,
1608159d09a2SMark Phalan 						      s2kparams)) != 0)
16097c478bd9Sstevel@tonic-gate 		  goto cleanup;
1610159d09a2SMark Phalan #ifdef DEBUG
1611159d09a2SMark Phalan 		for (j = 0; etype_info[j]; j++) {
1612159d09a2SMark Phalan 		    krb5_etype_info_entry *e = etype_info[j];
1613159d09a2SMark Phalan 		    fprintf (stderr, "etype info %d: etype %d salt len=%d",
1614159d09a2SMark Phalan 			     j, e->etype, e->length);
1615159d09a2SMark Phalan 		    if (e->length > 0 && e->length != KRB5_ETYPE_NO_SALT)
1616159d09a2SMark Phalan 			fprintf (stderr, " '%.*s'", e->length, e->salt);
1617159d09a2SMark Phalan 		    fprintf (stderr, "\n");
1618159d09a2SMark Phalan 		}
1619159d09a2SMark Phalan #endif
16207c478bd9Sstevel@tonic-gate 		break;
16217c478bd9Sstevel@tonic-gate 	    }
16227c478bd9Sstevel@tonic-gate 	    case KRB5_PADATA_PW_SALT:
16237c478bd9Sstevel@tonic-gate 	    case KRB5_PADATA_AFS3_SALT:
16247c478bd9Sstevel@tonic-gate 		if (etype_info)
16257c478bd9Sstevel@tonic-gate 		    continue;
16267c478bd9Sstevel@tonic-gate 		break;
16277c478bd9Sstevel@tonic-gate 	    default:
16287c478bd9Sstevel@tonic-gate 		;
16297c478bd9Sstevel@tonic-gate 	    }
1630159d09a2SMark Phalan 	    /* Try the internally-provided preauth type list. */
1631159d09a2SMark Phalan 	    if (!realdone) for (j=0; pa_types[j].type >= 0; j++) {
16327c478bd9Sstevel@tonic-gate 		if ((in_padata[i]->pa_type == pa_types[j].type) &&
16337c478bd9Sstevel@tonic-gate 		    (pa_types[j].flags & paorder[h])) {
1634159d09a2SMark Phalan #ifdef DEBUG
1635159d09a2SMark Phalan 		    fprintf (stderr, "calling internal function for pa_type "
1636159d09a2SMark Phalan 			     "%d, flag %d\n", pa_types[j].type, paorder[h]);
1637159d09a2SMark Phalan #endif
16387c478bd9Sstevel@tonic-gate 		    out_pa = NULL;
16397c478bd9Sstevel@tonic-gate 
1640505d05c7Sgtb 		    if ((ret = ((*pa_types[j].fct)(context, request,
1641159d09a2SMark Phalan 						   in_padata[i], &out_pa,
1642159d09a2SMark Phalan 						   salt, s2kparams, etype, as_key,
1643159d09a2SMark Phalan 						   prompter, prompter_data,
1644159d09a2SMark Phalan 						   gak_fct, gak_data)))) {
1645159d09a2SMark Phalan 		      goto cleanup;
16467c478bd9Sstevel@tonic-gate 		    }
16477c478bd9Sstevel@tonic-gate 
1648159d09a2SMark Phalan 		    ret = grow_pa_list(&out_pa_list, &out_pa_list_size,
1649159d09a2SMark Phalan 				       &out_pa, 1);
1650159d09a2SMark Phalan 		    if (ret != 0) {
1651159d09a2SMark Phalan 			    goto cleanup;
16527c478bd9Sstevel@tonic-gate 		    }
16537c478bd9Sstevel@tonic-gate 		    if (paorder[h] == PA_REAL)
16547c478bd9Sstevel@tonic-gate 			realdone = 1;
16557c478bd9Sstevel@tonic-gate 		}
16567c478bd9Sstevel@tonic-gate 	    }
1657159d09a2SMark Phalan 
1658159d09a2SMark Phalan 	    /* Try to use plugins now. */
1659159d09a2SMark Phalan 	    if (!realdone) {
1660159d09a2SMark Phalan 		krb5_init_preauth_context(context);
1661159d09a2SMark Phalan 		if (context->preauth_context != NULL) {
1662159d09a2SMark Phalan 		    int module_ret, module_flags;
1663159d09a2SMark Phalan #ifdef DEBUG
1664159d09a2SMark Phalan 		    fprintf (stderr, "trying modules for pa_type %d, flag %d\n",
1665159d09a2SMark Phalan 			     in_padata[i]->pa_type, paorder[h]);
1666159d09a2SMark Phalan #endif
1667159d09a2SMark Phalan 		    ret = krb5_run_preauth_plugins(context,
1668159d09a2SMark Phalan 						   paorder[h],
1669159d09a2SMark Phalan 						   request,
1670159d09a2SMark Phalan 						   encoded_request_body,
1671159d09a2SMark Phalan 						   encoded_previous_request,
1672159d09a2SMark Phalan 						   in_padata[i],
1673159d09a2SMark Phalan 						   prompter,
1674159d09a2SMark Phalan 						   prompter_data,
1675159d09a2SMark Phalan 						   gak_fct,
1676159d09a2SMark Phalan 						   salt, s2kparams,
1677159d09a2SMark Phalan 						   gak_data,
1678159d09a2SMark Phalan 						   get_data_rock,
1679159d09a2SMark Phalan 						   as_key,
1680159d09a2SMark Phalan 						   &out_pa_list,
1681159d09a2SMark Phalan 						   &out_pa_list_size,
1682159d09a2SMark Phalan 						   &module_ret,
1683159d09a2SMark Phalan 						   &module_flags,
1684159d09a2SMark Phalan 						   opte);
1685159d09a2SMark Phalan 		    if (ret == 0) {
1686159d09a2SMark Phalan 			if (module_ret == 0) {
1687159d09a2SMark Phalan 		            if (paorder[h] == PA_REAL) {
1688159d09a2SMark Phalan 				realdone = 1;
1689159d09a2SMark Phalan 			    }
1690159d09a2SMark Phalan 			}
1691159d09a2SMark Phalan 		    }
1692159d09a2SMark Phalan 		}
1693159d09a2SMark Phalan 	    }
16947c478bd9Sstevel@tonic-gate 	}
16957c478bd9Sstevel@tonic-gate     }
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate     *out_padata = out_pa_list;
16987c478bd9Sstevel@tonic-gate     if (etype_info)
1699159d09a2SMark Phalan       krb5_free_etype_info(context, etype_info);
1700*55fea89dSDan Cross 
1701159d09a2SMark Phalan     /* Solaris Kerberos */
17027c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() end");
17037c478bd9Sstevel@tonic-gate     return(0);
1704159d09a2SMark Phalan  cleanup:
17057c478bd9Sstevel@tonic-gate     if (out_pa_list) {
1706159d09a2SMark Phalan       out_pa_list[out_pa_list_size++] = NULL;
1707159d09a2SMark Phalan       krb5_free_pa_data(context, out_pa_list);
17087c478bd9Sstevel@tonic-gate     }
17097c478bd9Sstevel@tonic-gate     if (etype_info)
1710159d09a2SMark Phalan       krb5_free_etype_info(context, etype_info);
17117c478bd9Sstevel@tonic-gate 
1712159d09a2SMark Phalan     /* Solaris Kerberos */
17137c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() end");
17147c478bd9Sstevel@tonic-gate     return (ret);
17157c478bd9Sstevel@tonic-gate }
1716