17c478bd9Sstevel@tonic-gate /* 2*ba7b222eSGlenn 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 * 1056a424ccSmp153739 * 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. 177c478bd9Sstevel@tonic-gate * 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. 317c478bd9Sstevel@tonic-gate * 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. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * All rights reserved. 397c478bd9Sstevel@tonic-gate * 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. 447c478bd9Sstevel@tonic-gate * 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. 557c478bd9Sstevel@tonic-gate * 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> 6756a424ccSmp153739 #include "adm_proto.h" 687c478bd9Sstevel@tonic-gate #include <libintl.h> 697c478bd9Sstevel@tonic-gate #include <syslog.h> 707c478bd9Sstevel@tonic-gate 7156a424ccSmp153739 #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 7956a424ccSmp153739 8056a424ccSmp153739 /* XXX This is ugly and should be in a header file somewhere */ 8156a424ccSmp153739 #ifndef KRB5INT_DES_TYPES_DEFINED 8256a424ccSmp153739 #define KRB5INT_DES_TYPES_DEFINED 8356a424ccSmp153739 typedef unsigned char des_cblock[8]; /* crypto-block size */ 8456a424ccSmp153739 #endif 8556a424ccSmp153739 typedef des_cblock mit_des_cblock; 8656a424ccSmp153739 extern void mit_des_fixup_key_parity (mit_des_cblock ); 8756a424ccSmp153739 extern int mit_des_is_weak_key (mit_des_cblock ); 8856a424ccSmp153739 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, 1057c478bd9Sstevel@tonic-gate 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, 1157c478bd9Sstevel@tonic-gate krb5_db_entry *client, krb5_db_entry *server, 116159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data, 117159d09a2SMark Phalan void *pa_system_context, 1187c478bd9Sstevel@tonic-gate krb5_pa_data *data); 1197c478bd9Sstevel@tonic-gate static krb5_error_code 1207c478bd9Sstevel@tonic-gate get_etype_info2(krb5_context context, krb5_kdc_req *request, 1217c478bd9Sstevel@tonic-gate krb5_db_entry *client, krb5_db_entry *server, 122159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data, 123159d09a2SMark Phalan void *pa_system_context, 1247c478bd9Sstevel@tonic-gate krb5_pa_data *pa_data); 1257c478bd9Sstevel@tonic-gate static krb5_error_code 126159d09a2SMark Phalan etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata, 1277c478bd9Sstevel@tonic-gate krb5_db_entry *client, 1287c478bd9Sstevel@tonic-gate krb5_kdc_req *request, krb5_kdc_rep *reply, 1297c478bd9Sstevel@tonic-gate krb5_key_data *client_key, 1307c478bd9Sstevel@tonic-gate krb5_keyblock *encrypting_key, 131159d09a2SMark Phalan krb5_pa_data **send_pa, 132159d09a2SMark Phalan int etype_info2); 133159d09a2SMark Phalan 134159d09a2SMark Phalan static krb5_error_code 135159d09a2SMark Phalan 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 146159d09a2SMark Phalan static krb5_error_code 147159d09a2SMark Phalan return_etype_info2(krb5_context, krb5_pa_data * padata, 148159d09a2SMark Phalan krb5_db_entry *client, 149159d09a2SMark Phalan krb5_data *req_pkt, 150159d09a2SMark Phalan krb5_kdc_req *request, krb5_kdc_rep *reply, 151159d09a2SMark Phalan krb5_key_data *client_key, 152159d09a2SMark Phalan 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 1597c478bd9Sstevel@tonic-gate (krb5_context, krb5_pa_data * padata, 1607c478bd9Sstevel@tonic-gate krb5_db_entry *client, 161159d09a2SMark Phalan krb5_data *req_pkt, 1627c478bd9Sstevel@tonic-gate krb5_kdc_req *request, krb5_kdc_rep *reply, 1637c478bd9Sstevel@tonic-gate krb5_key_data *client_key, 1647c478bd9Sstevel@tonic-gate 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 1727c478bd9Sstevel@tonic-gate (krb5_context, krb5_db_entry *client, 173159d09a2SMark Phalan krb5_data *req_pkt, 1747c478bd9Sstevel@tonic-gate 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, 1847c478bd9Sstevel@tonic-gate krb5_db_entry *client, krb5_db_entry *server, 185159d09a2SMark Phalan preauth_get_entry_data_proc get_entry_data, 186159d09a2SMark Phalan void *pa_module_context, 1877c478bd9Sstevel@tonic-gate krb5_pa_data *data); 1887c478bd9Sstevel@tonic-gate static krb5_error_code return_sam_data 1897c478bd9Sstevel@tonic-gate (krb5_context, krb5_pa_data * padata, 1907c478bd9Sstevel@tonic-gate krb5_db_entry *client, 191159d09a2SMark Phalan krb5_data *req_pkt, 1927c478bd9Sstevel@tonic-gate krb5_kdc_req *request, krb5_kdc_rep *reply, 1937c478bd9Sstevel@tonic-gate krb5_key_data *client_key, 1947c478bd9Sstevel@tonic-gate 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 { 2247c478bd9Sstevel@tonic-gate "etype-info2", 2257c478bd9Sstevel@tonic-gate KRB5_PADATA_ETYPE_INFO2, 2267c478bd9Sstevel@tonic-gate 0, 227159d09a2SMark Phalan NULL, 228159d09a2SMark Phalan NULL, 229159d09a2SMark Phalan NULL, 2307c478bd9Sstevel@tonic-gate get_etype_info2, 2317c478bd9Sstevel@tonic-gate 0, 2327c478bd9Sstevel@tonic-gate 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, 2417c478bd9Sstevel@tonic-gate 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 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 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 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 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 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 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 6507c478bd9Sstevel@tonic-gate find_pa_system(int type, krb5_preauth_systems **preauth) 6517c478bd9Sstevel@tonic-gate { 652159d09a2SMark Phalan krb5_preauth_systems *ap; 6537c478bd9Sstevel@tonic-gate 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; 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 663159d09a2SMark Phalan static krb5_error_code 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 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 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 77056a424ccSmp153739 const char *missing_required_preauth(krb5_db_entry *client, 77156a424ccSmp153739 krb5_db_entry *server, 77256a424ccSmp153739 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. 7787c478bd9Sstevel@tonic-gate * 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 7867c478bd9Sstevel@tonic-gate 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 80756a424ccSmp153739 void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client, 80856a424ccSmp153739 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; 8157c478bd9Sstevel@tonic-gate 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; 8197c478bd9Sstevel@tonic-gate 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 } 855*ba7b222eSGlenn 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 8677c478bd9Sstevel@tonic-gate /* 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 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 916159d09a2SMark Phalan /* 9177c478bd9Sstevel@tonic-gate * This routine is called to verify the preauthentication information 9187c478bd9Sstevel@tonic-gate * for a V5 request. 9197c478bd9Sstevel@tonic-gate * 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 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; 9347c478bd9Sstevel@tonic-gate 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; 10237c478bd9Sstevel@tonic-gate 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 && 10547c478bd9Sstevel@tonic-gate !isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) && 10557c478bd9Sstevel@tonic-gate !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 } 10637c478bd9Sstevel@tonic-gate /* The following switch statement allows us 10647c478bd9Sstevel@tonic-gate * to return some preauth system errors back to the client. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate switch(retval) { 10677c478bd9Sstevel@tonic-gate case KRB5KRB_AP_ERR_BAD_INTEGRITY: 10687c478bd9Sstevel@tonic-gate 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: */ 10907c478bd9Sstevel@tonic-gate return retval; 10917c478bd9Sstevel@tonic-gate default: 10927c478bd9Sstevel@tonic-gate 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 1101159d09a2SMark Phalan return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt, 110256a424ccSmp153739 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; 11467c478bd9Sstevel@tonic-gate 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 } 11857c478bd9Sstevel@tonic-gate 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 } 11927c478bd9Sstevel@tonic-gate 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 } 120356a424ccSmp153739 12047c478bd9Sstevel@tonic-gate static krb5_boolean 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)) 12187c478bd9Sstevel@tonic-gate return 1; 12197c478bd9Sstevel@tonic-gate else return 0; 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate static krb5_boolean 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 123456a424ccSmp153739 12357c478bd9Sstevel@tonic-gate static krb5_error_code 123656a424ccSmp153739 verify_enc_timestamp(krb5_context context, krb5_db_entry *client, 1237159d09a2SMark Phalan krb5_data *req_pkt, 123856a424ccSmp153739 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; 12567c478bd9Sstevel@tonic-gate 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; 12627c478bd9Sstevel@tonic-gate 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 12787c478bd9Sstevel@tonic-gate 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; 12987c478bd9Sstevel@tonic-gate 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; 13077c478bd9Sstevel@tonic-gate 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 13287c478bd9Sstevel@tonic-gate _make_etype_info_entry(krb5_context context, 13297c478bd9Sstevel@tonic-gate krb5_kdc_req *request, krb5_key_data *client_key, 13307c478bd9Sstevel@tonic-gate krb5_enctype etype, krb5_etype_info_entry **entry, 13317c478bd9Sstevel@tonic-gate int etype_info2) 13327c478bd9Sstevel@tonic-gate { 13337c478bd9Sstevel@tonic-gate krb5_data salt; 13347c478bd9Sstevel@tonic-gate 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: 13587c478bd9Sstevel@tonic-gate tmp_entry->s2kparams.data = malloc(1); 13597c478bd9Sstevel@tonic-gate if (tmp_entry->s2kparams.data == NULL) { 13607c478bd9Sstevel@tonic-gate retval = ENOMEM; 13617c478bd9Sstevel@tonic-gate goto fail; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate tmp_entry->s2kparams.length = 1; 13647c478bd9Sstevel@tonic-gate tmp_entry->s2kparams.data[0] = 1; 13657c478bd9Sstevel@tonic-gate break; 13667c478bd9Sstevel@tonic-gate default: 13677c478bd9Sstevel@tonic-gate 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) 13827c478bd9Sstevel@tonic-gate 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 13937c478bd9Sstevel@tonic-gate * as most of the work is the same. 13947c478bd9Sstevel@tonic-gate */ 13957c478bd9Sstevel@tonic-gate static krb5_error_code 13967c478bd9Sstevel@tonic-gate etype_info_helper(krb5_context context, krb5_kdc_req *request, 13977c478bd9Sstevel@tonic-gate krb5_db_entry *client, krb5_db_entry *server, 13987c478bd9Sstevel@tonic-gate 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; 14057c478bd9Sstevel@tonic-gate int i = 0; 14067c478bd9Sstevel@tonic-gate int start = 0; 14077c478bd9Sstevel@tonic-gate int seen_des = 0; 14087c478bd9Sstevel@tonic-gate 140956a424ccSmp153739 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, 14167c478bd9Sstevel@tonic-gate -1, 0, &client_key); 14177c478bd9Sstevel@tonic-gate if (retval == KRB5_KDB_NO_MATCHING_KEY) 14187c478bd9Sstevel@tonic-gate break; 14197c478bd9Sstevel@tonic-gate if (retval) 14207c478bd9Sstevel@tonic-gate goto cleanup; 14217c478bd9Sstevel@tonic-gate db_etype = client_key->key_data_type[0]; 14227c478bd9Sstevel@tonic-gate if (db_etype == ENCTYPE_DES_CBC_MD4) 14237c478bd9Sstevel@tonic-gate db_etype = ENCTYPE_DES_CBC_MD5; 142456a424ccSmp153739 14257c478bd9Sstevel@tonic-gate if (request_contains_enctype(context, request, db_etype)) { 14267c478bd9Sstevel@tonic-gate assert(etype_info2 || 14277c478bd9Sstevel@tonic-gate !enctype_requires_etype_info_2(db_etype)); 14287c478bd9Sstevel@tonic-gate if ((retval = _make_etype_info_entry(context, request, client_key, 14297c478bd9Sstevel@tonic-gate db_etype, &entry[i], etype_info2)) != 0) { 14307c478bd9Sstevel@tonic-gate goto cleanup; 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate entry[i+1] = 0; 14337c478bd9Sstevel@tonic-gate i++; 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate /* 14377c478bd9Sstevel@tonic-gate * If there is a des key in the kdb, try the "similar" enctypes, 14387c478bd9Sstevel@tonic-gate * avoid duplicate entries. 14397c478bd9Sstevel@tonic-gate */ 14407c478bd9Sstevel@tonic-gate if (!seen_des) { 14417c478bd9Sstevel@tonic-gate switch (db_etype) { 14427c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5: 14437c478bd9Sstevel@tonic-gate db_etype = ENCTYPE_DES_CBC_CRC; 14447c478bd9Sstevel@tonic-gate break; 14457c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC: 14467c478bd9Sstevel@tonic-gate db_etype = ENCTYPE_DES_CBC_MD5; 14477c478bd9Sstevel@tonic-gate break; 14487c478bd9Sstevel@tonic-gate default: 14497c478bd9Sstevel@tonic-gate continue; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate if (request_contains_enctype(context, request, db_etype)) { 14537c478bd9Sstevel@tonic-gate if ((retval = _make_etype_info_entry(context, request, 14547c478bd9Sstevel@tonic-gate client_key, db_etype, &entry[i], etype_info2)) != 0) { 14557c478bd9Sstevel@tonic-gate goto cleanup; 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate entry[i+1] = 0; 14587c478bd9Sstevel@tonic-gate i++; 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate seen_des++; 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate if (etype_info2) 1464*ba7b222eSGlenn Barry retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry, 14657c478bd9Sstevel@tonic-gate &scratch); 1466*ba7b222eSGlenn Barry else retval = encode_krb5_etype_info((krb5_etype_info_entry * const*) entry, 146756a424ccSmp153739 &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 14837c478bd9Sstevel@tonic-gate get_etype_info(krb5_context context, krb5_kdc_req *request, 14847c478bd9Sstevel@tonic-gate 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, 14877c478bd9Sstevel@tonic-gate krb5_pa_data *pa_data) 14887c478bd9Sstevel@tonic-gate { 14897c478bd9Sstevel@tonic-gate int i; 14907c478bd9Sstevel@tonic-gate for (i=0; i < request->nktypes; i++) { 14917c478bd9Sstevel@tonic-gate if (enctype_requires_etype_info_2(request->ktype[i])) 14927c478bd9Sstevel@tonic-gate return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will 14937c478bd9Sstevel@tonic-gate * skip this 14947c478bd9Sstevel@tonic-gate * 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 15007c478bd9Sstevel@tonic-gate get_etype_info2(krb5_context context, krb5_kdc_req *request, 15017c478bd9Sstevel@tonic-gate 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, 15047c478bd9Sstevel@tonic-gate 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 1510159d09a2SMark Phalan etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata, 15117c478bd9Sstevel@tonic-gate krb5_db_entry *client, 15127c478bd9Sstevel@tonic-gate krb5_kdc_req *request, krb5_kdc_rep *reply, 15137c478bd9Sstevel@tonic-gate krb5_key_data *client_key, 15147c478bd9Sstevel@tonic-gate 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) 15417c478bd9Sstevel@tonic-gate 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) 1559*ba7b222eSGlenn Barry retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry, &scratch); 1560159d09a2SMark Phalan else 1561*ba7b222eSGlenn 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 15697c478bd9Sstevel@tonic-gate /* 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 */ 15727c478bd9Sstevel@tonic-gate 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) 15797c478bd9Sstevel@tonic-gate free(tmp_padata); 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate if (scratch) 15827c478bd9Sstevel@tonic-gate krb5_free_data(context, scratch); 15837c478bd9Sstevel@tonic-gate return retval; 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate 1586159d09a2SMark Phalan static krb5_error_code 1587159d09a2SMark Phalan 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 1604159d09a2SMark Phalan 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 162056a424ccSmp153739 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, 162256a424ccSmp153739 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; 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate for (i = 0; i < request->nktypes; i++) { 16357c478bd9Sstevel@tonic-gate if (enctype_requires_etype_info_2(request->ktype[i])) 16367c478bd9Sstevel@tonic-gate 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; 16467c478bd9Sstevel@tonic-gate 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: 16547c478bd9Sstevel@tonic-gate 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; 17037c478bd9Sstevel@tonic-gate 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 171056a424ccSmp153739 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, 171256a424ccSmp153739 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; 17377c478bd9Sstevel@tonic-gate 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 } 18427c478bd9Sstevel@tonic-gate 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 185656a424ccSmp153739 get_sam_edata(krb5_context context, krb5_kdc_req *request, 185756a424ccSmp153739 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 { 188856a424ccSmp153739 int npr = 1; 188956a424ccSmp153739 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)++; 19067c478bd9Sstevel@tonic-gate 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; 19127c478bd9Sstevel@tonic-gate 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); 191656a424ccSmp153739 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); 19417c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"), 19427c478bd9Sstevel@tonic-gate 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, 19507c478bd9Sstevel@tonic-gate &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"), 19557c478bd9Sstevel@tonic-gate 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; 20027c478bd9Sstevel@tonic-gate 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 */ 20497c478bd9Sstevel@tonic-gate 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; 20567c478bd9Sstevel@tonic-gate 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)); 207456a424ccSmp153739 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))) { 21307c478bd9Sstevel@tonic-gate com_err(gettext("krb5kdc"), 21317c478bd9Sstevel@tonic-gate 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; 21777c478bd9Sstevel@tonic-gate 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 */ 22257c478bd9Sstevel@tonic-gate 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; 22327c478bd9Sstevel@tonic-gate 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 224356a424ccSmp153739 verify_sam_response(krb5_context context, krb5_db_entry *client, 2244159d09a2SMark Phalan krb5_data *req_pkt, 224556a424ccSmp153739 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; 22637c478bd9Sstevel@tonic-gate 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; 233356a424ccSmp153739 retval = krb5_rc_store(kdc_context, kdc_rcache, &rep); 233456a424ccSmp153739 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 } 23667c478bd9Sstevel@tonic-gate 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: 23757c478bd9Sstevel@tonic-gate 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); 238256a424ccSmp153739 if (princ_psr) free(princ_psr); 238356a424ccSmp153739 if (princ_req) free(princ_req); 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate return retval; 23867c478bd9Sstevel@tonic-gate } 2387