17c478bd9Sstevel@tonic-gate /*
2ba7b222eSGlenn Barry * Copyright 2009 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 /*
87c478bd9Sstevel@tonic-gate * kdc/kdc_preauth.c
97c478bd9Sstevel@tonic-gate *
1056a424ccSmp * Copyright 1995, 2003 by the Massachusetts Institute of Technology.
117c478bd9Sstevel@tonic-gate * All Rights Reserved.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may
147c478bd9Sstevel@tonic-gate * require a specific license from the United States Government.
157c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
167c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting.
17*55fea89dSDan Cross *
187c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
197c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
207c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
217c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
227c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
237c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
247c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior
257c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
267c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a
277c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
287c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
297c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
307c478bd9Sstevel@tonic-gate * or implied warranty.
31*55fea89dSDan Cross *
327c478bd9Sstevel@tonic-gate * Preauthentication routines for the KDC.
337c478bd9Sstevel@tonic-gate */
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC.
37*55fea89dSDan Cross *
387c478bd9Sstevel@tonic-gate * All rights reserved.
39*55fea89dSDan Cross *
407c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may require
417c478bd9Sstevel@tonic-gate * a specific license from the United States Government. It is the
427c478bd9Sstevel@tonic-gate * responsibility of any person or organization contemplating export to
437c478bd9Sstevel@tonic-gate * obtain such a license before exporting.
44*55fea89dSDan Cross *
457c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
467c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
477c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
487c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
497c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
507c478bd9Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining
517c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior
527c478bd9Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of
537c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
547c478bd9Sstevel@tonic-gate * or implied warranty.
55*55fea89dSDan Cross *
567c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
577c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
587c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
597c478bd9Sstevel@tonic-gate */
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate #include "k5-int.h"
627c478bd9Sstevel@tonic-gate #include "kdc_util.h"
637c478bd9Sstevel@tonic-gate #include "extern.h"
647c478bd9Sstevel@tonic-gate #include "com_err.h"
657c478bd9Sstevel@tonic-gate #include <assert.h>
667c478bd9Sstevel@tonic-gate #include <stdio.h>
6756a424ccSmp #include "adm_proto.h"
687c478bd9Sstevel@tonic-gate #include <libintl.h>
697c478bd9Sstevel@tonic-gate #include <syslog.h>
707c478bd9Sstevel@tonic-gate
7156a424ccSmp #include <assert.h>
72159d09a2SMark Phalan #include "preauth_plugin.h"
73159d09a2SMark Phalan
74159d09a2SMark Phalan #if TARGET_OS_MAC
75159d09a2SMark Phalan static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/preauth", NULL }; /* should be a list */
76159d09a2SMark Phalan #else
77159d09a2SMark Phalan static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL };
78159d09a2SMark Phalan #endif
7956a424ccSmp
8056a424ccSmp /* XXX This is ugly and should be in a header file somewhere */
8156a424ccSmp #ifndef KRB5INT_DES_TYPES_DEFINED
8256a424ccSmp #define KRB5INT_DES_TYPES_DEFINED
8356a424ccSmp typedef unsigned char des_cblock[8]; /* crypto-block size */
8456a424ccSmp #endif
8556a424ccSmp typedef des_cblock mit_des_cblock;
8656a424ccSmp extern void mit_des_fixup_key_parity (mit_des_cblock );
8756a424ccSmp extern int mit_des_is_weak_key (mit_des_cblock );
8856a424ccSmp
897c478bd9Sstevel@tonic-gate typedef struct _krb5_preauth_systems {
90159d09a2SMark Phalan const char *name;
917c478bd9Sstevel@tonic-gate int type;
927c478bd9Sstevel@tonic-gate int flags;
93159d09a2SMark Phalan void *plugin_context;
94159d09a2SMark Phalan preauth_server_init_proc init;
95159d09a2SMark Phalan preauth_server_fini_proc fini;
96159d09a2SMark Phalan preauth_server_edata_proc get_edata;
97159d09a2SMark Phalan preauth_server_verify_proc verify_padata;
98159d09a2SMark Phalan preauth_server_return_proc return_padata;
99159d09a2SMark Phalan preauth_server_free_reqcontext_proc free_pa_reqctx;
1007c478bd9Sstevel@tonic-gate } krb5_preauth_systems;
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate static krb5_error_code verify_enc_timestamp
1037c478bd9Sstevel@tonic-gate (krb5_context, krb5_db_entry *client,
104159d09a2SMark Phalan krb5_data *req_pkt,
10556a424ccSmp krb5_kdc_req *request,
106159d09a2SMark Phalan krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data,
107159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
108159d09a2SMark Phalan void *pa_system_context,
109159d09a2SMark Phalan void **pa_request_context,
110159d09a2SMark Phalan krb5_data **e_data,
111159d09a2SMark Phalan krb5_authdata ***authz_data);
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate static krb5_error_code get_etype_info
1147c478bd9Sstevel@tonic-gate (krb5_context, krb5_kdc_req *request,
11556a424ccSmp krb5_db_entry *client, krb5_db_entry *server,
116159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
117159d09a2SMark Phalan void *pa_system_context,
11856a424ccSmp krb5_pa_data *data);
1197c478bd9Sstevel@tonic-gate static krb5_error_code
1207c478bd9Sstevel@tonic-gate get_etype_info2(krb5_context context, krb5_kdc_req *request,
121159d09a2SMark Phalan krb5_db_entry *client, krb5_db_entry *server,
122159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
123159d09a2SMark Phalan void *pa_system_context,
124159d09a2SMark Phalan krb5_pa_data *pa_data);
125159d09a2SMark Phalan static krb5_error_code
126*55fea89dSDan Cross etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
127159d09a2SMark Phalan krb5_db_entry *client,
128159d09a2SMark Phalan krb5_kdc_req *request, krb5_kdc_rep *reply,
129159d09a2SMark Phalan krb5_key_data *client_key,
130159d09a2SMark Phalan krb5_keyblock *encrypting_key,
131159d09a2SMark Phalan krb5_pa_data **send_pa,
132159d09a2SMark Phalan int etype_info2);
133159d09a2SMark Phalan
134159d09a2SMark Phalan static krb5_error_code
135*55fea89dSDan Cross return_etype_info(krb5_context, krb5_pa_data * padata,
136159d09a2SMark Phalan krb5_db_entry *client,
137159d09a2SMark Phalan krb5_data *req_pkt,
138159d09a2SMark Phalan krb5_kdc_req *request, krb5_kdc_rep *reply,
139159d09a2SMark Phalan krb5_key_data *client_key,
140159d09a2SMark Phalan krb5_keyblock *encrypting_key,
141159d09a2SMark Phalan krb5_pa_data **send_pa,
142159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
143159d09a2SMark Phalan void *pa_system_context,
144159d09a2SMark Phalan void **pa_request_context);
145159d09a2SMark Phalan
1467c478bd9Sstevel@tonic-gate static krb5_error_code
147*55fea89dSDan Cross return_etype_info2(krb5_context, krb5_pa_data * padata,
14856a424ccSmp krb5_db_entry *client,
149159d09a2SMark Phalan krb5_data *req_pkt,
15056a424ccSmp krb5_kdc_req *request, krb5_kdc_rep *reply,
15156a424ccSmp krb5_key_data *client_key,
15256a424ccSmp krb5_keyblock *encrypting_key,
153159d09a2SMark Phalan krb5_pa_data **send_pa,
154159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
155159d09a2SMark Phalan void *pa_system_context,
156159d09a2SMark Phalan void **pa_request_context);
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate static krb5_error_code return_pw_salt
159*55fea89dSDan Cross (krb5_context, krb5_pa_data * padata,
16056a424ccSmp krb5_db_entry *client,
161159d09a2SMark Phalan krb5_data *req_pkt,
16256a424ccSmp krb5_kdc_req *request, krb5_kdc_rep *reply,
16356a424ccSmp krb5_key_data *client_key,
16456a424ccSmp krb5_keyblock *encrypting_key,
165159d09a2SMark Phalan krb5_pa_data **send_pa,
166159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
167159d09a2SMark Phalan void *pa_system_context,
168159d09a2SMark Phalan void **pa_request_context);
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate /* SAM preauth support */
1717c478bd9Sstevel@tonic-gate static krb5_error_code verify_sam_response
17256a424ccSmp (krb5_context, krb5_db_entry *client,
173159d09a2SMark Phalan krb5_data *req_pkt,
17456a424ccSmp krb5_kdc_req *request,
175159d09a2SMark Phalan krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data,
176159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
177159d09a2SMark Phalan void *pa_module_context,
178159d09a2SMark Phalan void **pa_request_context,
179159d09a2SMark Phalan krb5_data **e_data,
180159d09a2SMark Phalan krb5_authdata ***authz_data);
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate static krb5_error_code get_sam_edata
1837c478bd9Sstevel@tonic-gate (krb5_context, krb5_kdc_req *request,
18456a424ccSmp krb5_db_entry *client, krb5_db_entry *server,
185159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
186159d09a2SMark Phalan void *pa_module_context,
18756a424ccSmp krb5_pa_data *data);
1887c478bd9Sstevel@tonic-gate static krb5_error_code return_sam_data
189*55fea89dSDan Cross (krb5_context, krb5_pa_data * padata,
19056a424ccSmp krb5_db_entry *client,
191159d09a2SMark Phalan krb5_data *req_pkt,
19256a424ccSmp krb5_kdc_req *request, krb5_kdc_rep *reply,
19356a424ccSmp krb5_key_data *client_key,
19456a424ccSmp krb5_keyblock *encrypting_key,
195159d09a2SMark Phalan krb5_pa_data **send_pa,
196159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data,
197159d09a2SMark Phalan void *pa_module_context,
198159d09a2SMark Phalan void **pa_request_context);
1997c478bd9Sstevel@tonic-gate
200159d09a2SMark Phalan static krb5_preauth_systems static_preauth_systems[] = {
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate "timestamp",
2037c478bd9Sstevel@tonic-gate KRB5_PADATA_ENC_TIMESTAMP,
2047c478bd9Sstevel@tonic-gate 0,
205159d09a2SMark Phalan NULL,
206159d09a2SMark Phalan NULL,
207159d09a2SMark Phalan NULL,
2087c478bd9Sstevel@tonic-gate 0,
2097c478bd9Sstevel@tonic-gate verify_enc_timestamp,
2107c478bd9Sstevel@tonic-gate 0
2117c478bd9Sstevel@tonic-gate },
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate "etype-info",
2147c478bd9Sstevel@tonic-gate KRB5_PADATA_ETYPE_INFO,
2157c478bd9Sstevel@tonic-gate 0,
216159d09a2SMark Phalan NULL,
217159d09a2SMark Phalan NULL,
218159d09a2SMark Phalan NULL,
2197c478bd9Sstevel@tonic-gate get_etype_info,
2207c478bd9Sstevel@tonic-gate 0,
221159d09a2SMark Phalan return_etype_info
2227c478bd9Sstevel@tonic-gate },
2237c478bd9Sstevel@tonic-gate {
22456a424ccSmp "etype-info2",
2257c478bd9Sstevel@tonic-gate KRB5_PADATA_ETYPE_INFO2,
2267c478bd9Sstevel@tonic-gate 0,
227159d09a2SMark Phalan NULL,
228159d09a2SMark Phalan NULL,
229159d09a2SMark Phalan NULL,
23056a424ccSmp get_etype_info2,
2317c478bd9Sstevel@tonic-gate 0,
23256a424ccSmp return_etype_info2
2337c478bd9Sstevel@tonic-gate },
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate "pw-salt",
2367c478bd9Sstevel@tonic-gate KRB5_PADATA_PW_SALT,
2377c478bd9Sstevel@tonic-gate PA_PSEUDO, /* Don't include this in the error list */
238159d09a2SMark Phalan NULL,
239159d09a2SMark Phalan NULL,
240159d09a2SMark Phalan NULL,
241*55fea89dSDan Cross 0,
2427c478bd9Sstevel@tonic-gate 0,
2437c478bd9Sstevel@tonic-gate return_pw_salt
2447c478bd9Sstevel@tonic-gate },
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate "sam-response",
2477c478bd9Sstevel@tonic-gate KRB5_PADATA_SAM_RESPONSE,
2487c478bd9Sstevel@tonic-gate 0,
249159d09a2SMark Phalan NULL,
250159d09a2SMark Phalan NULL,
251159d09a2SMark Phalan NULL,
2527c478bd9Sstevel@tonic-gate 0,
2537c478bd9Sstevel@tonic-gate verify_sam_response,
2547c478bd9Sstevel@tonic-gate return_sam_data
2557c478bd9Sstevel@tonic-gate },
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate "sam-challenge",
2587c478bd9Sstevel@tonic-gate KRB5_PADATA_SAM_CHALLENGE,
2597c478bd9Sstevel@tonic-gate PA_HARDWARE, /* causes get_preauth_hint_list to use this */
260159d09a2SMark Phalan NULL,
261159d09a2SMark Phalan NULL,
262159d09a2SMark Phalan NULL,
2637c478bd9Sstevel@tonic-gate get_sam_edata,
2647c478bd9Sstevel@tonic-gate 0,
2657c478bd9Sstevel@tonic-gate 0
2667c478bd9Sstevel@tonic-gate },
2677c478bd9Sstevel@tonic-gate { "[end]", -1,}
2687c478bd9Sstevel@tonic-gate };
2697c478bd9Sstevel@tonic-gate
270159d09a2SMark Phalan static krb5_preauth_systems *preauth_systems;
271159d09a2SMark Phalan static int n_preauth_systems;
272159d09a2SMark Phalan static struct plugin_dir_handle preauth_plugins;
273159d09a2SMark Phalan
274159d09a2SMark Phalan krb5_error_code
load_preauth_plugins(krb5_context context)275159d09a2SMark Phalan load_preauth_plugins(krb5_context context)
276159d09a2SMark Phalan {
277159d09a2SMark Phalan struct errinfo err;
278159d09a2SMark Phalan void **preauth_plugins_ftables;
279159d09a2SMark Phalan struct krb5plugin_preauth_server_ftable_v1 *ftable;
280159d09a2SMark Phalan int module_count, i, j, k;
281159d09a2SMark Phalan void *plugin_context;
282159d09a2SMark Phalan preauth_server_init_proc server_init_proc = NULL;
283159d09a2SMark Phalan char **kdc_realm_names = NULL;
284159d09a2SMark Phalan
285159d09a2SMark Phalan memset(&err, 0, sizeof(err));
286159d09a2SMark Phalan
287159d09a2SMark Phalan /* Attempt to load all of the preauth plugins we can find. */
288159d09a2SMark Phalan PLUGIN_DIR_INIT(&preauth_plugins);
289159d09a2SMark Phalan if (PLUGIN_DIR_OPEN(&preauth_plugins) == 0) {
290159d09a2SMark Phalan if (krb5int_open_plugin_dirs(objdirs, NULL,
291159d09a2SMark Phalan &preauth_plugins, &err) != 0) {
292159d09a2SMark Phalan return KRB5_PLUGIN_NO_HANDLE;
293159d09a2SMark Phalan }
294159d09a2SMark Phalan }
295159d09a2SMark Phalan
296159d09a2SMark Phalan /* Get the method tables provided by the loaded plugins. */
297159d09a2SMark Phalan preauth_plugins_ftables = NULL;
298159d09a2SMark Phalan if (krb5int_get_plugin_dir_data(&preauth_plugins,
299159d09a2SMark Phalan "preauthentication_server_1",
300159d09a2SMark Phalan &preauth_plugins_ftables, &err) != 0) {
301159d09a2SMark Phalan return KRB5_PLUGIN_NO_HANDLE;
302159d09a2SMark Phalan }
303159d09a2SMark Phalan
304159d09a2SMark Phalan /* Count the valid modules. */
305159d09a2SMark Phalan module_count = sizeof(static_preauth_systems)
306159d09a2SMark Phalan / sizeof(static_preauth_systems[0]);
307159d09a2SMark Phalan if (preauth_plugins_ftables != NULL) {
308159d09a2SMark Phalan for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
309159d09a2SMark Phalan ftable = preauth_plugins_ftables[i];
310159d09a2SMark Phalan if ((ftable->flags_proc == NULL) &&
311159d09a2SMark Phalan (ftable->edata_proc == NULL) &&
312159d09a2SMark Phalan (ftable->verify_proc == NULL) &&
313159d09a2SMark Phalan (ftable->return_proc == NULL)) {
314159d09a2SMark Phalan continue;
315159d09a2SMark Phalan }
316159d09a2SMark Phalan for (j = 0;
317159d09a2SMark Phalan ftable->pa_type_list != NULL &&
318159d09a2SMark Phalan ftable->pa_type_list[j] > 0;
319159d09a2SMark Phalan j++) {
320159d09a2SMark Phalan module_count++;
321159d09a2SMark Phalan }
322159d09a2SMark Phalan }
323159d09a2SMark Phalan }
324159d09a2SMark Phalan
325159d09a2SMark Phalan /* Build the complete list of supported preauthentication options, and
326159d09a2SMark Phalan * leave room for a terminator entry. */
327159d09a2SMark Phalan preauth_systems = malloc(sizeof(krb5_preauth_systems) * (module_count + 1));
328159d09a2SMark Phalan if (preauth_systems == NULL) {
329159d09a2SMark Phalan krb5int_free_plugin_dir_data(preauth_plugins_ftables);
330159d09a2SMark Phalan return ENOMEM;
331159d09a2SMark Phalan }
332159d09a2SMark Phalan
333159d09a2SMark Phalan /* Build a list of the names of the supported realms for this KDC.
334159d09a2SMark Phalan * The list of names is terminated with a NULL. */
335159d09a2SMark Phalan kdc_realm_names = malloc(sizeof(char *) * (kdc_numrealms + 1));
336159d09a2SMark Phalan if (kdc_realm_names == NULL) {
337159d09a2SMark Phalan krb5int_free_plugin_dir_data(preauth_plugins_ftables);
338159d09a2SMark Phalan return ENOMEM;
339159d09a2SMark Phalan }
340159d09a2SMark Phalan for (i = 0; i < kdc_numrealms; i++) {
341159d09a2SMark Phalan kdc_realm_names[i] = kdc_realmlist[i]->realm_name;
342159d09a2SMark Phalan }
343159d09a2SMark Phalan kdc_realm_names[i] = NULL;
344159d09a2SMark Phalan
345159d09a2SMark Phalan /* Add the locally-supplied mechanisms to the dynamic list first. */
346159d09a2SMark Phalan for (i = 0, k = 0;
347159d09a2SMark Phalan i < sizeof(static_preauth_systems) / sizeof(static_preauth_systems[0]);
348159d09a2SMark Phalan i++) {
349159d09a2SMark Phalan if (static_preauth_systems[i].type == -1)
350159d09a2SMark Phalan break;
351159d09a2SMark Phalan preauth_systems[k] = static_preauth_systems[i];
352159d09a2SMark Phalan /* Try to initialize the preauth system. If it fails, we'll remove it
353159d09a2SMark Phalan * from the list of systems we'll be using. */
354159d09a2SMark Phalan plugin_context = NULL;
355159d09a2SMark Phalan server_init_proc = static_preauth_systems[i].init;
356159d09a2SMark Phalan if ((server_init_proc != NULL) &&
357159d09a2SMark Phalan ((*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names) != 0)) {
358159d09a2SMark Phalan memset(&preauth_systems[k], 0, sizeof(preauth_systems[k]));
359159d09a2SMark Phalan continue;
360159d09a2SMark Phalan }
361159d09a2SMark Phalan preauth_systems[k].plugin_context = plugin_context;
362159d09a2SMark Phalan k++;
363159d09a2SMark Phalan }
364159d09a2SMark Phalan
365159d09a2SMark Phalan /* Now add the dynamically-loaded mechanisms to the list. */
366159d09a2SMark Phalan if (preauth_plugins_ftables != NULL) {
367159d09a2SMark Phalan for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
368159d09a2SMark Phalan ftable = preauth_plugins_ftables[i];
369159d09a2SMark Phalan if ((ftable->flags_proc == NULL) &&
370159d09a2SMark Phalan (ftable->edata_proc == NULL) &&
371159d09a2SMark Phalan (ftable->verify_proc == NULL) &&
372159d09a2SMark Phalan (ftable->return_proc == NULL)) {
373159d09a2SMark Phalan continue;
374159d09a2SMark Phalan }
375159d09a2SMark Phalan plugin_context = NULL;
376159d09a2SMark Phalan for (j = 0;
377159d09a2SMark Phalan ftable->pa_type_list != NULL &&
378159d09a2SMark Phalan ftable->pa_type_list[j] > 0;
379159d09a2SMark Phalan j++) {
380159d09a2SMark Phalan /* Try to initialize the plugin. If it fails, we'll remove it
381159d09a2SMark Phalan * from the list of modules we'll be using. */
382159d09a2SMark Phalan if (j == 0) {
383159d09a2SMark Phalan server_init_proc = ftable->init_proc;
384159d09a2SMark Phalan if (server_init_proc != NULL) {
385159d09a2SMark Phalan krb5_error_code initerr;
386159d09a2SMark Phalan initerr = (*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names);
387159d09a2SMark Phalan if (initerr) {
388159d09a2SMark Phalan const char *emsg;
389159d09a2SMark Phalan emsg = krb5_get_error_message(context, initerr);
390159d09a2SMark Phalan if (emsg) {
391159d09a2SMark Phalan krb5_klog_syslog(LOG_ERR,
392159d09a2SMark Phalan "preauth %s failed to initialize: %s",
393159d09a2SMark Phalan ftable->name, emsg);
394159d09a2SMark Phalan krb5_free_error_message(context, emsg);
395159d09a2SMark Phalan }
396159d09a2SMark Phalan memset(&preauth_systems[k], 0, sizeof(preauth_systems[k]));
397159d09a2SMark Phalan
398159d09a2SMark Phalan break; /* skip all modules in this plugin */
399159d09a2SMark Phalan }
400159d09a2SMark Phalan }
401159d09a2SMark Phalan }
402159d09a2SMark Phalan preauth_systems[k].name = ftable->name;
403159d09a2SMark Phalan preauth_systems[k].type = ftable->pa_type_list[j];
404159d09a2SMark Phalan if (ftable->flags_proc != NULL)
405159d09a2SMark Phalan preauth_systems[k].flags = ftable->flags_proc(context, preauth_systems[k].type);
406159d09a2SMark Phalan else
407159d09a2SMark Phalan preauth_systems[k].flags = 0;
408159d09a2SMark Phalan preauth_systems[k].plugin_context = plugin_context;
409159d09a2SMark Phalan preauth_systems[k].init = server_init_proc;
410159d09a2SMark Phalan /* Only call fini once for each plugin */
411159d09a2SMark Phalan if (j == 0)
412159d09a2SMark Phalan preauth_systems[k].fini = ftable->fini_proc;
413159d09a2SMark Phalan else
414159d09a2SMark Phalan preauth_systems[k].fini = NULL;
415159d09a2SMark Phalan preauth_systems[k].get_edata = ftable->edata_proc;
416159d09a2SMark Phalan preauth_systems[k].verify_padata = ftable->verify_proc;
417159d09a2SMark Phalan preauth_systems[k].return_padata = ftable->return_proc;
418159d09a2SMark Phalan preauth_systems[k].free_pa_reqctx =
419159d09a2SMark Phalan ftable->freepa_reqcontext_proc;
420159d09a2SMark Phalan k++;
421159d09a2SMark Phalan }
422159d09a2SMark Phalan }
423159d09a2SMark Phalan krb5int_free_plugin_dir_data(preauth_plugins_ftables);
424159d09a2SMark Phalan }
425159d09a2SMark Phalan free(kdc_realm_names);
426159d09a2SMark Phalan n_preauth_systems = k;
427159d09a2SMark Phalan /* Add the end-of-list marker. */
428159d09a2SMark Phalan preauth_systems[k].name = "[end]";
429159d09a2SMark Phalan preauth_systems[k].type = -1;
430159d09a2SMark Phalan return 0;
431159d09a2SMark Phalan }
432159d09a2SMark Phalan
433159d09a2SMark Phalan krb5_error_code
unload_preauth_plugins(krb5_context context)434159d09a2SMark Phalan unload_preauth_plugins(krb5_context context)
435159d09a2SMark Phalan {
436159d09a2SMark Phalan int i;
437159d09a2SMark Phalan if (preauth_systems != NULL) {
438159d09a2SMark Phalan for (i = 0; i < n_preauth_systems; i++) {
439159d09a2SMark Phalan if (preauth_systems[i].fini != NULL) {
440159d09a2SMark Phalan (*preauth_systems[i].fini)(context,
441159d09a2SMark Phalan preauth_systems[i].plugin_context);
442159d09a2SMark Phalan }
443159d09a2SMark Phalan memset(&preauth_systems[i], 0, sizeof(preauth_systems[i]));
444159d09a2SMark Phalan }
445159d09a2SMark Phalan free(preauth_systems);
446159d09a2SMark Phalan preauth_systems = NULL;
447159d09a2SMark Phalan n_preauth_systems = 0;
448159d09a2SMark Phalan krb5int_close_plugin_dirs(&preauth_plugins);
449159d09a2SMark Phalan }
450159d09a2SMark Phalan return 0;
451159d09a2SMark Phalan }
452159d09a2SMark Phalan
453159d09a2SMark Phalan /*
454159d09a2SMark Phalan * The make_padata_context() function creates a space for storing any context
455159d09a2SMark Phalan * information which will be needed by return_padata() later. Each preauth
456159d09a2SMark Phalan * type gets a context storage location of its own.
457159d09a2SMark Phalan */
458159d09a2SMark Phalan struct request_pa_context {
459159d09a2SMark Phalan int n_contexts;
460159d09a2SMark Phalan struct {
461159d09a2SMark Phalan krb5_preauth_systems *pa_system;
462159d09a2SMark Phalan void *pa_context;
463159d09a2SMark Phalan } *contexts;
464159d09a2SMark Phalan };
465159d09a2SMark Phalan
466159d09a2SMark Phalan static krb5_error_code
make_padata_context(krb5_context context,void ** padata_context)467159d09a2SMark Phalan make_padata_context(krb5_context context, void **padata_context)
468159d09a2SMark Phalan {
469159d09a2SMark Phalan int i;
470159d09a2SMark Phalan struct request_pa_context *ret;
471159d09a2SMark Phalan
472159d09a2SMark Phalan ret = malloc(sizeof(*ret));
473159d09a2SMark Phalan if (ret == NULL) {
474159d09a2SMark Phalan return ENOMEM;
475159d09a2SMark Phalan }
476159d09a2SMark Phalan
477159d09a2SMark Phalan ret->n_contexts = n_preauth_systems;
478159d09a2SMark Phalan ret->contexts = malloc(sizeof(ret->contexts[0]) * ret->n_contexts);
479159d09a2SMark Phalan if (ret->contexts == NULL) {
480159d09a2SMark Phalan free(ret);
481159d09a2SMark Phalan return ENOMEM;
482159d09a2SMark Phalan }
483159d09a2SMark Phalan
484159d09a2SMark Phalan memset(ret->contexts, 0, sizeof(ret->contexts[0]) * ret->n_contexts);
485159d09a2SMark Phalan
486159d09a2SMark Phalan for (i = 0; i < ret->n_contexts; i++) {
487159d09a2SMark Phalan ret->contexts[i].pa_system = &preauth_systems[i];
488159d09a2SMark Phalan ret->contexts[i].pa_context = NULL;
489159d09a2SMark Phalan }
490159d09a2SMark Phalan
491159d09a2SMark Phalan *padata_context = ret;
492159d09a2SMark Phalan
493159d09a2SMark Phalan return 0;
494159d09a2SMark Phalan }
495159d09a2SMark Phalan
496159d09a2SMark Phalan /*
497159d09a2SMark Phalan * The free_padata_context function frees any context information pointers
498159d09a2SMark Phalan * which the check_padata() function created but which weren't already cleaned
499159d09a2SMark Phalan * up by return_padata().
500159d09a2SMark Phalan */
501159d09a2SMark Phalan krb5_error_code
free_padata_context(krb5_context kcontext,void ** padata_context)502159d09a2SMark Phalan free_padata_context(krb5_context kcontext, void **padata_context)
503159d09a2SMark Phalan {
504159d09a2SMark Phalan struct request_pa_context *context;
505159d09a2SMark Phalan krb5_preauth_systems *preauth_system;
506159d09a2SMark Phalan void **pctx, *mctx;
507159d09a2SMark Phalan int i;
508159d09a2SMark Phalan
509159d09a2SMark Phalan if (padata_context == NULL)
510159d09a2SMark Phalan return 0;
511159d09a2SMark Phalan
512159d09a2SMark Phalan context = *padata_context;
513159d09a2SMark Phalan
514159d09a2SMark Phalan for (i = 0; i < context->n_contexts; i++) {
515159d09a2SMark Phalan if (context->contexts[i].pa_context != NULL) {
516159d09a2SMark Phalan preauth_system = context->contexts[i].pa_system;
517159d09a2SMark Phalan mctx = preauth_system->plugin_context;
518159d09a2SMark Phalan if (preauth_system->free_pa_reqctx != NULL) {
519159d09a2SMark Phalan pctx = &context->contexts[i].pa_context;
520159d09a2SMark Phalan (*preauth_system->free_pa_reqctx)(kcontext, mctx, pctx);
521159d09a2SMark Phalan }
522159d09a2SMark Phalan context->contexts[i].pa_context = NULL;
523159d09a2SMark Phalan }
524159d09a2SMark Phalan }
525159d09a2SMark Phalan
526159d09a2SMark Phalan free(context->contexts);
527159d09a2SMark Phalan free(context);
528159d09a2SMark Phalan
529159d09a2SMark Phalan return 0;
530159d09a2SMark Phalan }
531159d09a2SMark Phalan
532159d09a2SMark Phalan /* Retrieve a specified tl_data item from the given entry, and return its
533159d09a2SMark Phalan * contents in a new krb5_data, which must be freed by the caller. */
534159d09a2SMark Phalan static krb5_error_code
get_entry_tl_data(krb5_context context,krb5_db_entry * entry,krb5_int16 tl_data_type,krb5_data ** result)535159d09a2SMark Phalan get_entry_tl_data(krb5_context context, krb5_db_entry *entry,
536159d09a2SMark Phalan krb5_int16 tl_data_type, krb5_data **result)
537159d09a2SMark Phalan {
538159d09a2SMark Phalan krb5_tl_data *tl;
539159d09a2SMark Phalan for (tl = entry->tl_data; tl != NULL; tl = tl->tl_data_next) {
540159d09a2SMark Phalan if (tl->tl_data_type == tl_data_type) {
541159d09a2SMark Phalan *result = malloc(sizeof(krb5_data));
542159d09a2SMark Phalan if (*result == NULL) {
543159d09a2SMark Phalan return ENOMEM;
544159d09a2SMark Phalan }
545159d09a2SMark Phalan (*result)->magic = KV5M_DATA;
546159d09a2SMark Phalan (*result)->data = malloc(tl->tl_data_length);
547159d09a2SMark Phalan if ((*result)->data == NULL) {
548159d09a2SMark Phalan free(*result);
549159d09a2SMark Phalan *result = NULL;
550159d09a2SMark Phalan return ENOMEM;
551159d09a2SMark Phalan }
552159d09a2SMark Phalan memcpy((*result)->data, tl->tl_data_contents, tl->tl_data_length);
553159d09a2SMark Phalan return 0;
554159d09a2SMark Phalan }
555159d09a2SMark Phalan }
556159d09a2SMark Phalan return ENOENT;
557159d09a2SMark Phalan }
558159d09a2SMark Phalan
559159d09a2SMark Phalan /*
560159d09a2SMark Phalan * Retrieve a specific piece of information pertaining to the entry or the
561159d09a2SMark Phalan * request and return it in a new krb5_data item which the caller must free.
562159d09a2SMark Phalan *
563159d09a2SMark Phalan * This may require massaging data into a contrived format, but it will
564159d09a2SMark Phalan * hopefully keep us from having to reveal library-internal functions to
565159d09a2SMark Phalan * modules.
566159d09a2SMark Phalan */
567159d09a2SMark Phalan static krb5_error_code
get_entry_data(krb5_context context,krb5_kdc_req * request,krb5_db_entry * entry,krb5_int32 type,krb5_data ** result)568159d09a2SMark Phalan get_entry_data(krb5_context context,
569159d09a2SMark Phalan krb5_kdc_req *request, krb5_db_entry *entry,
570159d09a2SMark Phalan krb5_int32 type,
571159d09a2SMark Phalan krb5_data **result)
572159d09a2SMark Phalan {
573159d09a2SMark Phalan int i, k;
574159d09a2SMark Phalan krb5_data *ret;
575159d09a2SMark Phalan krb5_deltat *delta;
576159d09a2SMark Phalan krb5_keyblock *keys;
577159d09a2SMark Phalan krb5_key_data *entry_key;
578159d09a2SMark Phalan
579159d09a2SMark Phalan switch (type) {
580159d09a2SMark Phalan case krb5plugin_preauth_entry_request_certificate:
581159d09a2SMark Phalan return get_entry_tl_data(context, entry,
582159d09a2SMark Phalan KRB5_TL_USER_CERTIFICATE, result);
583159d09a2SMark Phalan break;
584159d09a2SMark Phalan case krb5plugin_preauth_entry_max_time_skew:
585159d09a2SMark Phalan ret = malloc(sizeof(krb5_data));
586159d09a2SMark Phalan if (ret == NULL)
587159d09a2SMark Phalan return ENOMEM;
588159d09a2SMark Phalan delta = malloc(sizeof(krb5_deltat));
589159d09a2SMark Phalan if (delta == NULL) {
590159d09a2SMark Phalan free(ret);
591159d09a2SMark Phalan return ENOMEM;
592159d09a2SMark Phalan }
593159d09a2SMark Phalan *delta = context->clockskew;
594159d09a2SMark Phalan ret->data = (char *) delta;
595159d09a2SMark Phalan ret->length = sizeof(*delta);
596159d09a2SMark Phalan *result = ret;
597159d09a2SMark Phalan return 0;
598159d09a2SMark Phalan break;
599159d09a2SMark Phalan case krb5plugin_preauth_keys:
600159d09a2SMark Phalan ret = malloc(sizeof(krb5_data));
601159d09a2SMark Phalan if (ret == NULL)
602159d09a2SMark Phalan return ENOMEM;
603159d09a2SMark Phalan keys = malloc(sizeof(krb5_keyblock) * (request->nktypes + 1));
604159d09a2SMark Phalan if (keys == NULL) {
605159d09a2SMark Phalan free(ret);
606159d09a2SMark Phalan return ENOMEM;
607159d09a2SMark Phalan }
608159d09a2SMark Phalan ret->data = (char *) keys;
609159d09a2SMark Phalan ret->length = sizeof(krb5_keyblock) * (request->nktypes + 1);
610159d09a2SMark Phalan memset(ret->data, 0, ret->length);
611159d09a2SMark Phalan k = 0;
612159d09a2SMark Phalan for (i = 0; i < request->nktypes; i++) {
613159d09a2SMark Phalan entry_key = NULL;
614159d09a2SMark Phalan if (krb5_dbe_find_enctype(context, entry, request->ktype[i],
615159d09a2SMark Phalan -1, 0, &entry_key) != 0)
616159d09a2SMark Phalan continue;
617159d09a2SMark Phalan if (krb5_dbekd_decrypt_key_data(context, &master_keyblock,
618159d09a2SMark Phalan entry_key, &keys[k], NULL) != 0) {
619159d09a2SMark Phalan if (keys[k].contents != NULL)
620159d09a2SMark Phalan krb5_free_keyblock_contents(context, &keys[k]);
621159d09a2SMark Phalan memset(&keys[k], 0, sizeof(keys[k]));
622159d09a2SMark Phalan continue;
623159d09a2SMark Phalan }
624159d09a2SMark Phalan k++;
625159d09a2SMark Phalan }
626159d09a2SMark Phalan if (k > 0) {
627159d09a2SMark Phalan *result = ret;
628159d09a2SMark Phalan return 0;
629159d09a2SMark Phalan } else {
630159d09a2SMark Phalan free(keys);
631159d09a2SMark Phalan free(ret);
632159d09a2SMark Phalan }
633159d09a2SMark Phalan break;
634159d09a2SMark Phalan case krb5plugin_preauth_request_body:
635159d09a2SMark Phalan ret = NULL;
636159d09a2SMark Phalan encode_krb5_kdc_req_body(request, &ret);
637159d09a2SMark Phalan if (ret != NULL) {
638159d09a2SMark Phalan *result = ret;
639159d09a2SMark Phalan return 0;
640159d09a2SMark Phalan }
641159d09a2SMark Phalan return ASN1_PARSE_ERROR;
642159d09a2SMark Phalan break;
643159d09a2SMark Phalan default:
644159d09a2SMark Phalan break;
645159d09a2SMark Phalan }
646159d09a2SMark Phalan return ENOENT;
647159d09a2SMark Phalan }
6487c478bd9Sstevel@tonic-gate
6497c478bd9Sstevel@tonic-gate static krb5_error_code
find_pa_system(int type,krb5_preauth_systems ** preauth)6507c478bd9Sstevel@tonic-gate find_pa_system(int type, krb5_preauth_systems **preauth)
6517c478bd9Sstevel@tonic-gate {
652159d09a2SMark Phalan krb5_preauth_systems *ap;
653159d09a2SMark Phalan
654159d09a2SMark Phalan ap = preauth_systems ? preauth_systems : static_preauth_systems;
6557c478bd9Sstevel@tonic-gate while ((ap->type != -1) && (ap->type != type))
6567c478bd9Sstevel@tonic-gate ap++;
6577c478bd9Sstevel@tonic-gate if (ap->type == -1)
6587c478bd9Sstevel@tonic-gate return(KRB5_PREAUTH_BAD_TYPE);
6597c478bd9Sstevel@tonic-gate *preauth = ap;
6607c478bd9Sstevel@tonic-gate return 0;
661*55fea89dSDan Cross }
6627c478bd9Sstevel@tonic-gate
663159d09a2SMark Phalan static krb5_error_code
find_pa_context(krb5_preauth_systems * pa_sys,struct request_pa_context * context,void *** pa_context)664159d09a2SMark Phalan find_pa_context(krb5_preauth_systems *pa_sys,
665159d09a2SMark Phalan struct request_pa_context *context,
666159d09a2SMark Phalan void ***pa_context)
667159d09a2SMark Phalan {
668159d09a2SMark Phalan int i;
669159d09a2SMark Phalan
670159d09a2SMark Phalan *pa_context = 0;
671159d09a2SMark Phalan
672159d09a2SMark Phalan if (context == NULL)
673159d09a2SMark Phalan return KRB5KRB_ERR_GENERIC;
674159d09a2SMark Phalan
675159d09a2SMark Phalan for (i = 0; i < context->n_contexts; i++) {
676159d09a2SMark Phalan if (context->contexts[i].pa_system == pa_sys) {
677159d09a2SMark Phalan *pa_context = &context->contexts[i].pa_context;
678159d09a2SMark Phalan return 0;
679159d09a2SMark Phalan }
680159d09a2SMark Phalan }
681159d09a2SMark Phalan
682159d09a2SMark Phalan return KRB5KRB_ERR_GENERIC;
683159d09a2SMark Phalan }
684159d09a2SMark Phalan
685159d09a2SMark Phalan /*
686159d09a2SMark Phalan * Create a list of indices into the preauth_systems array, sorted by order of
687159d09a2SMark Phalan * preference.
688159d09a2SMark Phalan */
689159d09a2SMark Phalan static krb5_boolean
pa_list_includes(krb5_pa_data ** pa_data,krb5_preauthtype pa_type)690159d09a2SMark Phalan pa_list_includes(krb5_pa_data **pa_data, krb5_preauthtype pa_type)
691159d09a2SMark Phalan {
692159d09a2SMark Phalan while (*pa_data != NULL) {
693159d09a2SMark Phalan if ((*pa_data)->pa_type == pa_type)
694159d09a2SMark Phalan return TRUE;
695159d09a2SMark Phalan pa_data++;
696159d09a2SMark Phalan }
697159d09a2SMark Phalan return FALSE;
698159d09a2SMark Phalan }
699159d09a2SMark Phalan static void
sort_pa_order(krb5_context context,krb5_kdc_req * request,int * pa_order)700159d09a2SMark Phalan sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order)
701159d09a2SMark Phalan {
702159d09a2SMark Phalan int i, j, k, n_repliers, n_key_replacers;
703159d09a2SMark Phalan
704159d09a2SMark Phalan /* First, set up the default order. */
705159d09a2SMark Phalan i = 0;
706159d09a2SMark Phalan for (j = 0; j < n_preauth_systems; j++) {
707159d09a2SMark Phalan if (preauth_systems[j].return_padata != NULL)
708159d09a2SMark Phalan pa_order[i++] = j;
709159d09a2SMark Phalan }
710159d09a2SMark Phalan n_repliers = i;
711159d09a2SMark Phalan pa_order[n_repliers] = -1;
712159d09a2SMark Phalan
713159d09a2SMark Phalan /* Reorder so that PA_REPLACES_KEY modules are listed first. */
714159d09a2SMark Phalan for (i = 0; i < n_repliers; i++) {
715159d09a2SMark Phalan /* If this module replaces the key, then it's okay to leave it where it
716159d09a2SMark Phalan * is in the order. */
717159d09a2SMark Phalan if (preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY)
718159d09a2SMark Phalan continue;
719159d09a2SMark Phalan /* If not, search for a module which does, and swap in the first one we
720159d09a2SMark Phalan * find. */
721159d09a2SMark Phalan for (j = i + 1; j < n_repliers; j++) {
722159d09a2SMark Phalan if (preauth_systems[pa_order[j]].flags & PA_REPLACES_KEY) {
723159d09a2SMark Phalan k = pa_order[j];
724159d09a2SMark Phalan pa_order[j] = pa_order[i];
725159d09a2SMark Phalan pa_order[i] = k;
726159d09a2SMark Phalan break;
727159d09a2SMark Phalan }
728159d09a2SMark Phalan }
729159d09a2SMark Phalan }
730159d09a2SMark Phalan
731159d09a2SMark Phalan if (request->padata != NULL) {
732159d09a2SMark Phalan /* Now reorder the subset of modules which replace the key,
733159d09a2SMark Phalan * bubbling those which handle pa_data types provided by the
734159d09a2SMark Phalan * client ahead of the others. */
735159d09a2SMark Phalan for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) {
736159d09a2SMark Phalan continue;
737159d09a2SMark Phalan }
738159d09a2SMark Phalan n_key_replacers = i;
739159d09a2SMark Phalan for (i = 0; i < n_key_replacers; i++) {
740159d09a2SMark Phalan if (pa_list_includes(request->padata,
741159d09a2SMark Phalan preauth_systems[pa_order[i]].type))
742159d09a2SMark Phalan continue;
743159d09a2SMark Phalan for (j = i + 1; j < n_key_replacers; j++) {
744159d09a2SMark Phalan if (pa_list_includes(request->padata,
745159d09a2SMark Phalan preauth_systems[pa_order[j]].type)) {
746159d09a2SMark Phalan k = pa_order[j];
747159d09a2SMark Phalan pa_order[j] = pa_order[i];
748159d09a2SMark Phalan pa_order[i] = k;
749159d09a2SMark Phalan break;
750159d09a2SMark Phalan }
751159d09a2SMark Phalan }
752159d09a2SMark Phalan }
753159d09a2SMark Phalan }
754159d09a2SMark Phalan #ifdef DEBUG
755159d09a2SMark Phalan krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:");
756159d09a2SMark Phalan for (i = 0; i < n_preauth_systems; i++) {
757159d09a2SMark Phalan if (preauth_systems[i].return_padata != NULL)
758159d09a2SMark Phalan krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", preauth_systems[i].name,
759159d09a2SMark Phalan preauth_systems[i].type);
760159d09a2SMark Phalan }
761159d09a2SMark Phalan krb5_klog_syslog(LOG_DEBUG, "sorted preauth mechanism list:");
762159d09a2SMark Phalan for (i = 0; pa_order[i] != -1; i++) {
763159d09a2SMark Phalan krb5_klog_syslog(LOG_DEBUG, "... %s(%d)",
764159d09a2SMark Phalan preauth_systems[pa_order[i]].name,
765159d09a2SMark Phalan preauth_systems[pa_order[i]].type);
766159d09a2SMark Phalan }
767159d09a2SMark Phalan #endif
768159d09a2SMark Phalan }
769159d09a2SMark Phalan
missing_required_preauth(krb5_db_entry * client,krb5_db_entry * server,krb5_enc_tkt_part * enc_tkt_reply)77056a424ccSmp const char *missing_required_preauth(krb5_db_entry *client,
77156a424ccSmp krb5_db_entry *server,
77256a424ccSmp krb5_enc_tkt_part *enc_tkt_reply)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate #if 0
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate * If this is the pwchange service, and the pre-auth bit is set,
7777c478bd9Sstevel@tonic-gate * allow it even if the HW preauth would normally be required.
778*55fea89dSDan Cross *
7797c478bd9Sstevel@tonic-gate * Sandia national labs wanted this for some strange reason... we
7807c478bd9Sstevel@tonic-gate * leave it disabled normally.
7817c478bd9Sstevel@tonic-gate */
7827c478bd9Sstevel@tonic-gate if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) &&
7837c478bd9Sstevel@tonic-gate isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
7847c478bd9Sstevel@tonic-gate return 0;
7857c478bd9Sstevel@tonic-gate #endif
786*55fea89dSDan Cross
7877c478bd9Sstevel@tonic-gate #ifdef DEBUG
7887c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG,
7897c478bd9Sstevel@tonic-gate "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth",
7907c478bd9Sstevel@tonic-gate isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ",
7917c478bd9Sstevel@tonic-gate isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ",
7927c478bd9Sstevel@tonic-gate isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ",
7937c478bd9Sstevel@tonic-gate isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no ");
7947c478bd9Sstevel@tonic-gate #endif
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
7977c478bd9Sstevel@tonic-gate !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
7987c478bd9Sstevel@tonic-gate return "NEEDED_PREAUTH";
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
8017c478bd9Sstevel@tonic-gate !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
8027c478bd9Sstevel@tonic-gate return "NEEDED_HW_PREAUTH";
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate return 0;
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
get_preauth_hint_list(krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_data * e_data)80756a424ccSmp void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client,
80856a424ccSmp krb5_db_entry *server, krb5_data *e_data)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate int hw_only;
8117c478bd9Sstevel@tonic-gate krb5_preauth_systems *ap;
8127c478bd9Sstevel@tonic-gate krb5_pa_data **pa_data, **pa;
8137c478bd9Sstevel@tonic-gate krb5_data *edat;
8147c478bd9Sstevel@tonic-gate krb5_error_code retval;
815*55fea89dSDan Cross
8167c478bd9Sstevel@tonic-gate /* Zero these out in case we need to abort */
8177c478bd9Sstevel@tonic-gate e_data->length = 0;
8187c478bd9Sstevel@tonic-gate e_data->data = 0;
819*55fea89dSDan Cross
8207c478bd9Sstevel@tonic-gate hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH);
821159d09a2SMark Phalan pa_data = malloc(sizeof(krb5_pa_data *) * (n_preauth_systems+1));
8227c478bd9Sstevel@tonic-gate if (pa_data == 0)
8237c478bd9Sstevel@tonic-gate return;
824159d09a2SMark Phalan memset(pa_data, 0, sizeof(krb5_pa_data *) * (n_preauth_systems+1));
8257c478bd9Sstevel@tonic-gate pa = pa_data;
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate for (ap = preauth_systems; ap->type != -1; ap++) {
8287c478bd9Sstevel@tonic-gate if (hw_only && !(ap->flags & PA_HARDWARE))
8297c478bd9Sstevel@tonic-gate continue;
8307c478bd9Sstevel@tonic-gate if (ap->flags & PA_PSEUDO)
8317c478bd9Sstevel@tonic-gate continue;
8327c478bd9Sstevel@tonic-gate *pa = malloc(sizeof(krb5_pa_data));
8337c478bd9Sstevel@tonic-gate if (*pa == 0)
8347c478bd9Sstevel@tonic-gate goto errout;
8357c478bd9Sstevel@tonic-gate memset(*pa, 0, sizeof(krb5_pa_data));
8367c478bd9Sstevel@tonic-gate (*pa)->magic = KV5M_PA_DATA;
8377c478bd9Sstevel@tonic-gate (*pa)->pa_type = ap->type;
8387c478bd9Sstevel@tonic-gate if (ap->get_edata) {
839159d09a2SMark Phalan retval = (ap->get_edata)(kdc_context, request, client, server,
840159d09a2SMark Phalan get_entry_data, ap->plugin_context, *pa);
8417c478bd9Sstevel@tonic-gate if (retval) {
8427c478bd9Sstevel@tonic-gate /* just failed on this type, continue */
8437c478bd9Sstevel@tonic-gate free(*pa);
8447c478bd9Sstevel@tonic-gate *pa = 0;
8457c478bd9Sstevel@tonic-gate continue;
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate pa++;
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate if (pa_data[0] == 0) {
8517c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO,
8527c478bd9Sstevel@tonic-gate "%spreauth required but hint list is empty",
8537c478bd9Sstevel@tonic-gate hw_only ? "hw" : "");
8547c478bd9Sstevel@tonic-gate }
855ba7b222eSGlenn Barry retval = encode_krb5_padata_sequence((krb5_pa_data * const *) pa_data,
8567c478bd9Sstevel@tonic-gate &edat);
8577c478bd9Sstevel@tonic-gate if (retval)
8587c478bd9Sstevel@tonic-gate goto errout;
8597c478bd9Sstevel@tonic-gate *e_data = *edat;
8607c478bd9Sstevel@tonic-gate free(edat);
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate errout:
8637c478bd9Sstevel@tonic-gate krb5_free_pa_data(kdc_context, pa_data);
8647c478bd9Sstevel@tonic-gate return;
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate
867159d09a2SMark Phalan /*
868159d09a2SMark Phalan * Add authorization data returned from preauth modules to the ticket
869159d09a2SMark Phalan * It is assumed that ad is a "null-terminated" array of krb5_authdata ptrs
870159d09a2SMark Phalan */
871159d09a2SMark Phalan static krb5_error_code
add_authorization_data(krb5_enc_tkt_part * enc_tkt_part,krb5_authdata ** ad)872159d09a2SMark Phalan add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad)
873159d09a2SMark Phalan {
874159d09a2SMark Phalan krb5_authdata **newad;
875159d09a2SMark Phalan int oldones, newones;
876159d09a2SMark Phalan int i;
877159d09a2SMark Phalan
878159d09a2SMark Phalan if (enc_tkt_part == NULL || ad == NULL)
879159d09a2SMark Phalan return EINVAL;
880159d09a2SMark Phalan
881159d09a2SMark Phalan for (newones = 0; ad[newones] != NULL; newones++);
882159d09a2SMark Phalan if (newones == 0)
883159d09a2SMark Phalan return 0; /* nothing to add */
884159d09a2SMark Phalan
885159d09a2SMark Phalan if (enc_tkt_part->authorization_data == NULL)
886159d09a2SMark Phalan oldones = 0;
887159d09a2SMark Phalan else
888159d09a2SMark Phalan for (oldones = 0;
889159d09a2SMark Phalan enc_tkt_part->authorization_data[oldones] != NULL; oldones++);
890159d09a2SMark Phalan
891159d09a2SMark Phalan newad = malloc((oldones + newones + 1) * sizeof(krb5_authdata *));
892159d09a2SMark Phalan if (newad == NULL)
893159d09a2SMark Phalan return ENOMEM;
894159d09a2SMark Phalan
895159d09a2SMark Phalan /* Copy any existing pointers */
896159d09a2SMark Phalan for (i = 0; i < oldones; i++)
897159d09a2SMark Phalan newad[i] = enc_tkt_part->authorization_data[i];
898159d09a2SMark Phalan
899159d09a2SMark Phalan /* Add the new ones */
900159d09a2SMark Phalan for (i = 0; i < newones; i++)
901159d09a2SMark Phalan newad[oldones+i] = ad[i];
902159d09a2SMark Phalan
903159d09a2SMark Phalan /* Terminate the new list */
904159d09a2SMark Phalan newad[oldones+i] = NULL;
905159d09a2SMark Phalan
906159d09a2SMark Phalan /* Free any existing list */
907159d09a2SMark Phalan if (enc_tkt_part->authorization_data != NULL)
908159d09a2SMark Phalan free(enc_tkt_part->authorization_data);
909159d09a2SMark Phalan
910159d09a2SMark Phalan /* Install our new list */
911159d09a2SMark Phalan enc_tkt_part->authorization_data = newad;
912159d09a2SMark Phalan
913159d09a2SMark Phalan return 0;
914159d09a2SMark Phalan }
915159d09a2SMark Phalan
9167c478bd9Sstevel@tonic-gate /*
9177c478bd9Sstevel@tonic-gate * This routine is called to verify the preauthentication information
9187c478bd9Sstevel@tonic-gate * for a V5 request.
919159d09a2SMark Phalan *
9207c478bd9Sstevel@tonic-gate * Returns 0 if the pre-authentication is valid, non-zero to indicate
9217c478bd9Sstevel@tonic-gate * an error code of some sort.
9227c478bd9Sstevel@tonic-gate */
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate krb5_error_code
check_padata(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,void ** padata_context,krb5_data * e_data)925159d09a2SMark Phalan check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
926159d09a2SMark Phalan krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
927159d09a2SMark Phalan void **padata_context, krb5_data *e_data)
9287c478bd9Sstevel@tonic-gate {
9297c478bd9Sstevel@tonic-gate krb5_error_code retval = 0;
9307c478bd9Sstevel@tonic-gate krb5_pa_data **padata;
9317c478bd9Sstevel@tonic-gate krb5_preauth_systems *pa_sys;
932159d09a2SMark Phalan void **pa_context;
933159d09a2SMark Phalan krb5_data *pa_e_data = NULL, *tmp_e_data = NULL;
934159d09a2SMark Phalan int pa_ok = 0, pa_found = 0;
935159d09a2SMark Phalan krb5_error_code saved_retval = 0;
936159d09a2SMark Phalan int use_saved_retval = 0;
937159d09a2SMark Phalan const char *emsg;
938159d09a2SMark Phalan krb5_authdata **tmp_authz_data = NULL;
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate if (request->padata == 0)
9417c478bd9Sstevel@tonic-gate return 0;
9427c478bd9Sstevel@tonic-gate
943159d09a2SMark Phalan if (make_padata_context(context, padata_context) != 0) {
944159d09a2SMark Phalan return KRB5KRB_ERR_GENERIC;
945159d09a2SMark Phalan }
946159d09a2SMark Phalan
9477c478bd9Sstevel@tonic-gate #ifdef DEBUG
9487c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, "checking padata");
9497c478bd9Sstevel@tonic-gate #endif
9507c478bd9Sstevel@tonic-gate for (padata = request->padata; *padata; padata++) {
9517c478bd9Sstevel@tonic-gate #ifdef DEBUG
9527c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*padata)->pa_type);
9537c478bd9Sstevel@tonic-gate #endif
9547c478bd9Sstevel@tonic-gate if (find_pa_system((*padata)->pa_type, &pa_sys))
9557c478bd9Sstevel@tonic-gate continue;
956159d09a2SMark Phalan if (find_pa_context(pa_sys, *padata_context, &pa_context))
957159d09a2SMark Phalan continue;
9587c478bd9Sstevel@tonic-gate #ifdef DEBUG
9597c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", pa_sys->name);
9607c478bd9Sstevel@tonic-gate #endif
9617c478bd9Sstevel@tonic-gate if (pa_sys->verify_padata == 0)
9627c478bd9Sstevel@tonic-gate continue;
9637c478bd9Sstevel@tonic-gate pa_found++;
964159d09a2SMark Phalan retval = pa_sys->verify_padata(context, client, req_pkt, request,
965159d09a2SMark Phalan enc_tkt_reply, *padata,
966159d09a2SMark Phalan get_entry_data, pa_sys->plugin_context,
967159d09a2SMark Phalan pa_context, &tmp_e_data, &tmp_authz_data);
9687c478bd9Sstevel@tonic-gate if (retval) {
969159d09a2SMark Phalan emsg = krb5_get_error_message (context, retval);
9707c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO, "preauth (%s) verify failure: %s",
971159d09a2SMark Phalan pa_sys->name, emsg);
972159d09a2SMark Phalan krb5_free_error_message (context, emsg);
973159d09a2SMark Phalan /* Ignore authorization data returned from modules that fail */
974159d09a2SMark Phalan if (tmp_authz_data != NULL) {
975159d09a2SMark Phalan krb5_free_authdata(context, tmp_authz_data);
976159d09a2SMark Phalan tmp_authz_data = NULL;
977159d09a2SMark Phalan }
9787c478bd9Sstevel@tonic-gate if (pa_sys->flags & PA_REQUIRED) {
979159d09a2SMark Phalan /* free up any previous edata we might have been saving */
980159d09a2SMark Phalan if (pa_e_data != NULL)
981159d09a2SMark Phalan krb5_free_data(context, pa_e_data);
982159d09a2SMark Phalan pa_e_data = tmp_e_data;
983159d09a2SMark Phalan tmp_e_data = NULL;
984159d09a2SMark Phalan use_saved_retval = 0; /* Make sure we use the current retval */
9857c478bd9Sstevel@tonic-gate pa_ok = 0;
9867c478bd9Sstevel@tonic-gate break;
9877c478bd9Sstevel@tonic-gate }
988159d09a2SMark Phalan /*
989159d09a2SMark Phalan * We'll return edata from either the first PA_REQUIRED module
990159d09a2SMark Phalan * that fails, or the first non-PA_REQUIRED module that fails.
991159d09a2SMark Phalan * Hang on to edata from the first non-PA_REQUIRED module.
992159d09a2SMark Phalan * If we've already got one saved, simply discard this one.
993159d09a2SMark Phalan */
994159d09a2SMark Phalan if (tmp_e_data != NULL) {
995159d09a2SMark Phalan if (pa_e_data == NULL) {
996159d09a2SMark Phalan /* save the first error code and e-data */
997159d09a2SMark Phalan pa_e_data = tmp_e_data;
998159d09a2SMark Phalan tmp_e_data = NULL;
999159d09a2SMark Phalan saved_retval = retval;
1000159d09a2SMark Phalan use_saved_retval = 1;
1001159d09a2SMark Phalan } else {
1002159d09a2SMark Phalan /* discard this extra e-data from non-PA_REQUIRED module */
1003159d09a2SMark Phalan krb5_free_data(context, tmp_e_data);
1004159d09a2SMark Phalan tmp_e_data = NULL;
1005159d09a2SMark Phalan }
1006159d09a2SMark Phalan }
10077c478bd9Sstevel@tonic-gate } else {
10087c478bd9Sstevel@tonic-gate #ifdef DEBUG
10097c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
10107c478bd9Sstevel@tonic-gate #endif
1011159d09a2SMark Phalan /* Ignore any edata returned on success */
1012159d09a2SMark Phalan if (tmp_e_data != NULL) {
1013159d09a2SMark Phalan krb5_free_data(context, tmp_e_data);
1014159d09a2SMark Phalan tmp_e_data = NULL;
1015159d09a2SMark Phalan }
1016159d09a2SMark Phalan /* Add any authorization data to the ticket */
1017159d09a2SMark Phalan if (tmp_authz_data != NULL) {
1018159d09a2SMark Phalan add_authorization_data(enc_tkt_reply, tmp_authz_data);
1019159d09a2SMark Phalan free(tmp_authz_data);
1020159d09a2SMark Phalan tmp_authz_data = NULL;
1021159d09a2SMark Phalan }
10227c478bd9Sstevel@tonic-gate pa_ok = 1;
1023159d09a2SMark Phalan if (pa_sys->flags & PA_SUFFICIENT)
10247c478bd9Sstevel@tonic-gate break;
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate }
1027159d09a2SMark Phalan
1028159d09a2SMark Phalan /* Don't bother copying and returning e-data on success */
1029159d09a2SMark Phalan if (pa_ok && pa_e_data != NULL) {
1030159d09a2SMark Phalan krb5_free_data(context, pa_e_data);
1031159d09a2SMark Phalan pa_e_data = NULL;
1032159d09a2SMark Phalan }
1033159d09a2SMark Phalan /* Return any e-data from the preauth that caused us to exit the loop */
1034159d09a2SMark Phalan if (pa_e_data != NULL) {
1035159d09a2SMark Phalan e_data->data = malloc(pa_e_data->length);
1036159d09a2SMark Phalan if (e_data->data == NULL) {
1037159d09a2SMark Phalan krb5_free_data(context, pa_e_data);
1038159d09a2SMark Phalan /* Solaris Kerberos */
1039159d09a2SMark Phalan return ENOMEM;
1040159d09a2SMark Phalan }
1041159d09a2SMark Phalan memcpy(e_data->data, pa_e_data->data, pa_e_data->length);
1042159d09a2SMark Phalan e_data->length = pa_e_data->length;
1043159d09a2SMark Phalan krb5_free_data(context, pa_e_data);
1044159d09a2SMark Phalan pa_e_data = NULL;
1045159d09a2SMark Phalan if (use_saved_retval != 0)
1046159d09a2SMark Phalan retval = saved_retval;
1047159d09a2SMark Phalan }
1048159d09a2SMark Phalan
10497c478bd9Sstevel@tonic-gate if (pa_ok)
10507c478bd9Sstevel@tonic-gate return 0;
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate /* pa system was not found, but principal doesn't require preauth */
10537c478bd9Sstevel@tonic-gate if (!pa_found &&
1054159d09a2SMark Phalan !isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
1055159d09a2SMark Phalan !isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH))
10567c478bd9Sstevel@tonic-gate return 0;
10577c478bd9Sstevel@tonic-gate
1058159d09a2SMark Phalan if (!pa_found) {
1059159d09a2SMark Phalan emsg = krb5_get_error_message(context, retval);
1060159d09a2SMark Phalan krb5_klog_syslog (LOG_INFO, "no valid preauth type found: %s", emsg);
1061159d09a2SMark Phalan krb5_free_error_message(context, emsg);
1062159d09a2SMark Phalan }
1063159d09a2SMark Phalan /* The following switch statement allows us
1064159d09a2SMark Phalan * to return some preauth system errors back to the client.
1065159d09a2SMark Phalan */
1066159d09a2SMark Phalan switch(retval) {
1067159d09a2SMark Phalan case KRB5KRB_AP_ERR_BAD_INTEGRITY:
106856a424ccSmp case KRB5KRB_AP_ERR_SKEW:
1069159d09a2SMark Phalan case KRB5KDC_ERR_ETYPE_NOSUPP:
1070159d09a2SMark Phalan /* rfc 4556 */
1071159d09a2SMark Phalan case KRB5KDC_ERR_CLIENT_NOT_TRUSTED:
1072159d09a2SMark Phalan case KRB5KDC_ERR_INVALID_SIG:
1073159d09a2SMark Phalan case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
1074159d09a2SMark Phalan case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
1075159d09a2SMark Phalan case KRB5KDC_ERR_INVALID_CERTIFICATE:
1076159d09a2SMark Phalan case KRB5KDC_ERR_REVOKED_CERTIFICATE:
1077159d09a2SMark Phalan case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN:
1078159d09a2SMark Phalan case KRB5KDC_ERR_CLIENT_NAME_MISMATCH:
1079159d09a2SMark Phalan case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE:
1080159d09a2SMark Phalan case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED:
1081159d09a2SMark Phalan case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED:
1082159d09a2SMark Phalan case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED:
1083159d09a2SMark Phalan case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED:
1084159d09a2SMark Phalan /* earlier drafts of what became rfc 4556 */
1085159d09a2SMark Phalan case KRB5KDC_ERR_CERTIFICATE_MISMATCH:
1086159d09a2SMark Phalan case KRB5KDC_ERR_KDC_NOT_TRUSTED:
1087159d09a2SMark Phalan case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE:
1088159d09a2SMark Phalan /* This value is shared with KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
1089159d09a2SMark Phalan /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
109056a424ccSmp return retval;
109156a424ccSmp default:
109256a424ccSmp return KRB5KDC_ERR_PREAUTH_FAILED;
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate /*
10977c478bd9Sstevel@tonic-gate * return_padata creates any necessary preauthentication
10987c478bd9Sstevel@tonic-gate * structures which should be returned by the KDC to the client
10997c478bd9Sstevel@tonic-gate */
11007c478bd9Sstevel@tonic-gate krb5_error_code
return_padata(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,void ** padata_context)1101159d09a2SMark Phalan return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
110256a424ccSmp krb5_kdc_req *request, krb5_kdc_rep *reply,
1103159d09a2SMark Phalan krb5_key_data *client_key, krb5_keyblock *encrypting_key,
1104159d09a2SMark Phalan void **padata_context)
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate krb5_error_code retval;
11077c478bd9Sstevel@tonic-gate krb5_pa_data ** padata;
11087c478bd9Sstevel@tonic-gate krb5_pa_data ** send_pa_list;
11097c478bd9Sstevel@tonic-gate krb5_pa_data ** send_pa;
11107c478bd9Sstevel@tonic-gate krb5_pa_data * pa = 0;
11117c478bd9Sstevel@tonic-gate krb5_preauth_systems * ap;
1112159d09a2SMark Phalan int * pa_order;
1113159d09a2SMark Phalan int * pa_type;
11147c478bd9Sstevel@tonic-gate int size = 0;
1115159d09a2SMark Phalan void ** pa_context;
1116159d09a2SMark Phalan krb5_boolean key_modified;
1117159d09a2SMark Phalan krb5_keyblock original_key;
1118159d09a2SMark Phalan if ((!*padata_context)&& (make_padata_context(context, padata_context) != 0)) {
1119159d09a2SMark Phalan return KRB5KRB_ERR_GENERIC;
1120159d09a2SMark Phalan }
11217c478bd9Sstevel@tonic-gate
11227c478bd9Sstevel@tonic-gate for (ap = preauth_systems; ap->type != -1; ap++) {
11237c478bd9Sstevel@tonic-gate if (ap->return_padata)
11247c478bd9Sstevel@tonic-gate size++;
11257c478bd9Sstevel@tonic-gate }
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
11287c478bd9Sstevel@tonic-gate return ENOMEM;
1129159d09a2SMark Phalan if ((pa_order = malloc((size+1) * sizeof(int))) == NULL) {
1130159d09a2SMark Phalan free(send_pa_list);
1131159d09a2SMark Phalan return ENOMEM;
1132159d09a2SMark Phalan }
1133159d09a2SMark Phalan sort_pa_order(context, request, pa_order);
1134159d09a2SMark Phalan
1135159d09a2SMark Phalan retval = krb5_copy_keyblock_contents(context, encrypting_key,
1136159d09a2SMark Phalan &original_key);
1137159d09a2SMark Phalan if (retval) {
1138159d09a2SMark Phalan free(send_pa_list);
1139159d09a2SMark Phalan free(pa_order);
1140159d09a2SMark Phalan return retval;
1141159d09a2SMark Phalan }
1142159d09a2SMark Phalan key_modified = FALSE;
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate send_pa = send_pa_list;
11457c478bd9Sstevel@tonic-gate *send_pa = 0;
1146159d09a2SMark Phalan
1147159d09a2SMark Phalan for (pa_type = pa_order; *pa_type != -1; pa_type++) {
1148159d09a2SMark Phalan ap = &preauth_systems[*pa_type];
1149159d09a2SMark Phalan if (!key_modified)
1150159d09a2SMark Phalan if (original_key.enctype != encrypting_key->enctype)
1151159d09a2SMark Phalan key_modified = TRUE;
1152159d09a2SMark Phalan if (!key_modified)
1153159d09a2SMark Phalan if (original_key.length != encrypting_key->length)
1154159d09a2SMark Phalan key_modified = TRUE;
1155159d09a2SMark Phalan if (!key_modified)
1156159d09a2SMark Phalan if (memcmp(original_key.contents, encrypting_key->contents,
1157159d09a2SMark Phalan original_key.length) != 0)
1158159d09a2SMark Phalan key_modified = TRUE;
1159159d09a2SMark Phalan if (key_modified && (ap->flags & PA_REPLACES_KEY))
1160159d09a2SMark Phalan continue;
11617c478bd9Sstevel@tonic-gate if (ap->return_padata == 0)
11627c478bd9Sstevel@tonic-gate continue;
1163159d09a2SMark Phalan if (find_pa_context(ap, *padata_context, &pa_context))
1164159d09a2SMark Phalan continue;
11657c478bd9Sstevel@tonic-gate pa = 0;
11667c478bd9Sstevel@tonic-gate if (request->padata) {
11677c478bd9Sstevel@tonic-gate for (padata = request->padata; *padata; padata++) {
11687c478bd9Sstevel@tonic-gate if ((*padata)->pa_type == ap->type) {
11697c478bd9Sstevel@tonic-gate pa = *padata;
11707c478bd9Sstevel@tonic-gate break;
11717c478bd9Sstevel@tonic-gate }
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate }
1174159d09a2SMark Phalan if ((retval = ap->return_padata(context, pa, client, req_pkt, request, reply,
1175159d09a2SMark Phalan client_key, encrypting_key, send_pa,
1176159d09a2SMark Phalan get_entry_data, ap->plugin_context,
1177159d09a2SMark Phalan pa_context))) {
11787c478bd9Sstevel@tonic-gate goto cleanup;
1179159d09a2SMark Phalan }
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate if (*send_pa)
11827c478bd9Sstevel@tonic-gate send_pa++;
11837c478bd9Sstevel@tonic-gate *send_pa = 0;
11847c478bd9Sstevel@tonic-gate }
1185*55fea89dSDan Cross
11867c478bd9Sstevel@tonic-gate retval = 0;
11877c478bd9Sstevel@tonic-gate
11887c478bd9Sstevel@tonic-gate if (send_pa_list[0]) {
11897c478bd9Sstevel@tonic-gate reply->padata = send_pa_list;
11907c478bd9Sstevel@tonic-gate send_pa_list = 0;
11917c478bd9Sstevel@tonic-gate }
1192*55fea89dSDan Cross
11937c478bd9Sstevel@tonic-gate cleanup:
11947c478bd9Sstevel@tonic-gate if (send_pa_list)
11957c478bd9Sstevel@tonic-gate krb5_free_pa_data(context, send_pa_list);
1196159d09a2SMark Phalan
1197159d09a2SMark Phalan /* Solaris Kerberos */
1198159d09a2SMark Phalan krb5_free_keyblock_contents(context, &original_key);
1199159d09a2SMark Phalan free(pa_order);
1200159d09a2SMark Phalan
12017c478bd9Sstevel@tonic-gate return (retval);
12027c478bd9Sstevel@tonic-gate }
120356a424ccSmp
12047c478bd9Sstevel@tonic-gate static krb5_boolean
enctype_requires_etype_info_2(krb5_enctype enctype)12057c478bd9Sstevel@tonic-gate enctype_requires_etype_info_2(krb5_enctype enctype)
12067c478bd9Sstevel@tonic-gate {
12077c478bd9Sstevel@tonic-gate switch(enctype) {
12087c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC:
12097c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD4:
12107c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5:
12117c478bd9Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA1:
12127c478bd9Sstevel@tonic-gate case ENCTYPE_DES3_CBC_RAW:
12137c478bd9Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC:
12147c478bd9Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC_EXP :
12157c478bd9Sstevel@tonic-gate return 0;
12167c478bd9Sstevel@tonic-gate default:
12177c478bd9Sstevel@tonic-gate if (krb5_c_valid_enctype(enctype))
121856a424ccSmp return 1;
12197c478bd9Sstevel@tonic-gate else return 0;
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate static krb5_boolean
request_contains_enctype(krb5_context context,const krb5_kdc_req * request,krb5_enctype enctype)12247c478bd9Sstevel@tonic-gate request_contains_enctype (krb5_context context, const krb5_kdc_req *request,
12257c478bd9Sstevel@tonic-gate krb5_enctype enctype)
12267c478bd9Sstevel@tonic-gate {
12277c478bd9Sstevel@tonic-gate int i;
12287c478bd9Sstevel@tonic-gate for (i =0; i < request->nktypes; i++)
12297c478bd9Sstevel@tonic-gate if (request->ktype[i] == enctype)
12307c478bd9Sstevel@tonic-gate return 1;
12317c478bd9Sstevel@tonic-gate return 0;
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate
123456a424ccSmp
12357c478bd9Sstevel@tonic-gate static krb5_error_code
verify_enc_timestamp(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * pa,preauth_get_entry_data_proc ets_get_entry_data,void * pa_system_context,void ** pa_request_context,krb5_data ** e_data,krb5_authdata *** authz_data)123656a424ccSmp verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
1237159d09a2SMark Phalan krb5_data *req_pkt,
123856a424ccSmp krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
1239159d09a2SMark Phalan krb5_pa_data *pa,
1240159d09a2SMark Phalan preauth_get_entry_data_proc ets_get_entry_data,
1241159d09a2SMark Phalan void *pa_system_context,
1242159d09a2SMark Phalan void **pa_request_context,
1243159d09a2SMark Phalan krb5_data **e_data,
1244159d09a2SMark Phalan krb5_authdata ***authz_data)
12457c478bd9Sstevel@tonic-gate {
12467c478bd9Sstevel@tonic-gate krb5_pa_enc_ts * pa_enc = 0;
12477c478bd9Sstevel@tonic-gate krb5_error_code retval;
12487c478bd9Sstevel@tonic-gate krb5_data scratch;
12497c478bd9Sstevel@tonic-gate krb5_data enc_ts_data;
12507c478bd9Sstevel@tonic-gate krb5_enc_data *enc_data = 0;
12517c478bd9Sstevel@tonic-gate krb5_keyblock key;
12527c478bd9Sstevel@tonic-gate krb5_key_data * client_key;
12537c478bd9Sstevel@tonic-gate krb5_int32 start;
12547c478bd9Sstevel@tonic-gate krb5_timestamp timenow;
1255159d09a2SMark Phalan krb5_error_code decrypt_err = 0;
125656a424ccSmp
12577c478bd9Sstevel@tonic-gate (void) memset(&key, 0, sizeof(krb5_keyblock));
12587c478bd9Sstevel@tonic-gate scratch.data = (char *) pa->contents;
12597c478bd9Sstevel@tonic-gate scratch.length = pa->length;
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate enc_ts_data.data = 0;
1262*55fea89dSDan Cross
12637c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0)
12647c478bd9Sstevel@tonic-gate goto cleanup;
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate enc_ts_data.length = enc_data->ciphertext.length;
12677c478bd9Sstevel@tonic-gate if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL)
12687c478bd9Sstevel@tonic-gate goto cleanup;
12697c478bd9Sstevel@tonic-gate
12707c478bd9Sstevel@tonic-gate start = 0;
12717c478bd9Sstevel@tonic-gate decrypt_err = 0;
12727c478bd9Sstevel@tonic-gate while (1) {
12737c478bd9Sstevel@tonic-gate if ((retval = krb5_dbe_search_enctype(context, client,
12747c478bd9Sstevel@tonic-gate &start, enc_data->enctype,
12757c478bd9Sstevel@tonic-gate -1, 0, &client_key)))
12767c478bd9Sstevel@tonic-gate goto cleanup;
12777c478bd9Sstevel@tonic-gate
1278*55fea89dSDan Cross if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
12797c478bd9Sstevel@tonic-gate client_key, &key, NULL)))
12807c478bd9Sstevel@tonic-gate goto cleanup;
12817c478bd9Sstevel@tonic-gate
12827c478bd9Sstevel@tonic-gate key.enctype = enc_data->enctype;
12837c478bd9Sstevel@tonic-gate
12847c478bd9Sstevel@tonic-gate retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
12857c478bd9Sstevel@tonic-gate 0, enc_data, &enc_ts_data);
12867c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key);
12877c478bd9Sstevel@tonic-gate if (retval == 0)
12887c478bd9Sstevel@tonic-gate break;
12897c478bd9Sstevel@tonic-gate else
12907c478bd9Sstevel@tonic-gate decrypt_err = retval;
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate
12937c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0)
12947c478bd9Sstevel@tonic-gate goto cleanup;
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate if ((retval = krb5_timeofday(context, &timenow)) != 0)
12977c478bd9Sstevel@tonic-gate goto cleanup;
1298*55fea89dSDan Cross
12997c478bd9Sstevel@tonic-gate if (labs(timenow - pa_enc->patimestamp) > context->clockskew) {
13007c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_SKEW;
13017c478bd9Sstevel@tonic-gate goto cleanup;
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
13057c478bd9Sstevel@tonic-gate
13067c478bd9Sstevel@tonic-gate retval = 0;
1307*55fea89dSDan Cross
13087c478bd9Sstevel@tonic-gate cleanup:
13097c478bd9Sstevel@tonic-gate if (enc_data) {
13107c478bd9Sstevel@tonic-gate krb5_free_data_contents(context, &enc_data->ciphertext);
13117c478bd9Sstevel@tonic-gate free(enc_data);
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate krb5_free_data_contents(context, &enc_ts_data);
13147c478bd9Sstevel@tonic-gate if (pa_enc)
13157c478bd9Sstevel@tonic-gate free(pa_enc);
13167c478bd9Sstevel@tonic-gate /*
13177c478bd9Sstevel@tonic-gate * If we get NO_MATCHING_KEY and decryption previously failed, and
13187c478bd9Sstevel@tonic-gate * we failed to find any other keys of the correct enctype after
13197c478bd9Sstevel@tonic-gate * that failed decryption, it probably means that the password was
13207c478bd9Sstevel@tonic-gate * incorrect.
13217c478bd9Sstevel@tonic-gate */
13227c478bd9Sstevel@tonic-gate if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0)
13237c478bd9Sstevel@tonic-gate retval = decrypt_err;
13247c478bd9Sstevel@tonic-gate return retval;
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate
13277c478bd9Sstevel@tonic-gate static krb5_error_code
_make_etype_info_entry(krb5_context context,krb5_kdc_req * request,krb5_key_data * client_key,krb5_enctype etype,krb5_etype_info_entry ** entry,int etype_info2)13287c478bd9Sstevel@tonic-gate _make_etype_info_entry(krb5_context context,
132956a424ccSmp krb5_kdc_req *request, krb5_key_data *client_key,
133056a424ccSmp krb5_enctype etype, krb5_etype_info_entry **entry,
133156a424ccSmp int etype_info2)
13327c478bd9Sstevel@tonic-gate {
13337c478bd9Sstevel@tonic-gate krb5_data salt;
1334*55fea89dSDan Cross krb5_etype_info_entry * tmp_entry;
13357c478bd9Sstevel@tonic-gate krb5_error_code retval;
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate if ((tmp_entry = malloc(sizeof(krb5_etype_info_entry))) == NULL)
13387c478bd9Sstevel@tonic-gate return ENOMEM;
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate salt.data = 0;
13417c478bd9Sstevel@tonic-gate
13427c478bd9Sstevel@tonic-gate tmp_entry->magic = KV5M_ETYPE_INFO_ENTRY;
13437c478bd9Sstevel@tonic-gate tmp_entry->etype = etype;
13447c478bd9Sstevel@tonic-gate tmp_entry->length = KRB5_ETYPE_NO_SALT;
13457c478bd9Sstevel@tonic-gate tmp_entry->salt = 0;
13467c478bd9Sstevel@tonic-gate tmp_entry->s2kparams.data = NULL;
13477c478bd9Sstevel@tonic-gate tmp_entry->s2kparams.length = 0;
13487c478bd9Sstevel@tonic-gate retval = get_salt_from_key(context, request->client,
13497c478bd9Sstevel@tonic-gate client_key, &salt);
13507c478bd9Sstevel@tonic-gate if (retval)
13517c478bd9Sstevel@tonic-gate goto fail;
13527c478bd9Sstevel@tonic-gate if (etype_info2 && client_key->key_data_ver > 1 &&
13537c478bd9Sstevel@tonic-gate client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) {
13547c478bd9Sstevel@tonic-gate switch (etype) {
13557c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC:
13567c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD4:
13577c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5:
135856a424ccSmp tmp_entry->s2kparams.data = malloc(1);
135956a424ccSmp if (tmp_entry->s2kparams.data == NULL) {
13607c478bd9Sstevel@tonic-gate retval = ENOMEM;
13617c478bd9Sstevel@tonic-gate goto fail;
136256a424ccSmp }
136356a424ccSmp tmp_entry->s2kparams.length = 1;
136456a424ccSmp tmp_entry->s2kparams.data[0] = 1;
136556a424ccSmp break;
13667c478bd9Sstevel@tonic-gate default:
136756a424ccSmp break;
13687c478bd9Sstevel@tonic-gate }
13697c478bd9Sstevel@tonic-gate }
13707c478bd9Sstevel@tonic-gate
13717c478bd9Sstevel@tonic-gate if (salt.length >= 0) {
13727c478bd9Sstevel@tonic-gate tmp_entry->length = salt.length;
13737c478bd9Sstevel@tonic-gate tmp_entry->salt = (unsigned char *) salt.data;
13747c478bd9Sstevel@tonic-gate salt.data = 0;
13757c478bd9Sstevel@tonic-gate }
13767c478bd9Sstevel@tonic-gate *entry = tmp_entry;
13777c478bd9Sstevel@tonic-gate return 0;
13787c478bd9Sstevel@tonic-gate
13797c478bd9Sstevel@tonic-gate fail:
13807c478bd9Sstevel@tonic-gate if (tmp_entry) {
13817c478bd9Sstevel@tonic-gate if (tmp_entry->s2kparams.data)
138256a424ccSmp free(tmp_entry->s2kparams.data);
13837c478bd9Sstevel@tonic-gate free(tmp_entry);
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate if (salt.data)
13867c478bd9Sstevel@tonic-gate free(salt.data);
13877c478bd9Sstevel@tonic-gate return retval;
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate /*
13907c478bd9Sstevel@tonic-gate * This function returns the etype information for a particular
13917c478bd9Sstevel@tonic-gate * client, to be passed back in the preauth list in the KRB_ERROR
13927c478bd9Sstevel@tonic-gate * message. It supports generating both etype_info and etype_info2
1393*55fea89dSDan Cross * as most of the work is the same.
13947c478bd9Sstevel@tonic-gate */
13957c478bd9Sstevel@tonic-gate static krb5_error_code
etype_info_helper(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_pa_data * pa_data,int etype_info2)13967c478bd9Sstevel@tonic-gate etype_info_helper(krb5_context context, krb5_kdc_req *request,
139756a424ccSmp krb5_db_entry *client, krb5_db_entry *server,
139856a424ccSmp krb5_pa_data *pa_data, int etype_info2)
13997c478bd9Sstevel@tonic-gate {
14007c478bd9Sstevel@tonic-gate krb5_etype_info_entry ** entry = 0;
14017c478bd9Sstevel@tonic-gate krb5_key_data *client_key;
14027c478bd9Sstevel@tonic-gate krb5_error_code retval;
14037c478bd9Sstevel@tonic-gate krb5_data * scratch;
14047c478bd9Sstevel@tonic-gate krb5_enctype db_etype;
140556a424ccSmp int i = 0;
140656a424ccSmp int start = 0;
14077c478bd9Sstevel@tonic-gate int seen_des = 0;
14087c478bd9Sstevel@tonic-gate
140956a424ccSmp entry = malloc((client->n_key_data * 2 + 1) * sizeof(krb5_etype_info_entry *));
14107c478bd9Sstevel@tonic-gate if (entry == NULL)
14117c478bd9Sstevel@tonic-gate return ENOMEM;
14127c478bd9Sstevel@tonic-gate entry[0] = NULL;
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate while (1) {
14157c478bd9Sstevel@tonic-gate retval = krb5_dbe_search_enctype(context, client, &start, -1,
141656a424ccSmp -1, 0, &client_key);
14177c478bd9Sstevel@tonic-gate if (retval == KRB5_KDB_NO_MATCHING_KEY)
141856a424ccSmp break;
14197c478bd9Sstevel@tonic-gate if (retval)
142056a424ccSmp goto cleanup;
14217c478bd9Sstevel@tonic-gate db_etype = client_key->key_data_type[0];
14227c478bd9Sstevel@tonic-gate if (db_etype == ENCTYPE_DES_CBC_MD4)
142356a424ccSmp db_etype = ENCTYPE_DES_CBC_MD5;
1424*55fea89dSDan Cross
14257c478bd9Sstevel@tonic-gate if (request_contains_enctype(context, request, db_etype)) {
142656a424ccSmp assert(etype_info2 ||
142756a424ccSmp !enctype_requires_etype_info_2(db_etype));
142856a424ccSmp if ((retval = _make_etype_info_entry(context, request, client_key,
142956a424ccSmp db_etype, &entry[i], etype_info2)) != 0) {
14307c478bd9Sstevel@tonic-gate goto cleanup;
143156a424ccSmp }
143256a424ccSmp entry[i+1] = 0;
143356a424ccSmp i++;
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate
1436*55fea89dSDan Cross /*
143756a424ccSmp * If there is a des key in the kdb, try the "similar" enctypes,
1438*55fea89dSDan Cross * avoid duplicate entries.
14397c478bd9Sstevel@tonic-gate */
14407c478bd9Sstevel@tonic-gate if (!seen_des) {
144156a424ccSmp switch (db_etype) {
144256a424ccSmp case ENCTYPE_DES_CBC_MD5:
14437c478bd9Sstevel@tonic-gate db_etype = ENCTYPE_DES_CBC_CRC;
14447c478bd9Sstevel@tonic-gate break;
144556a424ccSmp case ENCTYPE_DES_CBC_CRC:
14467c478bd9Sstevel@tonic-gate db_etype = ENCTYPE_DES_CBC_MD5;
14477c478bd9Sstevel@tonic-gate break;
144856a424ccSmp default:
14497c478bd9Sstevel@tonic-gate continue;
14507c478bd9Sstevel@tonic-gate
145156a424ccSmp }
145256a424ccSmp if (request_contains_enctype(context, request, db_etype)) {
14537c478bd9Sstevel@tonic-gate if ((retval = _make_etype_info_entry(context, request,
145456a424ccSmp client_key, db_etype, &entry[i], etype_info2)) != 0) {
145556a424ccSmp goto cleanup;
14567c478bd9Sstevel@tonic-gate }
145756a424ccSmp entry[i+1] = 0;
14587c478bd9Sstevel@tonic-gate i++;
145956a424ccSmp }
146056a424ccSmp seen_des++;
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate }
14637c478bd9Sstevel@tonic-gate if (etype_info2)
1464ba7b222eSGlenn Barry retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry,
146556a424ccSmp &scratch);
1466ba7b222eSGlenn Barry else retval = encode_krb5_etype_info((krb5_etype_info_entry * const*) entry,
146756a424ccSmp &scratch);
14687c478bd9Sstevel@tonic-gate if (retval)
14697c478bd9Sstevel@tonic-gate goto cleanup;
14707c478bd9Sstevel@tonic-gate pa_data->contents = (unsigned char *)scratch->data;
14717c478bd9Sstevel@tonic-gate pa_data->length = scratch->length;
14727c478bd9Sstevel@tonic-gate free(scratch);
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate retval = 0;
14757c478bd9Sstevel@tonic-gate
14767c478bd9Sstevel@tonic-gate cleanup:
14777c478bd9Sstevel@tonic-gate if (entry)
14787c478bd9Sstevel@tonic-gate krb5_free_etype_info(context, entry);
14797c478bd9Sstevel@tonic-gate return retval;
14807c478bd9Sstevel@tonic-gate }
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate static krb5_error_code
get_etype_info(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,krb5_pa_data * pa_data)14837c478bd9Sstevel@tonic-gate get_etype_info(krb5_context context, krb5_kdc_req *request,
148456a424ccSmp krb5_db_entry *client, krb5_db_entry *server,
1485159d09a2SMark Phalan preauth_get_entry_data_proc etype_get_entry_data,
1486159d09a2SMark Phalan void *pa_system_context,
148756a424ccSmp krb5_pa_data *pa_data)
14887c478bd9Sstevel@tonic-gate {
14897c478bd9Sstevel@tonic-gate int i;
14907c478bd9Sstevel@tonic-gate for (i=0; i < request->nktypes; i++) {
1491*55fea89dSDan Cross if (enctype_requires_etype_info_2(request->ktype[i]))
149256a424ccSmp return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will
149356a424ccSmp * skip this
149456a424ccSmp * type*/
14957c478bd9Sstevel@tonic-gate }
14967c478bd9Sstevel@tonic-gate return etype_info_helper(context, request, client, server, pa_data, 0);
14977c478bd9Sstevel@tonic-gate }
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate static krb5_error_code
get_etype_info2(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,krb5_pa_data * pa_data)15007c478bd9Sstevel@tonic-gate get_etype_info2(krb5_context context, krb5_kdc_req *request,
150156a424ccSmp krb5_db_entry *client, krb5_db_entry *server,
1502159d09a2SMark Phalan preauth_get_entry_data_proc etype_get_entry_data,
1503159d09a2SMark Phalan void *pa_system_context,
150456a424ccSmp krb5_pa_data *pa_data)
15057c478bd9Sstevel@tonic-gate {
15067c478bd9Sstevel@tonic-gate return etype_info_helper( context, request, client, server, pa_data, 1);
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate static krb5_error_code
etype_info_as_rep_helper(krb5_context context,krb5_pa_data * padata,krb5_db_entry * client,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,int etype_info2)1510*55fea89dSDan Cross etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
1511159d09a2SMark Phalan krb5_db_entry *client,
1512159d09a2SMark Phalan krb5_kdc_req *request, krb5_kdc_rep *reply,
1513159d09a2SMark Phalan krb5_key_data *client_key,
1514159d09a2SMark Phalan krb5_keyblock *encrypting_key,
1515159d09a2SMark Phalan krb5_pa_data **send_pa,
1516159d09a2SMark Phalan int etype_info2)
15177c478bd9Sstevel@tonic-gate {
1518159d09a2SMark Phalan int i;
15197c478bd9Sstevel@tonic-gate krb5_error_code retval;
15207c478bd9Sstevel@tonic-gate krb5_pa_data *tmp_padata;
15217c478bd9Sstevel@tonic-gate krb5_etype_info_entry **entry = NULL;
15227c478bd9Sstevel@tonic-gate krb5_data *scratch = NULL;
1523159d09a2SMark Phalan
1524159d09a2SMark Phalan /*
1525159d09a2SMark Phalan * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer"
1526159d09a2SMark Phalan * enctypes.
1527159d09a2SMark Phalan */
1528159d09a2SMark Phalan if (!etype_info2) {
1529159d09a2SMark Phalan for (i = 0; i < request->nktypes; i++) {
1530159d09a2SMark Phalan if (enctype_requires_etype_info_2(request->ktype[i])) {
1531159d09a2SMark Phalan *send_pa = NULL;
1532159d09a2SMark Phalan return 0;
1533159d09a2SMark Phalan }
1534159d09a2SMark Phalan }
1535159d09a2SMark Phalan }
1536159d09a2SMark Phalan
15377c478bd9Sstevel@tonic-gate tmp_padata = malloc( sizeof(krb5_pa_data));
15387c478bd9Sstevel@tonic-gate if (tmp_padata == NULL)
15397c478bd9Sstevel@tonic-gate return ENOMEM;
1540159d09a2SMark Phalan if (etype_info2)
1541159d09a2SMark Phalan tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2;
1542159d09a2SMark Phalan else
1543159d09a2SMark Phalan tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO;
1544159d09a2SMark Phalan
15457c478bd9Sstevel@tonic-gate entry = malloc(2 * sizeof(krb5_etype_info_entry *));
15467c478bd9Sstevel@tonic-gate if (entry == NULL) {
15477c478bd9Sstevel@tonic-gate retval = ENOMEM;
15487c478bd9Sstevel@tonic-gate goto cleanup;
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate entry[0] = NULL;
15517c478bd9Sstevel@tonic-gate entry[1] = NULL;
1552159d09a2SMark Phalan retval = _make_etype_info_entry(context, request,
1553159d09a2SMark Phalan client_key, encrypting_key->enctype,
1554159d09a2SMark Phalan entry, etype_info2);
15557c478bd9Sstevel@tonic-gate if (retval)
15567c478bd9Sstevel@tonic-gate goto cleanup;
1557159d09a2SMark Phalan
1558159d09a2SMark Phalan if (etype_info2)
1559ba7b222eSGlenn Barry retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry, &scratch);
1560159d09a2SMark Phalan else
1561ba7b222eSGlenn Barry retval = encode_krb5_etype_info((krb5_etype_info_entry * const*) entry, &scratch);
1562159d09a2SMark Phalan
15637c478bd9Sstevel@tonic-gate if (retval)
15647c478bd9Sstevel@tonic-gate goto cleanup;
15657c478bd9Sstevel@tonic-gate tmp_padata->contents = (uchar_t *)scratch->data;
15667c478bd9Sstevel@tonic-gate tmp_padata->length = scratch->length;
15677c478bd9Sstevel@tonic-gate *send_pa = tmp_padata;
15687c478bd9Sstevel@tonic-gate
1569*55fea89dSDan Cross /* For cleanup - we no longer own the contents of the krb5_data
15707c478bd9Sstevel@tonic-gate * only to pointer to the krb5_data
15717c478bd9Sstevel@tonic-gate */
157256a424ccSmp scratch->data = 0;
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate cleanup:
15757c478bd9Sstevel@tonic-gate if (entry)
15767c478bd9Sstevel@tonic-gate krb5_free_etype_info(context, entry);
15777c478bd9Sstevel@tonic-gate if (retval) {
15787c478bd9Sstevel@tonic-gate if (tmp_padata)
157956a424ccSmp free(tmp_padata);
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate if (scratch)
158256a424ccSmp krb5_free_data(context, scratch);
15837c478bd9Sstevel@tonic-gate return retval;
15847c478bd9Sstevel@tonic-gate }
15857c478bd9Sstevel@tonic-gate
1586159d09a2SMark Phalan static krb5_error_code
return_etype_info2(krb5_context context,krb5_pa_data * padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,void ** pa_request_context)1587*55fea89dSDan Cross return_etype_info2(krb5_context context, krb5_pa_data * padata,
1588159d09a2SMark Phalan krb5_db_entry *client,
1589159d09a2SMark Phalan krb5_data *req_pkt,
1590159d09a2SMark Phalan krb5_kdc_req *request, krb5_kdc_rep *reply,
1591159d09a2SMark Phalan krb5_key_data *client_key,
1592159d09a2SMark Phalan krb5_keyblock *encrypting_key,
1593159d09a2SMark Phalan krb5_pa_data **send_pa,
1594159d09a2SMark Phalan preauth_get_entry_data_proc etype_get_entry_data,
1595159d09a2SMark Phalan void *pa_system_context,
1596159d09a2SMark Phalan void **pa_request_context)
1597159d09a2SMark Phalan {
1598159d09a2SMark Phalan return etype_info_as_rep_helper(context, padata, client, request, reply,
1599159d09a2SMark Phalan client_key, encrypting_key, send_pa, 1);
1600159d09a2SMark Phalan }
1601159d09a2SMark Phalan
1602159d09a2SMark Phalan
1603159d09a2SMark Phalan static krb5_error_code
return_etype_info(krb5_context context,krb5_pa_data * padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc etypeget_entry_data,void * pa_system_context,void ** pa_request_context)1604*55fea89dSDan Cross return_etype_info(krb5_context context, krb5_pa_data * padata,
1605159d09a2SMark Phalan krb5_db_entry *client,
1606159d09a2SMark Phalan krb5_data *req_pkt,
1607159d09a2SMark Phalan krb5_kdc_req *request, krb5_kdc_rep *reply,
1608159d09a2SMark Phalan krb5_key_data *client_key,
1609159d09a2SMark Phalan krb5_keyblock *encrypting_key,
1610159d09a2SMark Phalan krb5_pa_data **send_pa,
1611159d09a2SMark Phalan preauth_get_entry_data_proc etypeget_entry_data,
1612159d09a2SMark Phalan void *pa_system_context,
1613159d09a2SMark Phalan void **pa_request_context)
1614159d09a2SMark Phalan {
1615159d09a2SMark Phalan return etype_info_as_rep_helper(context, padata, client, request, reply,
1616159d09a2SMark Phalan client_key, encrypting_key, send_pa, 0);
1617159d09a2SMark Phalan }
16187c478bd9Sstevel@tonic-gate
16197c478bd9Sstevel@tonic-gate static krb5_error_code
return_pw_salt(krb5_context context,krb5_pa_data * in_padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,void ** pa_request_context)162056a424ccSmp return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
1621159d09a2SMark Phalan krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request,
162256a424ccSmp krb5_kdc_rep *reply, krb5_key_data *client_key,
1623159d09a2SMark Phalan krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
1624159d09a2SMark Phalan preauth_get_entry_data_proc etype_get_entry_data,
1625159d09a2SMark Phalan void *pa_system_context,
1626159d09a2SMark Phalan void **pa_request_context)
16277c478bd9Sstevel@tonic-gate {
16287c478bd9Sstevel@tonic-gate krb5_error_code retval;
16297c478bd9Sstevel@tonic-gate krb5_pa_data * padata;
16307c478bd9Sstevel@tonic-gate krb5_data * scratch;
16317c478bd9Sstevel@tonic-gate krb5_data salt_data;
16327c478bd9Sstevel@tonic-gate int i;
1633*55fea89dSDan Cross
16347c478bd9Sstevel@tonic-gate for (i = 0; i < request->nktypes; i++) {
16357c478bd9Sstevel@tonic-gate if (enctype_requires_etype_info_2(request->ktype[i]))
163656a424ccSmp return 0;
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate if (client_key->key_data_ver == 1 ||
16397c478bd9Sstevel@tonic-gate client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)
16407c478bd9Sstevel@tonic-gate return 0;
16417c478bd9Sstevel@tonic-gate
16427c478bd9Sstevel@tonic-gate if ((padata = malloc(sizeof(krb5_pa_data))) == NULL)
16437c478bd9Sstevel@tonic-gate return ENOMEM;
16447c478bd9Sstevel@tonic-gate padata->magic = KV5M_PA_DATA;
16457c478bd9Sstevel@tonic-gate padata->pa_type = KRB5_PADATA_PW_SALT;
1646*55fea89dSDan Cross
16477c478bd9Sstevel@tonic-gate switch (client_key->key_data_type[1]) {
16487c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_V4:
16497c478bd9Sstevel@tonic-gate /* send an empty (V4) salt */
16507c478bd9Sstevel@tonic-gate padata->contents = 0;
16517c478bd9Sstevel@tonic-gate padata->length = 0;
16527c478bd9Sstevel@tonic-gate break;
16537c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_NOREALM:
1654*55fea89dSDan Cross if ((retval = krb5_principal2salt_norealm(kdc_context,
16557c478bd9Sstevel@tonic-gate request->client,
16567c478bd9Sstevel@tonic-gate &salt_data)))
16577c478bd9Sstevel@tonic-gate goto cleanup;
16587c478bd9Sstevel@tonic-gate padata->contents = (krb5_octet *)salt_data.data;
16597c478bd9Sstevel@tonic-gate padata->length = salt_data.length;
16607c478bd9Sstevel@tonic-gate break;
16617c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_AFS3:
16627c478bd9Sstevel@tonic-gate /* send an AFS style realm-based salt */
16637c478bd9Sstevel@tonic-gate /* for now, just pass the realm back and let the client
16647c478bd9Sstevel@tonic-gate do the work. In the future, add a kdc configuration
16657c478bd9Sstevel@tonic-gate variable that specifies the old cell name. */
16667c478bd9Sstevel@tonic-gate padata->pa_type = KRB5_PADATA_AFS3_SALT;
16677c478bd9Sstevel@tonic-gate /* it would be just like ONLYREALM, but we need to pass the 0 */
16687c478bd9Sstevel@tonic-gate scratch = krb5_princ_realm(kdc_context, request->client);
16697c478bd9Sstevel@tonic-gate if ((padata->contents = malloc(scratch->length+1)) == NULL) {
16707c478bd9Sstevel@tonic-gate retval = ENOMEM;
16717c478bd9Sstevel@tonic-gate goto cleanup;
16727c478bd9Sstevel@tonic-gate }
16737c478bd9Sstevel@tonic-gate memcpy(padata->contents, scratch->data, scratch->length);
16747c478bd9Sstevel@tonic-gate padata->length = scratch->length+1;
16757c478bd9Sstevel@tonic-gate padata->contents[scratch->length] = 0;
16767c478bd9Sstevel@tonic-gate break;
16777c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_ONLYREALM:
16787c478bd9Sstevel@tonic-gate scratch = krb5_princ_realm(kdc_context, request->client);
16797c478bd9Sstevel@tonic-gate if ((padata->contents = malloc(scratch->length)) == NULL) {
16807c478bd9Sstevel@tonic-gate retval = ENOMEM;
16817c478bd9Sstevel@tonic-gate goto cleanup;
16827c478bd9Sstevel@tonic-gate }
16837c478bd9Sstevel@tonic-gate memcpy(padata->contents, scratch->data, scratch->length);
16847c478bd9Sstevel@tonic-gate padata->length = scratch->length;
16857c478bd9Sstevel@tonic-gate break;
16867c478bd9Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_SPECIAL:
16877c478bd9Sstevel@tonic-gate if ((padata->contents = malloc(client_key->key_data_length[1]))
16887c478bd9Sstevel@tonic-gate == NULL) {
16897c478bd9Sstevel@tonic-gate retval = ENOMEM;
16907c478bd9Sstevel@tonic-gate goto cleanup;
16917c478bd9Sstevel@tonic-gate }
16927c478bd9Sstevel@tonic-gate memcpy(padata->contents, client_key->key_data_contents[1],
16937c478bd9Sstevel@tonic-gate client_key->key_data_length[1]);
16947c478bd9Sstevel@tonic-gate padata->length = client_key->key_data_length[1];
16957c478bd9Sstevel@tonic-gate break;
16967c478bd9Sstevel@tonic-gate default:
16977c478bd9Sstevel@tonic-gate free(padata);
16987c478bd9Sstevel@tonic-gate return 0;
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate *send_pa = padata;
17027c478bd9Sstevel@tonic-gate return 0;
1703*55fea89dSDan Cross
17047c478bd9Sstevel@tonic-gate cleanup:
17057c478bd9Sstevel@tonic-gate free(padata);
17067c478bd9Sstevel@tonic-gate return retval;
17077c478bd9Sstevel@tonic-gate }
17087c478bd9Sstevel@tonic-gate
17097c478bd9Sstevel@tonic-gate static krb5_error_code
return_sam_data(krb5_context context,krb5_pa_data * in_padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc sam_get_entry_data,void * pa_system_context,void ** pa_request_context)171056a424ccSmp return_sam_data(krb5_context context, krb5_pa_data *in_padata,
1711159d09a2SMark Phalan krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request,
171256a424ccSmp krb5_kdc_rep *reply, krb5_key_data *client_key,
1713159d09a2SMark Phalan krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
1714159d09a2SMark Phalan preauth_get_entry_data_proc sam_get_entry_data,
1715159d09a2SMark Phalan void *pa_system_context,
1716159d09a2SMark Phalan void **pa_request_context)
17177c478bd9Sstevel@tonic-gate {
17187c478bd9Sstevel@tonic-gate krb5_error_code retval;
17197c478bd9Sstevel@tonic-gate krb5_data scratch;
17207c478bd9Sstevel@tonic-gate int i;
17217c478bd9Sstevel@tonic-gate
17227c478bd9Sstevel@tonic-gate krb5_sam_response *sr = 0;
17237c478bd9Sstevel@tonic-gate krb5_predicted_sam_response *psr = 0;
17247c478bd9Sstevel@tonic-gate
17257c478bd9Sstevel@tonic-gate if (in_padata == 0)
17267c478bd9Sstevel@tonic-gate return 0;
17277c478bd9Sstevel@tonic-gate
17287c478bd9Sstevel@tonic-gate /*
17297c478bd9Sstevel@tonic-gate * We start by doing the same thing verify_sam_response() does:
17307c478bd9Sstevel@tonic-gate * extract the psr from the padata (which is an sr). Nothing
17317c478bd9Sstevel@tonic-gate * here should generate errors! We've already successfully done
17327c478bd9Sstevel@tonic-gate * all this once.
17337c478bd9Sstevel@tonic-gate */
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate scratch.data = (char *) in_padata->contents; /* SUNWresync121 XXX */
17367c478bd9Sstevel@tonic-gate scratch.length = in_padata->length;
1737*55fea89dSDan Cross
17387c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
17397c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval,
17407c478bd9Sstevel@tonic-gate gettext("return_sam_data(): decode_krb5_sam_response failed"));
17417c478bd9Sstevel@tonic-gate goto cleanup;
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate
17447c478bd9Sstevel@tonic-gate {
17457c478bd9Sstevel@tonic-gate krb5_enc_data tmpdata;
17467c478bd9Sstevel@tonic-gate
17477c478bd9Sstevel@tonic-gate tmpdata.enctype = ENCTYPE_UNKNOWN;
17487c478bd9Sstevel@tonic-gate tmpdata.ciphertext = sr->sam_track_id;
17497c478bd9Sstevel@tonic-gate
17507c478bd9Sstevel@tonic-gate scratch.length = tmpdata.ciphertext.length;
17517c478bd9Sstevel@tonic-gate if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
17527c478bd9Sstevel@tonic-gate retval = ENOMEM;
17537c478bd9Sstevel@tonic-gate goto cleanup;
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate
17567c478bd9Sstevel@tonic-gate if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
17577c478bd9Sstevel@tonic-gate &tmpdata, &scratch))) {
17587c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval,
17597c478bd9Sstevel@tonic-gate gettext("return_sam_data(): decrypt track_id failed"));
17607c478bd9Sstevel@tonic-gate free(scratch.data);
17617c478bd9Sstevel@tonic-gate goto cleanup;
17627c478bd9Sstevel@tonic-gate }
17637c478bd9Sstevel@tonic-gate }
17647c478bd9Sstevel@tonic-gate
17657c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
17667c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval,
17677c478bd9Sstevel@tonic-gate gettext(
17687c478bd9Sstevel@tonic-gate "return_sam_data(): decode_krb5_predicted_sam_response failed"));
17697c478bd9Sstevel@tonic-gate free(scratch.data);
17707c478bd9Sstevel@tonic-gate goto cleanup;
17717c478bd9Sstevel@tonic-gate }
17727c478bd9Sstevel@tonic-gate
17737c478bd9Sstevel@tonic-gate /* We could use sr->sam_flags, but it may be absent or altered. */
17747c478bd9Sstevel@tonic-gate if (psr->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
17757c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
17767c478bd9Sstevel@tonic-gate gettext("Unsupported SAM flag must-pk-encrypt-sad"));
17777c478bd9Sstevel@tonic-gate goto cleanup;
17787c478bd9Sstevel@tonic-gate }
17797c478bd9Sstevel@tonic-gate if (psr->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
17807c478bd9Sstevel@tonic-gate /* No key munging */
17817c478bd9Sstevel@tonic-gate goto cleanup;
17827c478bd9Sstevel@tonic-gate }
17837c478bd9Sstevel@tonic-gate if (psr->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
17847c478bd9Sstevel@tonic-gate /* Use sam_key instead of client key */
17857c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, encrypting_key);
17867c478bd9Sstevel@tonic-gate krb5_copy_keyblock_contents(context, &psr->sam_key, encrypting_key);
17877c478bd9Sstevel@tonic-gate /* XXX Attach a useful pa_data */
17887c478bd9Sstevel@tonic-gate goto cleanup;
17897c478bd9Sstevel@tonic-gate }
17907c478bd9Sstevel@tonic-gate
17917c478bd9Sstevel@tonic-gate /* Otherwise (no flags set), we XOR the keys */
17927c478bd9Sstevel@tonic-gate /* XXX The passwords-04 draft is underspecified here wrt different
17937c478bd9Sstevel@tonic-gate key types. We will do what I hope to get into the -05 draft. */
17947c478bd9Sstevel@tonic-gate {
17957c478bd9Sstevel@tonic-gate krb5_octet *p = encrypting_key->contents;
17967c478bd9Sstevel@tonic-gate krb5_octet *q = psr->sam_key.contents;
17977c478bd9Sstevel@tonic-gate int length = ((encrypting_key->length < psr->sam_key.length)
17987c478bd9Sstevel@tonic-gate ? encrypting_key->length
17997c478bd9Sstevel@tonic-gate : psr->sam_key.length);
18007c478bd9Sstevel@tonic-gate
18017c478bd9Sstevel@tonic-gate for (i = 0; i < length; i++)
18027c478bd9Sstevel@tonic-gate p[i] ^= q[i];
18037c478bd9Sstevel@tonic-gate }
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate /* Post-mixing key correction */
18067c478bd9Sstevel@tonic-gate switch (encrypting_key->enctype) {
18077c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC:
18087c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD4:
18097c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5:
18107c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_RAW:
18117c478bd9Sstevel@tonic-gate mit_des_fixup_key_parity(encrypting_key->contents);
18127c478bd9Sstevel@tonic-gate if (mit_des_is_weak_key(encrypting_key->contents))
18137c478bd9Sstevel@tonic-gate ((krb5_octet *) encrypting_key->contents)[7] ^= 0xf0;
18147c478bd9Sstevel@tonic-gate break;
18157c478bd9Sstevel@tonic-gate
18167c478bd9Sstevel@tonic-gate /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */
18177c478bd9Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA: /* XXX deprecated? */
18187c478bd9Sstevel@tonic-gate case ENCTYPE_DES3_CBC_RAW:
18197c478bd9Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA1:
18207c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) {
18217c478bd9Sstevel@tonic-gate mit_des_fixup_key_parity(encrypting_key->contents + i * 8);
18227c478bd9Sstevel@tonic-gate if (mit_des_is_weak_key(encrypting_key->contents + i * 8))
18237c478bd9Sstevel@tonic-gate ((krb5_octet *) encrypting_key->contents)[7 + i * 8] ^= 0xf0;
18247c478bd9Sstevel@tonic-gate }
18257c478bd9Sstevel@tonic-gate break;
18267c478bd9Sstevel@tonic-gate
18277c478bd9Sstevel@tonic-gate default:
18287c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
18297c478bd9Sstevel@tonic-gate gettext("Unimplemented keytype for SAM key mixing"));
18307c478bd9Sstevel@tonic-gate goto cleanup;
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate /* XXX Attach a useful pa_data */
18347c478bd9Sstevel@tonic-gate cleanup:
18357c478bd9Sstevel@tonic-gate if (sr)
18367c478bd9Sstevel@tonic-gate krb5_free_sam_response(context, sr);
18377c478bd9Sstevel@tonic-gate if (psr)
18387c478bd9Sstevel@tonic-gate krb5_free_predicted_sam_response(context, psr);
18397c478bd9Sstevel@tonic-gate
18407c478bd9Sstevel@tonic-gate return retval;
18417c478bd9Sstevel@tonic-gate }
1842*55fea89dSDan Cross
18437c478bd9Sstevel@tonic-gate static struct {
18447c478bd9Sstevel@tonic-gate char* name;
18457c478bd9Sstevel@tonic-gate int sam_type;
18467c478bd9Sstevel@tonic-gate } *sam_ptr, sam_inst_map[] = {
18477c478bd9Sstevel@tonic-gate #if 0 /* SUNWresync121 - unsupported hardware and kdc.log annoyance */
18487c478bd9Sstevel@tonic-gate { "SNK4", PA_SAM_TYPE_DIGI_PATH, },
18497c478bd9Sstevel@tonic-gate { "SECURID", PA_SAM_TYPE_SECURID, },
18507c478bd9Sstevel@tonic-gate { "GRAIL", PA_SAM_TYPE_GRAIL, },
18517c478bd9Sstevel@tonic-gate #endif
18527c478bd9Sstevel@tonic-gate { 0, 0 },
18537c478bd9Sstevel@tonic-gate };
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate static krb5_error_code
get_sam_edata(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,preauth_get_entry_data_proc sam_get_entry_data,void * pa_system_context,krb5_pa_data * pa_data)185656a424ccSmp get_sam_edata(krb5_context context, krb5_kdc_req *request,
185756a424ccSmp krb5_db_entry *client, krb5_db_entry *server,
1858159d09a2SMark Phalan preauth_get_entry_data_proc sam_get_entry_data,
1859159d09a2SMark Phalan void *pa_system_context, krb5_pa_data *pa_data)
18607c478bd9Sstevel@tonic-gate {
18617c478bd9Sstevel@tonic-gate krb5_error_code retval;
18627c478bd9Sstevel@tonic-gate krb5_sam_challenge sc;
18637c478bd9Sstevel@tonic-gate krb5_predicted_sam_response psr;
18647c478bd9Sstevel@tonic-gate krb5_data * scratch;
18657c478bd9Sstevel@tonic-gate krb5_keyblock encrypting_key;
18667c478bd9Sstevel@tonic-gate char response[9];
18677c478bd9Sstevel@tonic-gate char inputblock[8];
18687c478bd9Sstevel@tonic-gate krb5_data predict_response;
18697c478bd9Sstevel@tonic-gate
18707c478bd9Sstevel@tonic-gate (void) memset(&encrypting_key, 0, sizeof(krb5_keyblock));
18717c478bd9Sstevel@tonic-gate (void) memset(&sc, 0, sizeof(sc));
18727c478bd9Sstevel@tonic-gate (void) memset(&psr, 0, sizeof(psr));
18737c478bd9Sstevel@tonic-gate
18747c478bd9Sstevel@tonic-gate /* Given the client name we can figure out what type of preauth
18757c478bd9Sstevel@tonic-gate they need. The spec is currently for querying the database for
18767c478bd9Sstevel@tonic-gate names that match the types of preauth used. Later we should
18777c478bd9Sstevel@tonic-gate make this mapping show up in kdc.conf. In the meantime, we
18787c478bd9Sstevel@tonic-gate hardcode the following:
18797c478bd9Sstevel@tonic-gate /SNK4 -- Digital Pathways SNK/4 preauth.
18807c478bd9Sstevel@tonic-gate /GRAIL -- experimental preauth
18817c478bd9Sstevel@tonic-gate The first one found is used. See sam_inst_map above.
18827c478bd9Sstevel@tonic-gate
18837c478bd9Sstevel@tonic-gate For SNK4 in particular, the key in the database is the key for
18847c478bd9Sstevel@tonic-gate the device; kadmin needs a special interface for it.
18857c478bd9Sstevel@tonic-gate */
18867c478bd9Sstevel@tonic-gate
18877c478bd9Sstevel@tonic-gate {
188856a424ccSmp int npr = 1;
188956a424ccSmp krb5_boolean more;
18907c478bd9Sstevel@tonic-gate krb5_db_entry assoc;
18917c478bd9Sstevel@tonic-gate krb5_key_data *assoc_key;
18927c478bd9Sstevel@tonic-gate krb5_principal newp;
18937c478bd9Sstevel@tonic-gate int probeslot;
18947c478bd9Sstevel@tonic-gate
18957c478bd9Sstevel@tonic-gate sc.sam_type = 0;
18967c478bd9Sstevel@tonic-gate
18977c478bd9Sstevel@tonic-gate retval = krb5_copy_principal(kdc_context, request->client, &newp);
18987c478bd9Sstevel@tonic-gate if (retval) {
18997c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"),
19007c478bd9Sstevel@tonic-gate retval,
19017c478bd9Sstevel@tonic-gate gettext("copying client name for preauth probe"));
19027c478bd9Sstevel@tonic-gate return retval;
19037c478bd9Sstevel@tonic-gate }
19047c478bd9Sstevel@tonic-gate
19057c478bd9Sstevel@tonic-gate probeslot = krb5_princ_size(context, newp)++;
1906*55fea89dSDan Cross krb5_princ_name(kdc_context, newp) =
19077c478bd9Sstevel@tonic-gate realloc(krb5_princ_name(kdc_context, newp),
19087c478bd9Sstevel@tonic-gate krb5_princ_size(context, newp) * sizeof(krb5_data));
19097c478bd9Sstevel@tonic-gate
19107c478bd9Sstevel@tonic-gate for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) {
19117c478bd9Sstevel@tonic-gate krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name;
1912*55fea89dSDan Cross krb5_princ_component(kdc_context,newp,probeslot)->length =
19137c478bd9Sstevel@tonic-gate strlen(sam_ptr->name);
19147c478bd9Sstevel@tonic-gate npr = 1;
19157c478bd9Sstevel@tonic-gate retval = krb5_db_get_principal(kdc_context, newp, &assoc, &npr, (uint *)&more);
191656a424ccSmp if(!retval && npr) {
19177c478bd9Sstevel@tonic-gate sc.sam_type = sam_ptr->sam_type;
19187c478bd9Sstevel@tonic-gate break;
19197c478bd9Sstevel@tonic-gate }
19207c478bd9Sstevel@tonic-gate }
19217c478bd9Sstevel@tonic-gate
19227c478bd9Sstevel@tonic-gate krb5_princ_component(kdc_context,newp,probeslot)->data = 0;
19237c478bd9Sstevel@tonic-gate krb5_princ_component(kdc_context,newp,probeslot)->length = 0;
19247c478bd9Sstevel@tonic-gate krb5_princ_size(context, newp)--;
19257c478bd9Sstevel@tonic-gate
19267c478bd9Sstevel@tonic-gate krb5_free_principal(kdc_context, newp);
19277c478bd9Sstevel@tonic-gate
19287c478bd9Sstevel@tonic-gate /* if sc.sam_type is set, it worked */
19297c478bd9Sstevel@tonic-gate if (sc.sam_type) {
19307c478bd9Sstevel@tonic-gate /* so use assoc to get the key out! */
19317c478bd9Sstevel@tonic-gate {
19327c478bd9Sstevel@tonic-gate /* here's what do_tgs_req does */
19337c478bd9Sstevel@tonic-gate retval = krb5_dbe_find_enctype(kdc_context, &assoc,
19347c478bd9Sstevel@tonic-gate ENCTYPE_DES_CBC_RAW,
19357c478bd9Sstevel@tonic-gate KRB5_KDB_SALTTYPE_NORMAL,
19367c478bd9Sstevel@tonic-gate 0, /* Get highest kvno */
19377c478bd9Sstevel@tonic-gate &assoc_key);
19387c478bd9Sstevel@tonic-gate if (retval) {
19397c478bd9Sstevel@tonic-gate char *sname;
19407c478bd9Sstevel@tonic-gate krb5_unparse_name(kdc_context, request->client, &sname);
1941*55fea89dSDan Cross com_err(gettext("krb5kdc"),
1942*55fea89dSDan Cross retval,
19437c478bd9Sstevel@tonic-gate gettext("snk4 finding the enctype and key <%s>"),
19447c478bd9Sstevel@tonic-gate sname);
19457c478bd9Sstevel@tonic-gate free(sname);
19467c478bd9Sstevel@tonic-gate return retval;
19477c478bd9Sstevel@tonic-gate }
19487c478bd9Sstevel@tonic-gate /* convert server.key into a real key */
19497c478bd9Sstevel@tonic-gate retval = krb5_dbekd_decrypt_key_data(kdc_context,
1950*55fea89dSDan Cross &master_keyblock,
19517c478bd9Sstevel@tonic-gate assoc_key, &encrypting_key,
19527c478bd9Sstevel@tonic-gate NULL);
19537c478bd9Sstevel@tonic-gate if (retval) {
19547c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"),
1955*55fea89dSDan Cross retval,
19567c478bd9Sstevel@tonic-gate gettext("snk4 pulling out key entry"));
19577c478bd9Sstevel@tonic-gate return retval;
19587c478bd9Sstevel@tonic-gate }
19597c478bd9Sstevel@tonic-gate /* now we can use encrypting_key... */
19607c478bd9Sstevel@tonic-gate }
19617c478bd9Sstevel@tonic-gate } else {
19627c478bd9Sstevel@tonic-gate /* SAM is not an option - so don't return as hint */
19637c478bd9Sstevel@tonic-gate return KRB5_PREAUTH_BAD_TYPE;
19647c478bd9Sstevel@tonic-gate }
19657c478bd9Sstevel@tonic-gate }
19667c478bd9Sstevel@tonic-gate sc.magic = KV5M_SAM_CHALLENGE;
19677c478bd9Sstevel@tonic-gate psr.sam_flags = sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY;
19687c478bd9Sstevel@tonic-gate
19697c478bd9Sstevel@tonic-gate /* Replay prevention */
19707c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_principal(context, request->client, &psr.client)))
19717c478bd9Sstevel@tonic-gate return retval;
19727c478bd9Sstevel@tonic-gate #ifdef USE_RCACHE
19737c478bd9Sstevel@tonic-gate if ((retval = krb5_us_timeofday(context, &psr.stime, &psr.susec)))
19747c478bd9Sstevel@tonic-gate return retval;
19757c478bd9Sstevel@tonic-gate #endif /* USE_RCACHE */
19767c478bd9Sstevel@tonic-gate
19777c478bd9Sstevel@tonic-gate switch (sc.sam_type) {
19787c478bd9Sstevel@tonic-gate case PA_SAM_TYPE_GRAIL:
19797c478bd9Sstevel@tonic-gate sc.sam_type_name.data = "Experimental System";
19807c478bd9Sstevel@tonic-gate sc.sam_type_name.length = strlen(sc.sam_type_name.data);
19817c478bd9Sstevel@tonic-gate sc.sam_challenge_label.data = "experimental challenge label";
19827c478bd9Sstevel@tonic-gate sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
19837c478bd9Sstevel@tonic-gate sc.sam_challenge.data = "12345";
19847c478bd9Sstevel@tonic-gate sc.sam_challenge.length = strlen(sc.sam_challenge.data);
19857c478bd9Sstevel@tonic-gate
19867c478bd9Sstevel@tonic-gate #if 0 /* Enable this to test "normal" (no flags set) mode. */
19877c478bd9Sstevel@tonic-gate psr.sam_flags = sc.sam_flags = 0;
19887c478bd9Sstevel@tonic-gate #endif
19897c478bd9Sstevel@tonic-gate
19907c478bd9Sstevel@tonic-gate psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
19917c478bd9Sstevel@tonic-gate /* string2key on sc.sam_challenge goes in here */
19927c478bd9Sstevel@tonic-gate /* eblock is just to set the enctype */
19937c478bd9Sstevel@tonic-gate {
19947c478bd9Sstevel@tonic-gate const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
19957c478bd9Sstevel@tonic-gate
19967c478bd9Sstevel@tonic-gate if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge,
19977c478bd9Sstevel@tonic-gate 0 /* salt */, &psr.sam_key)))
19987c478bd9Sstevel@tonic-gate goto cleanup;
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch)))
20017c478bd9Sstevel@tonic-gate goto cleanup;
2002*55fea89dSDan Cross
20037c478bd9Sstevel@tonic-gate {
20047c478bd9Sstevel@tonic-gate size_t enclen;
20057c478bd9Sstevel@tonic-gate krb5_enc_data tmpdata;
20067c478bd9Sstevel@tonic-gate
20077c478bd9Sstevel@tonic-gate if ((retval = krb5_c_encrypt_length(context,
20087c478bd9Sstevel@tonic-gate psr_key.enctype,
20097c478bd9Sstevel@tonic-gate scratch->length, &enclen)))
20107c478bd9Sstevel@tonic-gate goto cleanup;
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
20137c478bd9Sstevel@tonic-gate retval = ENOMEM;
20147c478bd9Sstevel@tonic-gate goto cleanup;
20157c478bd9Sstevel@tonic-gate }
20167c478bd9Sstevel@tonic-gate tmpdata.ciphertext.length = enclen;
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate if ((retval = krb5_c_encrypt(context, &psr_key,
20197c478bd9Sstevel@tonic-gate /* XXX */ 0, 0, scratch, &tmpdata)))
20207c478bd9Sstevel@tonic-gate goto cleanup;
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate sc.sam_track_id = tmpdata.ciphertext;
20237c478bd9Sstevel@tonic-gate }
20247c478bd9Sstevel@tonic-gate }
20257c478bd9Sstevel@tonic-gate
20267c478bd9Sstevel@tonic-gate sc.sam_response_prompt.data = "response prompt";
20277c478bd9Sstevel@tonic-gate sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
20287c478bd9Sstevel@tonic-gate sc.sam_pk_for_sad.length = 0;
20297c478bd9Sstevel@tonic-gate sc.sam_nonce = 0;
20307c478bd9Sstevel@tonic-gate /* Generate checksum */
20317c478bd9Sstevel@tonic-gate /*krb5_checksum_size(context, ctype)*/
20327c478bd9Sstevel@tonic-gate /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
20337c478bd9Sstevel@tonic-gate seed_length,outcksum) */
20347c478bd9Sstevel@tonic-gate /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
20357c478bd9Sstevel@tonic-gate seed_length) */
20367c478bd9Sstevel@tonic-gate #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
20377c478bd9Sstevel@tonic-gate sc.sam_cksum.contents = (krb5_octet *)
20387c478bd9Sstevel@tonic-gate malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
20397c478bd9Sstevel@tonic-gate if (sc.sam_cksum.contents == NULL) return(ENOMEM);
20407c478bd9Sstevel@tonic-gate
20417c478bd9Sstevel@tonic-gate retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
20427c478bd9Sstevel@tonic-gate sc.sam_challenge.data,
20437c478bd9Sstevel@tonic-gate sc.sam_challenge.length,
20447c478bd9Sstevel@tonic-gate psr.sam_key.contents, /* key */
20457c478bd9Sstevel@tonic-gate psr.sam_key.length, /* key length */
20467c478bd9Sstevel@tonic-gate &sc.sam_cksum);
20477c478bd9Sstevel@tonic-gate if (retval) { free(sc.sam_cksum.contents); return(retval); }
20487c478bd9Sstevel@tonic-gate #endif /* 0 */
2049*55fea89dSDan Cross
20507c478bd9Sstevel@tonic-gate retval = encode_krb5_sam_challenge(&sc, &scratch);
20517c478bd9Sstevel@tonic-gate if (retval) goto cleanup;
20527c478bd9Sstevel@tonic-gate pa_data->magic = KV5M_PA_DATA;
20537c478bd9Sstevel@tonic-gate pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
20547c478bd9Sstevel@tonic-gate pa_data->contents = (unsigned char *) scratch->data;
20557c478bd9Sstevel@tonic-gate pa_data->length = scratch->length;
2056*55fea89dSDan Cross
20577c478bd9Sstevel@tonic-gate retval = 0;
20587c478bd9Sstevel@tonic-gate break;
20597c478bd9Sstevel@tonic-gate case PA_SAM_TYPE_DIGI_PATH:
20607c478bd9Sstevel@tonic-gate sc.sam_type_name.data = "Digital Pathways";
20617c478bd9Sstevel@tonic-gate sc.sam_type_name.length = strlen(sc.sam_type_name.data);
20627c478bd9Sstevel@tonic-gate #if 1
20637c478bd9Sstevel@tonic-gate sc.sam_challenge_label.data = "Enter the following on your keypad";
20647c478bd9Sstevel@tonic-gate sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
20657c478bd9Sstevel@tonic-gate #endif
20667c478bd9Sstevel@tonic-gate /* generate digit string, take it mod 1000000 (six digits.) */
20677c478bd9Sstevel@tonic-gate {
20687c478bd9Sstevel@tonic-gate int j;
20697c478bd9Sstevel@tonic-gate krb5_keyblock session_key;
20707c478bd9Sstevel@tonic-gate char outputblock[8];
20717c478bd9Sstevel@tonic-gate int i;
20727c478bd9Sstevel@tonic-gate
20737c478bd9Sstevel@tonic-gate (void) memset(&session_key, 0, sizeof(krb5_keyblock));
207456a424ccSmp
20757c478bd9Sstevel@tonic-gate (void) memset(inputblock, 0, 8);
20767c478bd9Sstevel@tonic-gate
20777c478bd9Sstevel@tonic-gate retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC,
20787c478bd9Sstevel@tonic-gate &session_key);
20797c478bd9Sstevel@tonic-gate
20807c478bd9Sstevel@tonic-gate if (retval) {
20817c478bd9Sstevel@tonic-gate /* random key failed */
20827c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"),
20837c478bd9Sstevel@tonic-gate retval,
20847c478bd9Sstevel@tonic-gate gettext("generating random challenge for preauth"));
20857c478bd9Sstevel@tonic-gate return retval;
20867c478bd9Sstevel@tonic-gate }
20877c478bd9Sstevel@tonic-gate /* now session_key has a key which we can pick bits out of */
20887c478bd9Sstevel@tonic-gate /* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */
20897c478bd9Sstevel@tonic-gate if (session_key.length != 8) {
20907c478bd9Sstevel@tonic-gate retval = KRB5KDC_ERR_ETYPE_NOSUPP,
20917c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"),
20927c478bd9Sstevel@tonic-gate retval = KRB5KDC_ERR_ETYPE_NOSUPP,
20937c478bd9Sstevel@tonic-gate gettext("keytype didn't match code expectations"));
20947c478bd9Sstevel@tonic-gate return retval;
20957c478bd9Sstevel@tonic-gate }
20967c478bd9Sstevel@tonic-gate for(i = 0; i<6; i++) {
20977c478bd9Sstevel@tonic-gate inputblock[i] = '0' + ((session_key.contents[i]/2) % 10);
20987c478bd9Sstevel@tonic-gate }
20997c478bd9Sstevel@tonic-gate if (session_key.contents)
21007c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(kdc_context, &session_key);
21017c478bd9Sstevel@tonic-gate
21027c478bd9Sstevel@tonic-gate /* retval = krb5_finish_key(kdc_context, &eblock); */
21037c478bd9Sstevel@tonic-gate /* now we have inputblock containing the 8 byte input to DES... */
21047c478bd9Sstevel@tonic-gate sc.sam_challenge.data = inputblock;
21057c478bd9Sstevel@tonic-gate sc.sam_challenge.length = 6;
21067c478bd9Sstevel@tonic-gate
21077c478bd9Sstevel@tonic-gate encrypting_key.enctype = ENCTYPE_DES_CBC_RAW;
21087c478bd9Sstevel@tonic-gate
21097c478bd9Sstevel@tonic-gate if (retval) {
21107c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"),
21117c478bd9Sstevel@tonic-gate retval,
21127c478bd9Sstevel@tonic-gate gettext("snk4 processing key"));
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate {
21167c478bd9Sstevel@tonic-gate krb5_data plain;
21177c478bd9Sstevel@tonic-gate krb5_enc_data cipher;
21187c478bd9Sstevel@tonic-gate
21197c478bd9Sstevel@tonic-gate plain.length = 8;
21207c478bd9Sstevel@tonic-gate plain.data = inputblock;
21217c478bd9Sstevel@tonic-gate
21227c478bd9Sstevel@tonic-gate /* XXX I know this is enough because of the fixed raw enctype.
21237c478bd9Sstevel@tonic-gate if it's not, the underlying code will return a reasonable
21247c478bd9Sstevel@tonic-gate error, which should never happen */
21257c478bd9Sstevel@tonic-gate cipher.ciphertext.length = 8;
21267c478bd9Sstevel@tonic-gate cipher.ciphertext.data = outputblock;
21277c478bd9Sstevel@tonic-gate
21287c478bd9Sstevel@tonic-gate if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key,
21297c478bd9Sstevel@tonic-gate /* XXX */ 0, 0, &plain, &cipher))) {
2130*55fea89dSDan Cross com_err(gettext("krb5kdc"),
2131*55fea89dSDan Cross retval,
21327c478bd9Sstevel@tonic-gate gettext("snk4 response generation failed"));
21337c478bd9Sstevel@tonic-gate return retval;
21347c478bd9Sstevel@tonic-gate }
21357c478bd9Sstevel@tonic-gate }
21367c478bd9Sstevel@tonic-gate
21377c478bd9Sstevel@tonic-gate /* now output block is the raw bits of the response; convert it
21387c478bd9Sstevel@tonic-gate to display form */
21397c478bd9Sstevel@tonic-gate for (j=0; j<4; j++) {
21407c478bd9Sstevel@tonic-gate char n[2];
21417c478bd9Sstevel@tonic-gate int k;
21427c478bd9Sstevel@tonic-gate n[0] = outputblock[j] & 0xf;
21437c478bd9Sstevel@tonic-gate n[1] = (outputblock[j]>>4) & 0xf;
21447c478bd9Sstevel@tonic-gate for (k=0; k<2; k++) {
21457c478bd9Sstevel@tonic-gate if(n[k] > 9) n[k] = ((n[k]-1)>>2);
21467c478bd9Sstevel@tonic-gate /* This is equivalent to:
21477c478bd9Sstevel@tonic-gate if(n[k]>=0xa && n[k]<=0xc) n[k] = 2;
21487c478bd9Sstevel@tonic-gate if(n[k]>=0xd && n[k]<=0xf) n[k] = 3;
21497c478bd9Sstevel@tonic-gate */
21507c478bd9Sstevel@tonic-gate }
21517c478bd9Sstevel@tonic-gate /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */
21527c478bd9Sstevel@tonic-gate /* for v5, we just generate a string */
21537c478bd9Sstevel@tonic-gate response[2*j+0] = '0' + n[1];
21547c478bd9Sstevel@tonic-gate response[2*j+1] = '0' + n[0];
21557c478bd9Sstevel@tonic-gate /* and now, response has what we work with. */
21567c478bd9Sstevel@tonic-gate }
21577c478bd9Sstevel@tonic-gate response[8] = 0;
21587c478bd9Sstevel@tonic-gate predict_response.data = response;
21597c478bd9Sstevel@tonic-gate predict_response.length = 8;
21607c478bd9Sstevel@tonic-gate #if 0 /* for debugging, hack the output too! */
21617c478bd9Sstevel@tonic-gate sc.sam_challenge_label.data = response;
21627c478bd9Sstevel@tonic-gate sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
21637c478bd9Sstevel@tonic-gate #endif
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate
21667c478bd9Sstevel@tonic-gate psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
21677c478bd9Sstevel@tonic-gate /* string2key on sc.sam_challenge goes in here */
21687c478bd9Sstevel@tonic-gate /* eblock is just to set the enctype */
21697c478bd9Sstevel@tonic-gate {
21707c478bd9Sstevel@tonic-gate retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
21717c478bd9Sstevel@tonic-gate &predict_response, 0 /* salt */,
21727c478bd9Sstevel@tonic-gate &psr.sam_key);
21737c478bd9Sstevel@tonic-gate if (retval) goto cleanup;
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate retval = encode_krb5_predicted_sam_response(&psr, &scratch);
21767c478bd9Sstevel@tonic-gate if (retval) goto cleanup;
2177*55fea89dSDan Cross
21787c478bd9Sstevel@tonic-gate {
21797c478bd9Sstevel@tonic-gate size_t enclen;
21807c478bd9Sstevel@tonic-gate krb5_enc_data tmpdata;
21817c478bd9Sstevel@tonic-gate
21827c478bd9Sstevel@tonic-gate if ((retval = krb5_c_encrypt_length(context,
21837c478bd9Sstevel@tonic-gate psr_key.enctype,
21847c478bd9Sstevel@tonic-gate scratch->length, &enclen)))
21857c478bd9Sstevel@tonic-gate goto cleanup;
21867c478bd9Sstevel@tonic-gate
21877c478bd9Sstevel@tonic-gate if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
21887c478bd9Sstevel@tonic-gate retval = ENOMEM;
21897c478bd9Sstevel@tonic-gate goto cleanup;
21907c478bd9Sstevel@tonic-gate }
21917c478bd9Sstevel@tonic-gate tmpdata.ciphertext.length = enclen;
21927c478bd9Sstevel@tonic-gate
21937c478bd9Sstevel@tonic-gate if ((retval = krb5_c_encrypt(context, &psr_key,
21947c478bd9Sstevel@tonic-gate /* XXX */ 0, 0, scratch, &tmpdata)))
21957c478bd9Sstevel@tonic-gate goto cleanup;
21967c478bd9Sstevel@tonic-gate
21977c478bd9Sstevel@tonic-gate sc.sam_track_id = tmpdata.ciphertext;
21987c478bd9Sstevel@tonic-gate }
21997c478bd9Sstevel@tonic-gate if (retval) goto cleanup;
22007c478bd9Sstevel@tonic-gate }
22017c478bd9Sstevel@tonic-gate
22027c478bd9Sstevel@tonic-gate sc.sam_response_prompt.data = "Enter the displayed response";
22037c478bd9Sstevel@tonic-gate sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
22047c478bd9Sstevel@tonic-gate sc.sam_pk_for_sad.length = 0;
22057c478bd9Sstevel@tonic-gate sc.sam_nonce = 0;
22067c478bd9Sstevel@tonic-gate /* Generate checksum */
22077c478bd9Sstevel@tonic-gate /*krb5_checksum_size(context, ctype)*/
22087c478bd9Sstevel@tonic-gate /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
22097c478bd9Sstevel@tonic-gate seed_length,outcksum) */
22107c478bd9Sstevel@tonic-gate /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
22117c478bd9Sstevel@tonic-gate seed_length) */
22127c478bd9Sstevel@tonic-gate #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
22137c478bd9Sstevel@tonic-gate sc.sam_cksum.contents = (krb5_octet *)
22147c478bd9Sstevel@tonic-gate malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
22157c478bd9Sstevel@tonic-gate if (sc.sam_cksum.contents == NULL) return(ENOMEM);
22167c478bd9Sstevel@tonic-gate
22177c478bd9Sstevel@tonic-gate retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
22187c478bd9Sstevel@tonic-gate sc.sam_challenge.data,
22197c478bd9Sstevel@tonic-gate sc.sam_challenge.length,
22207c478bd9Sstevel@tonic-gate psr.sam_key.contents, /* key */
22217c478bd9Sstevel@tonic-gate psr.sam_key.length, /* key length */
22227c478bd9Sstevel@tonic-gate &sc.sam_cksum);
22237c478bd9Sstevel@tonic-gate if (retval) { free(sc.sam_cksum.contents); return(retval); }
22247c478bd9Sstevel@tonic-gate #endif /* 0 */
2225*55fea89dSDan Cross
22267c478bd9Sstevel@tonic-gate retval = encode_krb5_sam_challenge(&sc, &scratch);
22277c478bd9Sstevel@tonic-gate if (retval) goto cleanup;
22287c478bd9Sstevel@tonic-gate pa_data->magic = KV5M_PA_DATA;
22297c478bd9Sstevel@tonic-gate pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
22307c478bd9Sstevel@tonic-gate pa_data->contents = (unsigned char *) scratch->data;
22317c478bd9Sstevel@tonic-gate pa_data->length = scratch->length;
2232*55fea89dSDan Cross
22337c478bd9Sstevel@tonic-gate retval = 0;
22347c478bd9Sstevel@tonic-gate break;
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate
22377c478bd9Sstevel@tonic-gate cleanup:
22387c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &encrypting_key);
22397c478bd9Sstevel@tonic-gate return retval;
22407c478bd9Sstevel@tonic-gate }
22417c478bd9Sstevel@tonic-gate
22427c478bd9Sstevel@tonic-gate static krb5_error_code
verify_sam_response(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * pa,preauth_get_entry_data_proc sam_get_entry_data,void * pa_system_context,void ** pa_request_context,krb5_data ** e_data,krb5_authdata *** authz_data)224356a424ccSmp verify_sam_response(krb5_context context, krb5_db_entry *client,
2244159d09a2SMark Phalan krb5_data *req_pkt,
224556a424ccSmp krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
2246159d09a2SMark Phalan krb5_pa_data *pa,
2247159d09a2SMark Phalan preauth_get_entry_data_proc sam_get_entry_data,
2248159d09a2SMark Phalan void *pa_system_context,
2249159d09a2SMark Phalan void **pa_request_context,
2250159d09a2SMark Phalan krb5_data **e_data,
2251159d09a2SMark Phalan krb5_authdata ***authz_data)
22527c478bd9Sstevel@tonic-gate {
22537c478bd9Sstevel@tonic-gate krb5_error_code retval;
22547c478bd9Sstevel@tonic-gate krb5_data scratch;
22557c478bd9Sstevel@tonic-gate krb5_sam_response *sr = 0;
22567c478bd9Sstevel@tonic-gate krb5_predicted_sam_response *psr = 0;
22577c478bd9Sstevel@tonic-gate krb5_enc_sam_response_enc *esre = 0;
22587c478bd9Sstevel@tonic-gate krb5_timestamp timenow;
22597c478bd9Sstevel@tonic-gate char *princ_req = 0, *princ_psr = 0;
22607c478bd9Sstevel@tonic-gate
22617c478bd9Sstevel@tonic-gate scratch.data = (char *) pa->contents;
22627c478bd9Sstevel@tonic-gate scratch.length = pa->length;
2263*55fea89dSDan Cross
22647c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
22657c478bd9Sstevel@tonic-gate scratch.data = 0;
22667c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("decode_krb5_sam_response failed"));
22677c478bd9Sstevel@tonic-gate goto cleanup;
22687c478bd9Sstevel@tonic-gate }
22697c478bd9Sstevel@tonic-gate
22707c478bd9Sstevel@tonic-gate /* XXX We can only handle the challenge/response model of SAM.
22717c478bd9Sstevel@tonic-gate See passwords-04, par 4.1, 4.2 */
22727c478bd9Sstevel@tonic-gate {
22737c478bd9Sstevel@tonic-gate krb5_enc_data tmpdata;
22747c478bd9Sstevel@tonic-gate
22757c478bd9Sstevel@tonic-gate tmpdata.enctype = ENCTYPE_UNKNOWN;
22767c478bd9Sstevel@tonic-gate tmpdata.ciphertext = sr->sam_track_id;
22777c478bd9Sstevel@tonic-gate
22787c478bd9Sstevel@tonic-gate scratch.length = tmpdata.ciphertext.length;
22797c478bd9Sstevel@tonic-gate if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
22807c478bd9Sstevel@tonic-gate retval = ENOMEM;
22817c478bd9Sstevel@tonic-gate goto cleanup;
22827c478bd9Sstevel@tonic-gate }
22837c478bd9Sstevel@tonic-gate
22847c478bd9Sstevel@tonic-gate if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
22857c478bd9Sstevel@tonic-gate &tmpdata, &scratch))) {
22867c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"),
22877c478bd9Sstevel@tonic-gate retval,
22887c478bd9Sstevel@tonic-gate gettext("decrypt track_id failed"));
22897c478bd9Sstevel@tonic-gate goto cleanup;
22907c478bd9Sstevel@tonic-gate }
22917c478bd9Sstevel@tonic-gate }
22927c478bd9Sstevel@tonic-gate
22937c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
22947c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"), retval,
22957c478bd9Sstevel@tonic-gate gettext("decode_krb5_predicted_sam_response failed -- replay attack?"));
22967c478bd9Sstevel@tonic-gate goto cleanup;
22977c478bd9Sstevel@tonic-gate }
22987c478bd9Sstevel@tonic-gate
22997c478bd9Sstevel@tonic-gate /* Replay detection */
23007c478bd9Sstevel@tonic-gate if ((retval = krb5_unparse_name(context, request->client, &princ_req)))
23017c478bd9Sstevel@tonic-gate goto cleanup;
23027c478bd9Sstevel@tonic-gate if ((retval = krb5_unparse_name(context, psr->client, &princ_psr)))
23037c478bd9Sstevel@tonic-gate goto cleanup;
23047c478bd9Sstevel@tonic-gate if (strcmp(princ_req, princ_psr) != 0) {
23057c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
23067c478bd9Sstevel@tonic-gate gettext("Principal mismatch in SAM psr! -- replay attack?"));
23077c478bd9Sstevel@tonic-gate goto cleanup;
23087c478bd9Sstevel@tonic-gate }
23097c478bd9Sstevel@tonic-gate
23107c478bd9Sstevel@tonic-gate if ((retval = krb5_timeofday(context, &timenow)))
23117c478bd9Sstevel@tonic-gate goto cleanup;
23127c478bd9Sstevel@tonic-gate
23137c478bd9Sstevel@tonic-gate #ifdef USE_RCACHE
23147c478bd9Sstevel@tonic-gate {
23157c478bd9Sstevel@tonic-gate krb5_donot_replay rep;
23167c478bd9Sstevel@tonic-gate extern krb5_deltat rc_lifetime;
23177c478bd9Sstevel@tonic-gate /*
23187c478bd9Sstevel@tonic-gate * Verify this response came back in a timely manner.
23197c478bd9Sstevel@tonic-gate * We do this b/c otherwise very old (expunged from the rcache)
23207c478bd9Sstevel@tonic-gate * psr's would be able to be replayed.
23217c478bd9Sstevel@tonic-gate */
23227c478bd9Sstevel@tonic-gate if (timenow - psr->stime > rc_lifetime) {
23237c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
23247c478bd9Sstevel@tonic-gate gettext("SAM psr came back too late! -- replay attack?"));
23257c478bd9Sstevel@tonic-gate goto cleanup;
23267c478bd9Sstevel@tonic-gate }
23277c478bd9Sstevel@tonic-gate
23287c478bd9Sstevel@tonic-gate /* Now check the replay cache. */
23297c478bd9Sstevel@tonic-gate rep.client = princ_psr;
23307c478bd9Sstevel@tonic-gate rep.server = "SAM/rc"; /* Should not match any principal name. */
23317c478bd9Sstevel@tonic-gate rep.ctime = psr->stime;
23327c478bd9Sstevel@tonic-gate rep.cusec = psr->susec;
233356a424ccSmp retval = krb5_rc_store(kdc_context, kdc_rcache, &rep);
233456a424ccSmp if (retval) {
23357c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("SAM psr replay attack!"));
23367c478bd9Sstevel@tonic-gate goto cleanup;
23377c478bd9Sstevel@tonic-gate }
23387c478bd9Sstevel@tonic-gate }
23397c478bd9Sstevel@tonic-gate #endif /* USE_RCACHE */
23407c478bd9Sstevel@tonic-gate
23417c478bd9Sstevel@tonic-gate
23427c478bd9Sstevel@tonic-gate {
23437c478bd9Sstevel@tonic-gate free(scratch.data);
23447c478bd9Sstevel@tonic-gate scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length;
23457c478bd9Sstevel@tonic-gate if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
23467c478bd9Sstevel@tonic-gate retval = ENOMEM;
23477c478bd9Sstevel@tonic-gate goto cleanup;
23487c478bd9Sstevel@tonic-gate }
23497c478bd9Sstevel@tonic-gate
23507c478bd9Sstevel@tonic-gate if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0,
23517c478bd9Sstevel@tonic-gate 0, &sr->sam_enc_nonce_or_ts, &scratch))) {
23527c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("decrypt nonce_or_ts failed"));
23537c478bd9Sstevel@tonic-gate goto cleanup;
23547c478bd9Sstevel@tonic-gate }
23557c478bd9Sstevel@tonic-gate }
23567c478bd9Sstevel@tonic-gate
23577c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) {
23587c478bd9Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("decode_krb5_enc_sam_response_enc failed"));
23597c478bd9Sstevel@tonic-gate goto cleanup;
23607c478bd9Sstevel@tonic-gate }
23617c478bd9Sstevel@tonic-gate
23627c478bd9Sstevel@tonic-gate if (esre->sam_timestamp != sr->sam_patimestamp) {
23637c478bd9Sstevel@tonic-gate retval = KRB5KDC_ERR_PREAUTH_FAILED;
23647c478bd9Sstevel@tonic-gate goto cleanup;
23657c478bd9Sstevel@tonic-gate }
2366*55fea89dSDan Cross
23677c478bd9Sstevel@tonic-gate if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
23687c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_SKEW;
23697c478bd9Sstevel@tonic-gate goto cleanup;
23707c478bd9Sstevel@tonic-gate }
23717c478bd9Sstevel@tonic-gate
23727c478bd9Sstevel@tonic-gate setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
23737c478bd9Sstevel@tonic-gate
23747c478bd9Sstevel@tonic-gate cleanup:
2375*55fea89dSDan Cross if (retval) com_err(gettext("krb5kdc"),
23767c478bd9Sstevel@tonic-gate retval,
23777c478bd9Sstevel@tonic-gate gettext("sam verify failure"));
23787c478bd9Sstevel@tonic-gate if (scratch.data) free(scratch.data);
23797c478bd9Sstevel@tonic-gate if (sr) free(sr);
23807c478bd9Sstevel@tonic-gate if (psr) free(psr);
23817c478bd9Sstevel@tonic-gate if (esre) free(esre);
238256a424ccSmp if (princ_psr) free(princ_psr);
238356a424ccSmp if (princ_req) free(princ_req);
23847c478bd9Sstevel@tonic-gate
23857c478bd9Sstevel@tonic-gate return retval;
23867c478bd9Sstevel@tonic-gate }
2387