10Sstevel@tonic-gate /* 2*7934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate 70Sstevel@tonic-gate /* 80Sstevel@tonic-gate * kdc/kdc_preauth.c 90Sstevel@tonic-gate * 102881Smp153739 * Copyright 1995, 2003 by the Massachusetts Institute of Technology. 110Sstevel@tonic-gate * All Rights Reserved. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * Export of this software from the United States of America may 140Sstevel@tonic-gate * require a specific license from the United States Government. 150Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 160Sstevel@tonic-gate * export to obtain such a license before exporting. 170Sstevel@tonic-gate * 180Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 190Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 200Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 210Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 220Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 230Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 240Sstevel@tonic-gate * to distribution of the software without specific, written prior 250Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 260Sstevel@tonic-gate * your software as modified software and not distribute it in such a 270Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 280Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 290Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 300Sstevel@tonic-gate * or implied warranty. 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * Preauthentication routines for the KDC. 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate /* 360Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * All rights reserved. 390Sstevel@tonic-gate * 400Sstevel@tonic-gate * Export of this software from the United States of America may require 410Sstevel@tonic-gate * a specific license from the United States Government. It is the 420Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 430Sstevel@tonic-gate * obtain such a license before exporting. 440Sstevel@tonic-gate * 450Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 460Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 470Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 480Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 490Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 500Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 510Sstevel@tonic-gate * to distribution of the software without specific, written prior 520Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 530Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 540Sstevel@tonic-gate * or implied warranty. 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 570Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 580Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 590Sstevel@tonic-gate */ 600Sstevel@tonic-gate 610Sstevel@tonic-gate #include "k5-int.h" 620Sstevel@tonic-gate #include "kdc_util.h" 630Sstevel@tonic-gate #include "extern.h" 640Sstevel@tonic-gate #include "com_err.h" 650Sstevel@tonic-gate #include <assert.h> 660Sstevel@tonic-gate #include <stdio.h> 672881Smp153739 #include "adm_proto.h" 680Sstevel@tonic-gate #include <libintl.h> 690Sstevel@tonic-gate #include <syslog.h> 700Sstevel@tonic-gate 712881Smp153739 #include <assert.h> 72*7934SMark.Phalan@Sun.COM #include "preauth_plugin.h" 73*7934SMark.Phalan@Sun.COM 74*7934SMark.Phalan@Sun.COM #if TARGET_OS_MAC 75*7934SMark.Phalan@Sun.COM static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/preauth", NULL }; /* should be a list */ 76*7934SMark.Phalan@Sun.COM #else 77*7934SMark.Phalan@Sun.COM static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL }; 78*7934SMark.Phalan@Sun.COM #endif 792881Smp153739 802881Smp153739 /* XXX This is ugly and should be in a header file somewhere */ 812881Smp153739 #ifndef KRB5INT_DES_TYPES_DEFINED 822881Smp153739 #define KRB5INT_DES_TYPES_DEFINED 832881Smp153739 typedef unsigned char des_cblock[8]; /* crypto-block size */ 842881Smp153739 #endif 852881Smp153739 typedef des_cblock mit_des_cblock; 862881Smp153739 extern void mit_des_fixup_key_parity (mit_des_cblock ); 872881Smp153739 extern int mit_des_is_weak_key (mit_des_cblock ); 882881Smp153739 890Sstevel@tonic-gate typedef struct _krb5_preauth_systems { 90*7934SMark.Phalan@Sun.COM const char *name; 910Sstevel@tonic-gate int type; 920Sstevel@tonic-gate int flags; 93*7934SMark.Phalan@Sun.COM void *plugin_context; 94*7934SMark.Phalan@Sun.COM preauth_server_init_proc init; 95*7934SMark.Phalan@Sun.COM preauth_server_fini_proc fini; 96*7934SMark.Phalan@Sun.COM preauth_server_edata_proc get_edata; 97*7934SMark.Phalan@Sun.COM preauth_server_verify_proc verify_padata; 98*7934SMark.Phalan@Sun.COM preauth_server_return_proc return_padata; 99*7934SMark.Phalan@Sun.COM preauth_server_free_reqcontext_proc free_pa_reqctx; 1000Sstevel@tonic-gate } krb5_preauth_systems; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate static krb5_error_code verify_enc_timestamp 1030Sstevel@tonic-gate (krb5_context, krb5_db_entry *client, 104*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 1052881Smp153739 krb5_kdc_req *request, 106*7934SMark.Phalan@Sun.COM krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data, 107*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 108*7934SMark.Phalan@Sun.COM void *pa_system_context, 109*7934SMark.Phalan@Sun.COM void **pa_request_context, 110*7934SMark.Phalan@Sun.COM krb5_data **e_data, 111*7934SMark.Phalan@Sun.COM krb5_authdata ***authz_data); 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate static krb5_error_code get_etype_info 1140Sstevel@tonic-gate (krb5_context, krb5_kdc_req *request, 1152881Smp153739 krb5_db_entry *client, krb5_db_entry *server, 116*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 117*7934SMark.Phalan@Sun.COM void *pa_system_context, 1182881Smp153739 krb5_pa_data *data); 1190Sstevel@tonic-gate static krb5_error_code 1200Sstevel@tonic-gate get_etype_info2(krb5_context context, krb5_kdc_req *request, 121*7934SMark.Phalan@Sun.COM krb5_db_entry *client, krb5_db_entry *server, 122*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 123*7934SMark.Phalan@Sun.COM void *pa_system_context, 124*7934SMark.Phalan@Sun.COM krb5_pa_data *pa_data); 125*7934SMark.Phalan@Sun.COM static krb5_error_code 126*7934SMark.Phalan@Sun.COM etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata, 127*7934SMark.Phalan@Sun.COM krb5_db_entry *client, 128*7934SMark.Phalan@Sun.COM krb5_kdc_req *request, krb5_kdc_rep *reply, 129*7934SMark.Phalan@Sun.COM krb5_key_data *client_key, 130*7934SMark.Phalan@Sun.COM krb5_keyblock *encrypting_key, 131*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 132*7934SMark.Phalan@Sun.COM int etype_info2); 133*7934SMark.Phalan@Sun.COM 134*7934SMark.Phalan@Sun.COM static krb5_error_code 135*7934SMark.Phalan@Sun.COM return_etype_info(krb5_context, krb5_pa_data * padata, 136*7934SMark.Phalan@Sun.COM krb5_db_entry *client, 137*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 138*7934SMark.Phalan@Sun.COM krb5_kdc_req *request, krb5_kdc_rep *reply, 139*7934SMark.Phalan@Sun.COM krb5_key_data *client_key, 140*7934SMark.Phalan@Sun.COM krb5_keyblock *encrypting_key, 141*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 142*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 143*7934SMark.Phalan@Sun.COM void *pa_system_context, 144*7934SMark.Phalan@Sun.COM void **pa_request_context); 145*7934SMark.Phalan@Sun.COM 1460Sstevel@tonic-gate static krb5_error_code 1472881Smp153739 return_etype_info2(krb5_context, krb5_pa_data * padata, 1482881Smp153739 krb5_db_entry *client, 149*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 1502881Smp153739 krb5_kdc_req *request, krb5_kdc_rep *reply, 1512881Smp153739 krb5_key_data *client_key, 1522881Smp153739 krb5_keyblock *encrypting_key, 153*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 154*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 155*7934SMark.Phalan@Sun.COM void *pa_system_context, 156*7934SMark.Phalan@Sun.COM void **pa_request_context); 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate static krb5_error_code return_pw_salt 1590Sstevel@tonic-gate (krb5_context, krb5_pa_data * padata, 1602881Smp153739 krb5_db_entry *client, 161*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 1622881Smp153739 krb5_kdc_req *request, krb5_kdc_rep *reply, 1632881Smp153739 krb5_key_data *client_key, 1642881Smp153739 krb5_keyblock *encrypting_key, 165*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 166*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 167*7934SMark.Phalan@Sun.COM void *pa_system_context, 168*7934SMark.Phalan@Sun.COM void **pa_request_context); 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate /* SAM preauth support */ 1710Sstevel@tonic-gate static krb5_error_code verify_sam_response 1722881Smp153739 (krb5_context, krb5_db_entry *client, 173*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 1742881Smp153739 krb5_kdc_req *request, 175*7934SMark.Phalan@Sun.COM krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data, 176*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 177*7934SMark.Phalan@Sun.COM void *pa_module_context, 178*7934SMark.Phalan@Sun.COM void **pa_request_context, 179*7934SMark.Phalan@Sun.COM krb5_data **e_data, 180*7934SMark.Phalan@Sun.COM krb5_authdata ***authz_data); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate static krb5_error_code get_sam_edata 1830Sstevel@tonic-gate (krb5_context, krb5_kdc_req *request, 1842881Smp153739 krb5_db_entry *client, krb5_db_entry *server, 185*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 186*7934SMark.Phalan@Sun.COM void *pa_module_context, 1872881Smp153739 krb5_pa_data *data); 1880Sstevel@tonic-gate static krb5_error_code return_sam_data 1890Sstevel@tonic-gate (krb5_context, krb5_pa_data * padata, 1902881Smp153739 krb5_db_entry *client, 191*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 1922881Smp153739 krb5_kdc_req *request, krb5_kdc_rep *reply, 1932881Smp153739 krb5_key_data *client_key, 1942881Smp153739 krb5_keyblock *encrypting_key, 195*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 196*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc get_entry_data, 197*7934SMark.Phalan@Sun.COM void *pa_module_context, 198*7934SMark.Phalan@Sun.COM void **pa_request_context); 1990Sstevel@tonic-gate 200*7934SMark.Phalan@Sun.COM static krb5_preauth_systems static_preauth_systems[] = { 2010Sstevel@tonic-gate { 2020Sstevel@tonic-gate "timestamp", 2030Sstevel@tonic-gate KRB5_PADATA_ENC_TIMESTAMP, 2040Sstevel@tonic-gate 0, 205*7934SMark.Phalan@Sun.COM NULL, 206*7934SMark.Phalan@Sun.COM NULL, 207*7934SMark.Phalan@Sun.COM NULL, 2080Sstevel@tonic-gate 0, 2090Sstevel@tonic-gate verify_enc_timestamp, 2100Sstevel@tonic-gate 0 2110Sstevel@tonic-gate }, 2120Sstevel@tonic-gate { 2130Sstevel@tonic-gate "etype-info", 2140Sstevel@tonic-gate KRB5_PADATA_ETYPE_INFO, 2150Sstevel@tonic-gate 0, 216*7934SMark.Phalan@Sun.COM NULL, 217*7934SMark.Phalan@Sun.COM NULL, 218*7934SMark.Phalan@Sun.COM NULL, 2190Sstevel@tonic-gate get_etype_info, 2200Sstevel@tonic-gate 0, 221*7934SMark.Phalan@Sun.COM return_etype_info 2220Sstevel@tonic-gate }, 2230Sstevel@tonic-gate { 2242881Smp153739 "etype-info2", 2250Sstevel@tonic-gate KRB5_PADATA_ETYPE_INFO2, 2260Sstevel@tonic-gate 0, 227*7934SMark.Phalan@Sun.COM NULL, 228*7934SMark.Phalan@Sun.COM NULL, 229*7934SMark.Phalan@Sun.COM NULL, 2302881Smp153739 get_etype_info2, 2310Sstevel@tonic-gate 0, 2322881Smp153739 return_etype_info2 2330Sstevel@tonic-gate }, 2340Sstevel@tonic-gate { 2350Sstevel@tonic-gate "pw-salt", 2360Sstevel@tonic-gate KRB5_PADATA_PW_SALT, 2370Sstevel@tonic-gate PA_PSEUDO, /* Don't include this in the error list */ 238*7934SMark.Phalan@Sun.COM NULL, 239*7934SMark.Phalan@Sun.COM NULL, 240*7934SMark.Phalan@Sun.COM NULL, 2410Sstevel@tonic-gate 0, 2420Sstevel@tonic-gate 0, 2430Sstevel@tonic-gate return_pw_salt 2440Sstevel@tonic-gate }, 2450Sstevel@tonic-gate { 2460Sstevel@tonic-gate "sam-response", 2470Sstevel@tonic-gate KRB5_PADATA_SAM_RESPONSE, 2480Sstevel@tonic-gate 0, 249*7934SMark.Phalan@Sun.COM NULL, 250*7934SMark.Phalan@Sun.COM NULL, 251*7934SMark.Phalan@Sun.COM NULL, 2520Sstevel@tonic-gate 0, 2530Sstevel@tonic-gate verify_sam_response, 2540Sstevel@tonic-gate return_sam_data 2550Sstevel@tonic-gate }, 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate "sam-challenge", 2580Sstevel@tonic-gate KRB5_PADATA_SAM_CHALLENGE, 2590Sstevel@tonic-gate PA_HARDWARE, /* causes get_preauth_hint_list to use this */ 260*7934SMark.Phalan@Sun.COM NULL, 261*7934SMark.Phalan@Sun.COM NULL, 262*7934SMark.Phalan@Sun.COM NULL, 2630Sstevel@tonic-gate get_sam_edata, 2640Sstevel@tonic-gate 0, 2650Sstevel@tonic-gate 0 2660Sstevel@tonic-gate }, 2670Sstevel@tonic-gate { "[end]", -1,} 2680Sstevel@tonic-gate }; 2690Sstevel@tonic-gate 270*7934SMark.Phalan@Sun.COM static krb5_preauth_systems *preauth_systems; 271*7934SMark.Phalan@Sun.COM static int n_preauth_systems; 272*7934SMark.Phalan@Sun.COM static struct plugin_dir_handle preauth_plugins; 273*7934SMark.Phalan@Sun.COM 274*7934SMark.Phalan@Sun.COM krb5_error_code 275*7934SMark.Phalan@Sun.COM load_preauth_plugins(krb5_context context) 276*7934SMark.Phalan@Sun.COM { 277*7934SMark.Phalan@Sun.COM struct errinfo err; 278*7934SMark.Phalan@Sun.COM void **preauth_plugins_ftables; 279*7934SMark.Phalan@Sun.COM struct krb5plugin_preauth_server_ftable_v1 *ftable; 280*7934SMark.Phalan@Sun.COM int module_count, i, j, k; 281*7934SMark.Phalan@Sun.COM void *plugin_context; 282*7934SMark.Phalan@Sun.COM preauth_server_init_proc server_init_proc = NULL; 283*7934SMark.Phalan@Sun.COM char **kdc_realm_names = NULL; 284*7934SMark.Phalan@Sun.COM 285*7934SMark.Phalan@Sun.COM memset(&err, 0, sizeof(err)); 286*7934SMark.Phalan@Sun.COM 287*7934SMark.Phalan@Sun.COM /* Attempt to load all of the preauth plugins we can find. */ 288*7934SMark.Phalan@Sun.COM PLUGIN_DIR_INIT(&preauth_plugins); 289*7934SMark.Phalan@Sun.COM if (PLUGIN_DIR_OPEN(&preauth_plugins) == 0) { 290*7934SMark.Phalan@Sun.COM if (krb5int_open_plugin_dirs(objdirs, NULL, 291*7934SMark.Phalan@Sun.COM &preauth_plugins, &err) != 0) { 292*7934SMark.Phalan@Sun.COM return KRB5_PLUGIN_NO_HANDLE; 293*7934SMark.Phalan@Sun.COM } 294*7934SMark.Phalan@Sun.COM } 295*7934SMark.Phalan@Sun.COM 296*7934SMark.Phalan@Sun.COM /* Get the method tables provided by the loaded plugins. */ 297*7934SMark.Phalan@Sun.COM preauth_plugins_ftables = NULL; 298*7934SMark.Phalan@Sun.COM if (krb5int_get_plugin_dir_data(&preauth_plugins, 299*7934SMark.Phalan@Sun.COM "preauthentication_server_1", 300*7934SMark.Phalan@Sun.COM &preauth_plugins_ftables, &err) != 0) { 301*7934SMark.Phalan@Sun.COM return KRB5_PLUGIN_NO_HANDLE; 302*7934SMark.Phalan@Sun.COM } 303*7934SMark.Phalan@Sun.COM 304*7934SMark.Phalan@Sun.COM /* Count the valid modules. */ 305*7934SMark.Phalan@Sun.COM module_count = sizeof(static_preauth_systems) 306*7934SMark.Phalan@Sun.COM / sizeof(static_preauth_systems[0]); 307*7934SMark.Phalan@Sun.COM if (preauth_plugins_ftables != NULL) { 308*7934SMark.Phalan@Sun.COM for (i = 0; preauth_plugins_ftables[i] != NULL; i++) { 309*7934SMark.Phalan@Sun.COM ftable = preauth_plugins_ftables[i]; 310*7934SMark.Phalan@Sun.COM if ((ftable->flags_proc == NULL) && 311*7934SMark.Phalan@Sun.COM (ftable->edata_proc == NULL) && 312*7934SMark.Phalan@Sun.COM (ftable->verify_proc == NULL) && 313*7934SMark.Phalan@Sun.COM (ftable->return_proc == NULL)) { 314*7934SMark.Phalan@Sun.COM continue; 315*7934SMark.Phalan@Sun.COM } 316*7934SMark.Phalan@Sun.COM for (j = 0; 317*7934SMark.Phalan@Sun.COM ftable->pa_type_list != NULL && 318*7934SMark.Phalan@Sun.COM ftable->pa_type_list[j] > 0; 319*7934SMark.Phalan@Sun.COM j++) { 320*7934SMark.Phalan@Sun.COM module_count++; 321*7934SMark.Phalan@Sun.COM } 322*7934SMark.Phalan@Sun.COM } 323*7934SMark.Phalan@Sun.COM } 324*7934SMark.Phalan@Sun.COM 325*7934SMark.Phalan@Sun.COM /* Build the complete list of supported preauthentication options, and 326*7934SMark.Phalan@Sun.COM * leave room for a terminator entry. */ 327*7934SMark.Phalan@Sun.COM preauth_systems = malloc(sizeof(krb5_preauth_systems) * (module_count + 1)); 328*7934SMark.Phalan@Sun.COM if (preauth_systems == NULL) { 329*7934SMark.Phalan@Sun.COM krb5int_free_plugin_dir_data(preauth_plugins_ftables); 330*7934SMark.Phalan@Sun.COM return ENOMEM; 331*7934SMark.Phalan@Sun.COM } 332*7934SMark.Phalan@Sun.COM 333*7934SMark.Phalan@Sun.COM /* Build a list of the names of the supported realms for this KDC. 334*7934SMark.Phalan@Sun.COM * The list of names is terminated with a NULL. */ 335*7934SMark.Phalan@Sun.COM kdc_realm_names = malloc(sizeof(char *) * (kdc_numrealms + 1)); 336*7934SMark.Phalan@Sun.COM if (kdc_realm_names == NULL) { 337*7934SMark.Phalan@Sun.COM krb5int_free_plugin_dir_data(preauth_plugins_ftables); 338*7934SMark.Phalan@Sun.COM return ENOMEM; 339*7934SMark.Phalan@Sun.COM } 340*7934SMark.Phalan@Sun.COM for (i = 0; i < kdc_numrealms; i++) { 341*7934SMark.Phalan@Sun.COM kdc_realm_names[i] = kdc_realmlist[i]->realm_name; 342*7934SMark.Phalan@Sun.COM } 343*7934SMark.Phalan@Sun.COM kdc_realm_names[i] = NULL; 344*7934SMark.Phalan@Sun.COM 345*7934SMark.Phalan@Sun.COM /* Add the locally-supplied mechanisms to the dynamic list first. */ 346*7934SMark.Phalan@Sun.COM for (i = 0, k = 0; 347*7934SMark.Phalan@Sun.COM i < sizeof(static_preauth_systems) / sizeof(static_preauth_systems[0]); 348*7934SMark.Phalan@Sun.COM i++) { 349*7934SMark.Phalan@Sun.COM if (static_preauth_systems[i].type == -1) 350*7934SMark.Phalan@Sun.COM break; 351*7934SMark.Phalan@Sun.COM preauth_systems[k] = static_preauth_systems[i]; 352*7934SMark.Phalan@Sun.COM /* Try to initialize the preauth system. If it fails, we'll remove it 353*7934SMark.Phalan@Sun.COM * from the list of systems we'll be using. */ 354*7934SMark.Phalan@Sun.COM plugin_context = NULL; 355*7934SMark.Phalan@Sun.COM server_init_proc = static_preauth_systems[i].init; 356*7934SMark.Phalan@Sun.COM if ((server_init_proc != NULL) && 357*7934SMark.Phalan@Sun.COM ((*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names) != 0)) { 358*7934SMark.Phalan@Sun.COM memset(&preauth_systems[k], 0, sizeof(preauth_systems[k])); 359*7934SMark.Phalan@Sun.COM continue; 360*7934SMark.Phalan@Sun.COM } 361*7934SMark.Phalan@Sun.COM preauth_systems[k].plugin_context = plugin_context; 362*7934SMark.Phalan@Sun.COM k++; 363*7934SMark.Phalan@Sun.COM } 364*7934SMark.Phalan@Sun.COM 365*7934SMark.Phalan@Sun.COM /* Now add the dynamically-loaded mechanisms to the list. */ 366*7934SMark.Phalan@Sun.COM if (preauth_plugins_ftables != NULL) { 367*7934SMark.Phalan@Sun.COM for (i = 0; preauth_plugins_ftables[i] != NULL; i++) { 368*7934SMark.Phalan@Sun.COM ftable = preauth_plugins_ftables[i]; 369*7934SMark.Phalan@Sun.COM if ((ftable->flags_proc == NULL) && 370*7934SMark.Phalan@Sun.COM (ftable->edata_proc == NULL) && 371*7934SMark.Phalan@Sun.COM (ftable->verify_proc == NULL) && 372*7934SMark.Phalan@Sun.COM (ftable->return_proc == NULL)) { 373*7934SMark.Phalan@Sun.COM continue; 374*7934SMark.Phalan@Sun.COM } 375*7934SMark.Phalan@Sun.COM plugin_context = NULL; 376*7934SMark.Phalan@Sun.COM for (j = 0; 377*7934SMark.Phalan@Sun.COM ftable->pa_type_list != NULL && 378*7934SMark.Phalan@Sun.COM ftable->pa_type_list[j] > 0; 379*7934SMark.Phalan@Sun.COM j++) { 380*7934SMark.Phalan@Sun.COM /* Try to initialize the plugin. If it fails, we'll remove it 381*7934SMark.Phalan@Sun.COM * from the list of modules we'll be using. */ 382*7934SMark.Phalan@Sun.COM if (j == 0) { 383*7934SMark.Phalan@Sun.COM server_init_proc = ftable->init_proc; 384*7934SMark.Phalan@Sun.COM if (server_init_proc != NULL) { 385*7934SMark.Phalan@Sun.COM krb5_error_code initerr; 386*7934SMark.Phalan@Sun.COM initerr = (*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names); 387*7934SMark.Phalan@Sun.COM if (initerr) { 388*7934SMark.Phalan@Sun.COM const char *emsg; 389*7934SMark.Phalan@Sun.COM emsg = krb5_get_error_message(context, initerr); 390*7934SMark.Phalan@Sun.COM if (emsg) { 391*7934SMark.Phalan@Sun.COM krb5_klog_syslog(LOG_ERR, 392*7934SMark.Phalan@Sun.COM "preauth %s failed to initialize: %s", 393*7934SMark.Phalan@Sun.COM ftable->name, emsg); 394*7934SMark.Phalan@Sun.COM krb5_free_error_message(context, emsg); 395*7934SMark.Phalan@Sun.COM } 396*7934SMark.Phalan@Sun.COM memset(&preauth_systems[k], 0, sizeof(preauth_systems[k])); 397*7934SMark.Phalan@Sun.COM 398*7934SMark.Phalan@Sun.COM break; /* skip all modules in this plugin */ 399*7934SMark.Phalan@Sun.COM } 400*7934SMark.Phalan@Sun.COM } 401*7934SMark.Phalan@Sun.COM } 402*7934SMark.Phalan@Sun.COM preauth_systems[k].name = ftable->name; 403*7934SMark.Phalan@Sun.COM preauth_systems[k].type = ftable->pa_type_list[j]; 404*7934SMark.Phalan@Sun.COM if (ftable->flags_proc != NULL) 405*7934SMark.Phalan@Sun.COM preauth_systems[k].flags = ftable->flags_proc(context, preauth_systems[k].type); 406*7934SMark.Phalan@Sun.COM else 407*7934SMark.Phalan@Sun.COM preauth_systems[k].flags = 0; 408*7934SMark.Phalan@Sun.COM preauth_systems[k].plugin_context = plugin_context; 409*7934SMark.Phalan@Sun.COM preauth_systems[k].init = server_init_proc; 410*7934SMark.Phalan@Sun.COM /* Only call fini once for each plugin */ 411*7934SMark.Phalan@Sun.COM if (j == 0) 412*7934SMark.Phalan@Sun.COM preauth_systems[k].fini = ftable->fini_proc; 413*7934SMark.Phalan@Sun.COM else 414*7934SMark.Phalan@Sun.COM preauth_systems[k].fini = NULL; 415*7934SMark.Phalan@Sun.COM preauth_systems[k].get_edata = ftable->edata_proc; 416*7934SMark.Phalan@Sun.COM preauth_systems[k].verify_padata = ftable->verify_proc; 417*7934SMark.Phalan@Sun.COM preauth_systems[k].return_padata = ftable->return_proc; 418*7934SMark.Phalan@Sun.COM preauth_systems[k].free_pa_reqctx = 419*7934SMark.Phalan@Sun.COM ftable->freepa_reqcontext_proc; 420*7934SMark.Phalan@Sun.COM k++; 421*7934SMark.Phalan@Sun.COM } 422*7934SMark.Phalan@Sun.COM } 423*7934SMark.Phalan@Sun.COM krb5int_free_plugin_dir_data(preauth_plugins_ftables); 424*7934SMark.Phalan@Sun.COM } 425*7934SMark.Phalan@Sun.COM free(kdc_realm_names); 426*7934SMark.Phalan@Sun.COM n_preauth_systems = k; 427*7934SMark.Phalan@Sun.COM /* Add the end-of-list marker. */ 428*7934SMark.Phalan@Sun.COM preauth_systems[k].name = "[end]"; 429*7934SMark.Phalan@Sun.COM preauth_systems[k].type = -1; 430*7934SMark.Phalan@Sun.COM return 0; 431*7934SMark.Phalan@Sun.COM } 432*7934SMark.Phalan@Sun.COM 433*7934SMark.Phalan@Sun.COM krb5_error_code 434*7934SMark.Phalan@Sun.COM unload_preauth_plugins(krb5_context context) 435*7934SMark.Phalan@Sun.COM { 436*7934SMark.Phalan@Sun.COM int i; 437*7934SMark.Phalan@Sun.COM if (preauth_systems != NULL) { 438*7934SMark.Phalan@Sun.COM for (i = 0; i < n_preauth_systems; i++) { 439*7934SMark.Phalan@Sun.COM if (preauth_systems[i].fini != NULL) { 440*7934SMark.Phalan@Sun.COM (*preauth_systems[i].fini)(context, 441*7934SMark.Phalan@Sun.COM preauth_systems[i].plugin_context); 442*7934SMark.Phalan@Sun.COM } 443*7934SMark.Phalan@Sun.COM memset(&preauth_systems[i], 0, sizeof(preauth_systems[i])); 444*7934SMark.Phalan@Sun.COM } 445*7934SMark.Phalan@Sun.COM free(preauth_systems); 446*7934SMark.Phalan@Sun.COM preauth_systems = NULL; 447*7934SMark.Phalan@Sun.COM n_preauth_systems = 0; 448*7934SMark.Phalan@Sun.COM krb5int_close_plugin_dirs(&preauth_plugins); 449*7934SMark.Phalan@Sun.COM } 450*7934SMark.Phalan@Sun.COM return 0; 451*7934SMark.Phalan@Sun.COM } 452*7934SMark.Phalan@Sun.COM 453*7934SMark.Phalan@Sun.COM /* 454*7934SMark.Phalan@Sun.COM * The make_padata_context() function creates a space for storing any context 455*7934SMark.Phalan@Sun.COM * information which will be needed by return_padata() later. Each preauth 456*7934SMark.Phalan@Sun.COM * type gets a context storage location of its own. 457*7934SMark.Phalan@Sun.COM */ 458*7934SMark.Phalan@Sun.COM struct request_pa_context { 459*7934SMark.Phalan@Sun.COM int n_contexts; 460*7934SMark.Phalan@Sun.COM struct { 461*7934SMark.Phalan@Sun.COM krb5_preauth_systems *pa_system; 462*7934SMark.Phalan@Sun.COM void *pa_context; 463*7934SMark.Phalan@Sun.COM } *contexts; 464*7934SMark.Phalan@Sun.COM }; 465*7934SMark.Phalan@Sun.COM 466*7934SMark.Phalan@Sun.COM static krb5_error_code 467*7934SMark.Phalan@Sun.COM make_padata_context(krb5_context context, void **padata_context) 468*7934SMark.Phalan@Sun.COM { 469*7934SMark.Phalan@Sun.COM int i; 470*7934SMark.Phalan@Sun.COM struct request_pa_context *ret; 471*7934SMark.Phalan@Sun.COM 472*7934SMark.Phalan@Sun.COM ret = malloc(sizeof(*ret)); 473*7934SMark.Phalan@Sun.COM if (ret == NULL) { 474*7934SMark.Phalan@Sun.COM return ENOMEM; 475*7934SMark.Phalan@Sun.COM } 476*7934SMark.Phalan@Sun.COM 477*7934SMark.Phalan@Sun.COM ret->n_contexts = n_preauth_systems; 478*7934SMark.Phalan@Sun.COM ret->contexts = malloc(sizeof(ret->contexts[0]) * ret->n_contexts); 479*7934SMark.Phalan@Sun.COM if (ret->contexts == NULL) { 480*7934SMark.Phalan@Sun.COM free(ret); 481*7934SMark.Phalan@Sun.COM return ENOMEM; 482*7934SMark.Phalan@Sun.COM } 483*7934SMark.Phalan@Sun.COM 484*7934SMark.Phalan@Sun.COM memset(ret->contexts, 0, sizeof(ret->contexts[0]) * ret->n_contexts); 485*7934SMark.Phalan@Sun.COM 486*7934SMark.Phalan@Sun.COM for (i = 0; i < ret->n_contexts; i++) { 487*7934SMark.Phalan@Sun.COM ret->contexts[i].pa_system = &preauth_systems[i]; 488*7934SMark.Phalan@Sun.COM ret->contexts[i].pa_context = NULL; 489*7934SMark.Phalan@Sun.COM } 490*7934SMark.Phalan@Sun.COM 491*7934SMark.Phalan@Sun.COM *padata_context = ret; 492*7934SMark.Phalan@Sun.COM 493*7934SMark.Phalan@Sun.COM return 0; 494*7934SMark.Phalan@Sun.COM } 495*7934SMark.Phalan@Sun.COM 496*7934SMark.Phalan@Sun.COM /* 497*7934SMark.Phalan@Sun.COM * The free_padata_context function frees any context information pointers 498*7934SMark.Phalan@Sun.COM * which the check_padata() function created but which weren't already cleaned 499*7934SMark.Phalan@Sun.COM * up by return_padata(). 500*7934SMark.Phalan@Sun.COM */ 501*7934SMark.Phalan@Sun.COM krb5_error_code 502*7934SMark.Phalan@Sun.COM free_padata_context(krb5_context kcontext, void **padata_context) 503*7934SMark.Phalan@Sun.COM { 504*7934SMark.Phalan@Sun.COM struct request_pa_context *context; 505*7934SMark.Phalan@Sun.COM krb5_preauth_systems *preauth_system; 506*7934SMark.Phalan@Sun.COM void **pctx, *mctx; 507*7934SMark.Phalan@Sun.COM int i; 508*7934SMark.Phalan@Sun.COM 509*7934SMark.Phalan@Sun.COM if (padata_context == NULL) 510*7934SMark.Phalan@Sun.COM return 0; 511*7934SMark.Phalan@Sun.COM 512*7934SMark.Phalan@Sun.COM context = *padata_context; 513*7934SMark.Phalan@Sun.COM 514*7934SMark.Phalan@Sun.COM for (i = 0; i < context->n_contexts; i++) { 515*7934SMark.Phalan@Sun.COM if (context->contexts[i].pa_context != NULL) { 516*7934SMark.Phalan@Sun.COM preauth_system = context->contexts[i].pa_system; 517*7934SMark.Phalan@Sun.COM mctx = preauth_system->plugin_context; 518*7934SMark.Phalan@Sun.COM if (preauth_system->free_pa_reqctx != NULL) { 519*7934SMark.Phalan@Sun.COM pctx = &context->contexts[i].pa_context; 520*7934SMark.Phalan@Sun.COM (*preauth_system->free_pa_reqctx)(kcontext, mctx, pctx); 521*7934SMark.Phalan@Sun.COM } 522*7934SMark.Phalan@Sun.COM context->contexts[i].pa_context = NULL; 523*7934SMark.Phalan@Sun.COM } 524*7934SMark.Phalan@Sun.COM } 525*7934SMark.Phalan@Sun.COM 526*7934SMark.Phalan@Sun.COM free(context->contexts); 527*7934SMark.Phalan@Sun.COM free(context); 528*7934SMark.Phalan@Sun.COM 529*7934SMark.Phalan@Sun.COM return 0; 530*7934SMark.Phalan@Sun.COM } 531*7934SMark.Phalan@Sun.COM 532*7934SMark.Phalan@Sun.COM /* Retrieve a specified tl_data item from the given entry, and return its 533*7934SMark.Phalan@Sun.COM * contents in a new krb5_data, which must be freed by the caller. */ 534*7934SMark.Phalan@Sun.COM static krb5_error_code 535*7934SMark.Phalan@Sun.COM get_entry_tl_data(krb5_context context, krb5_db_entry *entry, 536*7934SMark.Phalan@Sun.COM krb5_int16 tl_data_type, krb5_data **result) 537*7934SMark.Phalan@Sun.COM { 538*7934SMark.Phalan@Sun.COM krb5_tl_data *tl; 539*7934SMark.Phalan@Sun.COM for (tl = entry->tl_data; tl != NULL; tl = tl->tl_data_next) { 540*7934SMark.Phalan@Sun.COM if (tl->tl_data_type == tl_data_type) { 541*7934SMark.Phalan@Sun.COM *result = malloc(sizeof(krb5_data)); 542*7934SMark.Phalan@Sun.COM if (*result == NULL) { 543*7934SMark.Phalan@Sun.COM return ENOMEM; 544*7934SMark.Phalan@Sun.COM } 545*7934SMark.Phalan@Sun.COM (*result)->magic = KV5M_DATA; 546*7934SMark.Phalan@Sun.COM (*result)->data = malloc(tl->tl_data_length); 547*7934SMark.Phalan@Sun.COM if ((*result)->data == NULL) { 548*7934SMark.Phalan@Sun.COM free(*result); 549*7934SMark.Phalan@Sun.COM *result = NULL; 550*7934SMark.Phalan@Sun.COM return ENOMEM; 551*7934SMark.Phalan@Sun.COM } 552*7934SMark.Phalan@Sun.COM memcpy((*result)->data, tl->tl_data_contents, tl->tl_data_length); 553*7934SMark.Phalan@Sun.COM return 0; 554*7934SMark.Phalan@Sun.COM } 555*7934SMark.Phalan@Sun.COM } 556*7934SMark.Phalan@Sun.COM return ENOENT; 557*7934SMark.Phalan@Sun.COM } 558*7934SMark.Phalan@Sun.COM 559*7934SMark.Phalan@Sun.COM /* 560*7934SMark.Phalan@Sun.COM * Retrieve a specific piece of information pertaining to the entry or the 561*7934SMark.Phalan@Sun.COM * request and return it in a new krb5_data item which the caller must free. 562*7934SMark.Phalan@Sun.COM * 563*7934SMark.Phalan@Sun.COM * This may require massaging data into a contrived format, but it will 564*7934SMark.Phalan@Sun.COM * hopefully keep us from having to reveal library-internal functions to 565*7934SMark.Phalan@Sun.COM * modules. 566*7934SMark.Phalan@Sun.COM */ 567*7934SMark.Phalan@Sun.COM static krb5_error_code 568*7934SMark.Phalan@Sun.COM get_entry_data(krb5_context context, 569*7934SMark.Phalan@Sun.COM krb5_kdc_req *request, krb5_db_entry *entry, 570*7934SMark.Phalan@Sun.COM krb5_int32 type, 571*7934SMark.Phalan@Sun.COM krb5_data **result) 572*7934SMark.Phalan@Sun.COM { 573*7934SMark.Phalan@Sun.COM int i, k; 574*7934SMark.Phalan@Sun.COM krb5_data *ret; 575*7934SMark.Phalan@Sun.COM krb5_deltat *delta; 576*7934SMark.Phalan@Sun.COM krb5_keyblock *keys; 577*7934SMark.Phalan@Sun.COM krb5_key_data *entry_key; 578*7934SMark.Phalan@Sun.COM 579*7934SMark.Phalan@Sun.COM switch (type) { 580*7934SMark.Phalan@Sun.COM case krb5plugin_preauth_entry_request_certificate: 581*7934SMark.Phalan@Sun.COM return get_entry_tl_data(context, entry, 582*7934SMark.Phalan@Sun.COM KRB5_TL_USER_CERTIFICATE, result); 583*7934SMark.Phalan@Sun.COM break; 584*7934SMark.Phalan@Sun.COM case krb5plugin_preauth_entry_max_time_skew: 585*7934SMark.Phalan@Sun.COM ret = malloc(sizeof(krb5_data)); 586*7934SMark.Phalan@Sun.COM if (ret == NULL) 587*7934SMark.Phalan@Sun.COM return ENOMEM; 588*7934SMark.Phalan@Sun.COM delta = malloc(sizeof(krb5_deltat)); 589*7934SMark.Phalan@Sun.COM if (delta == NULL) { 590*7934SMark.Phalan@Sun.COM free(ret); 591*7934SMark.Phalan@Sun.COM return ENOMEM; 592*7934SMark.Phalan@Sun.COM } 593*7934SMark.Phalan@Sun.COM *delta = context->clockskew; 594*7934SMark.Phalan@Sun.COM ret->data = (char *) delta; 595*7934SMark.Phalan@Sun.COM ret->length = sizeof(*delta); 596*7934SMark.Phalan@Sun.COM *result = ret; 597*7934SMark.Phalan@Sun.COM return 0; 598*7934SMark.Phalan@Sun.COM break; 599*7934SMark.Phalan@Sun.COM case krb5plugin_preauth_keys: 600*7934SMark.Phalan@Sun.COM ret = malloc(sizeof(krb5_data)); 601*7934SMark.Phalan@Sun.COM if (ret == NULL) 602*7934SMark.Phalan@Sun.COM return ENOMEM; 603*7934SMark.Phalan@Sun.COM keys = malloc(sizeof(krb5_keyblock) * (request->nktypes + 1)); 604*7934SMark.Phalan@Sun.COM if (keys == NULL) { 605*7934SMark.Phalan@Sun.COM free(ret); 606*7934SMark.Phalan@Sun.COM return ENOMEM; 607*7934SMark.Phalan@Sun.COM } 608*7934SMark.Phalan@Sun.COM ret->data = (char *) keys; 609*7934SMark.Phalan@Sun.COM ret->length = sizeof(krb5_keyblock) * (request->nktypes + 1); 610*7934SMark.Phalan@Sun.COM memset(ret->data, 0, ret->length); 611*7934SMark.Phalan@Sun.COM k = 0; 612*7934SMark.Phalan@Sun.COM for (i = 0; i < request->nktypes; i++) { 613*7934SMark.Phalan@Sun.COM entry_key = NULL; 614*7934SMark.Phalan@Sun.COM if (krb5_dbe_find_enctype(context, entry, request->ktype[i], 615*7934SMark.Phalan@Sun.COM -1, 0, &entry_key) != 0) 616*7934SMark.Phalan@Sun.COM continue; 617*7934SMark.Phalan@Sun.COM if (krb5_dbekd_decrypt_key_data(context, &master_keyblock, 618*7934SMark.Phalan@Sun.COM entry_key, &keys[k], NULL) != 0) { 619*7934SMark.Phalan@Sun.COM if (keys[k].contents != NULL) 620*7934SMark.Phalan@Sun.COM krb5_free_keyblock_contents(context, &keys[k]); 621*7934SMark.Phalan@Sun.COM memset(&keys[k], 0, sizeof(keys[k])); 622*7934SMark.Phalan@Sun.COM continue; 623*7934SMark.Phalan@Sun.COM } 624*7934SMark.Phalan@Sun.COM k++; 625*7934SMark.Phalan@Sun.COM } 626*7934SMark.Phalan@Sun.COM if (k > 0) { 627*7934SMark.Phalan@Sun.COM *result = ret; 628*7934SMark.Phalan@Sun.COM return 0; 629*7934SMark.Phalan@Sun.COM } else { 630*7934SMark.Phalan@Sun.COM free(keys); 631*7934SMark.Phalan@Sun.COM free(ret); 632*7934SMark.Phalan@Sun.COM } 633*7934SMark.Phalan@Sun.COM break; 634*7934SMark.Phalan@Sun.COM case krb5plugin_preauth_request_body: 635*7934SMark.Phalan@Sun.COM ret = NULL; 636*7934SMark.Phalan@Sun.COM encode_krb5_kdc_req_body(request, &ret); 637*7934SMark.Phalan@Sun.COM if (ret != NULL) { 638*7934SMark.Phalan@Sun.COM *result = ret; 639*7934SMark.Phalan@Sun.COM return 0; 640*7934SMark.Phalan@Sun.COM } 641*7934SMark.Phalan@Sun.COM return ASN1_PARSE_ERROR; 642*7934SMark.Phalan@Sun.COM break; 643*7934SMark.Phalan@Sun.COM default: 644*7934SMark.Phalan@Sun.COM break; 645*7934SMark.Phalan@Sun.COM } 646*7934SMark.Phalan@Sun.COM return ENOENT; 647*7934SMark.Phalan@Sun.COM } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate static krb5_error_code 6500Sstevel@tonic-gate find_pa_system(int type, krb5_preauth_systems **preauth) 6510Sstevel@tonic-gate { 652*7934SMark.Phalan@Sun.COM krb5_preauth_systems *ap; 653*7934SMark.Phalan@Sun.COM 654*7934SMark.Phalan@Sun.COM ap = preauth_systems ? preauth_systems : static_preauth_systems; 6550Sstevel@tonic-gate while ((ap->type != -1) && (ap->type != type)) 6560Sstevel@tonic-gate ap++; 6570Sstevel@tonic-gate if (ap->type == -1) 6580Sstevel@tonic-gate return(KRB5_PREAUTH_BAD_TYPE); 6590Sstevel@tonic-gate *preauth = ap; 6600Sstevel@tonic-gate return 0; 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate 663*7934SMark.Phalan@Sun.COM static krb5_error_code 664*7934SMark.Phalan@Sun.COM find_pa_context(krb5_preauth_systems *pa_sys, 665*7934SMark.Phalan@Sun.COM struct request_pa_context *context, 666*7934SMark.Phalan@Sun.COM void ***pa_context) 667*7934SMark.Phalan@Sun.COM { 668*7934SMark.Phalan@Sun.COM int i; 669*7934SMark.Phalan@Sun.COM 670*7934SMark.Phalan@Sun.COM *pa_context = 0; 671*7934SMark.Phalan@Sun.COM 672*7934SMark.Phalan@Sun.COM if (context == NULL) 673*7934SMark.Phalan@Sun.COM return KRB5KRB_ERR_GENERIC; 674*7934SMark.Phalan@Sun.COM 675*7934SMark.Phalan@Sun.COM for (i = 0; i < context->n_contexts; i++) { 676*7934SMark.Phalan@Sun.COM if (context->contexts[i].pa_system == pa_sys) { 677*7934SMark.Phalan@Sun.COM *pa_context = &context->contexts[i].pa_context; 678*7934SMark.Phalan@Sun.COM return 0; 679*7934SMark.Phalan@Sun.COM } 680*7934SMark.Phalan@Sun.COM } 681*7934SMark.Phalan@Sun.COM 682*7934SMark.Phalan@Sun.COM return KRB5KRB_ERR_GENERIC; 683*7934SMark.Phalan@Sun.COM } 684*7934SMark.Phalan@Sun.COM 685*7934SMark.Phalan@Sun.COM /* 686*7934SMark.Phalan@Sun.COM * Create a list of indices into the preauth_systems array, sorted by order of 687*7934SMark.Phalan@Sun.COM * preference. 688*7934SMark.Phalan@Sun.COM */ 689*7934SMark.Phalan@Sun.COM static krb5_boolean 690*7934SMark.Phalan@Sun.COM pa_list_includes(krb5_pa_data **pa_data, krb5_preauthtype pa_type) 691*7934SMark.Phalan@Sun.COM { 692*7934SMark.Phalan@Sun.COM while (*pa_data != NULL) { 693*7934SMark.Phalan@Sun.COM if ((*pa_data)->pa_type == pa_type) 694*7934SMark.Phalan@Sun.COM return TRUE; 695*7934SMark.Phalan@Sun.COM pa_data++; 696*7934SMark.Phalan@Sun.COM } 697*7934SMark.Phalan@Sun.COM return FALSE; 698*7934SMark.Phalan@Sun.COM } 699*7934SMark.Phalan@Sun.COM static void 700*7934SMark.Phalan@Sun.COM sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order) 701*7934SMark.Phalan@Sun.COM { 702*7934SMark.Phalan@Sun.COM int i, j, k, n_repliers, n_key_replacers; 703*7934SMark.Phalan@Sun.COM 704*7934SMark.Phalan@Sun.COM /* First, set up the default order. */ 705*7934SMark.Phalan@Sun.COM i = 0; 706*7934SMark.Phalan@Sun.COM for (j = 0; j < n_preauth_systems; j++) { 707*7934SMark.Phalan@Sun.COM if (preauth_systems[j].return_padata != NULL) 708*7934SMark.Phalan@Sun.COM pa_order[i++] = j; 709*7934SMark.Phalan@Sun.COM } 710*7934SMark.Phalan@Sun.COM n_repliers = i; 711*7934SMark.Phalan@Sun.COM pa_order[n_repliers] = -1; 712*7934SMark.Phalan@Sun.COM 713*7934SMark.Phalan@Sun.COM /* Reorder so that PA_REPLACES_KEY modules are listed first. */ 714*7934SMark.Phalan@Sun.COM for (i = 0; i < n_repliers; i++) { 715*7934SMark.Phalan@Sun.COM /* If this module replaces the key, then it's okay to leave it where it 716*7934SMark.Phalan@Sun.COM * is in the order. */ 717*7934SMark.Phalan@Sun.COM if (preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY) 718*7934SMark.Phalan@Sun.COM continue; 719*7934SMark.Phalan@Sun.COM /* If not, search for a module which does, and swap in the first one we 720*7934SMark.Phalan@Sun.COM * find. */ 721*7934SMark.Phalan@Sun.COM for (j = i + 1; j < n_repliers; j++) { 722*7934SMark.Phalan@Sun.COM if (preauth_systems[pa_order[j]].flags & PA_REPLACES_KEY) { 723*7934SMark.Phalan@Sun.COM k = pa_order[j]; 724*7934SMark.Phalan@Sun.COM pa_order[j] = pa_order[i]; 725*7934SMark.Phalan@Sun.COM pa_order[i] = k; 726*7934SMark.Phalan@Sun.COM break; 727*7934SMark.Phalan@Sun.COM } 728*7934SMark.Phalan@Sun.COM } 729*7934SMark.Phalan@Sun.COM } 730*7934SMark.Phalan@Sun.COM 731*7934SMark.Phalan@Sun.COM if (request->padata != NULL) { 732*7934SMark.Phalan@Sun.COM /* Now reorder the subset of modules which replace the key, 733*7934SMark.Phalan@Sun.COM * bubbling those which handle pa_data types provided by the 734*7934SMark.Phalan@Sun.COM * client ahead of the others. */ 735*7934SMark.Phalan@Sun.COM for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) { 736*7934SMark.Phalan@Sun.COM continue; 737*7934SMark.Phalan@Sun.COM } 738*7934SMark.Phalan@Sun.COM n_key_replacers = i; 739*7934SMark.Phalan@Sun.COM for (i = 0; i < n_key_replacers; i++) { 740*7934SMark.Phalan@Sun.COM if (pa_list_includes(request->padata, 741*7934SMark.Phalan@Sun.COM preauth_systems[pa_order[i]].type)) 742*7934SMark.Phalan@Sun.COM continue; 743*7934SMark.Phalan@Sun.COM for (j = i + 1; j < n_key_replacers; j++) { 744*7934SMark.Phalan@Sun.COM if (pa_list_includes(request->padata, 745*7934SMark.Phalan@Sun.COM preauth_systems[pa_order[j]].type)) { 746*7934SMark.Phalan@Sun.COM k = pa_order[j]; 747*7934SMark.Phalan@Sun.COM pa_order[j] = pa_order[i]; 748*7934SMark.Phalan@Sun.COM pa_order[i] = k; 749*7934SMark.Phalan@Sun.COM break; 750*7934SMark.Phalan@Sun.COM } 751*7934SMark.Phalan@Sun.COM } 752*7934SMark.Phalan@Sun.COM } 753*7934SMark.Phalan@Sun.COM } 754*7934SMark.Phalan@Sun.COM #ifdef DEBUG 755*7934SMark.Phalan@Sun.COM krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:"); 756*7934SMark.Phalan@Sun.COM for (i = 0; i < n_preauth_systems; i++) { 757*7934SMark.Phalan@Sun.COM if (preauth_systems[i].return_padata != NULL) 758*7934SMark.Phalan@Sun.COM krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", preauth_systems[i].name, 759*7934SMark.Phalan@Sun.COM preauth_systems[i].type); 760*7934SMark.Phalan@Sun.COM } 761*7934SMark.Phalan@Sun.COM krb5_klog_syslog(LOG_DEBUG, "sorted preauth mechanism list:"); 762*7934SMark.Phalan@Sun.COM for (i = 0; pa_order[i] != -1; i++) { 763*7934SMark.Phalan@Sun.COM krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", 764*7934SMark.Phalan@Sun.COM preauth_systems[pa_order[i]].name, 765*7934SMark.Phalan@Sun.COM preauth_systems[pa_order[i]].type); 766*7934SMark.Phalan@Sun.COM } 767*7934SMark.Phalan@Sun.COM #endif 768*7934SMark.Phalan@Sun.COM } 769*7934SMark.Phalan@Sun.COM 7702881Smp153739 const char *missing_required_preauth(krb5_db_entry *client, 7712881Smp153739 krb5_db_entry *server, 7722881Smp153739 krb5_enc_tkt_part *enc_tkt_reply) 7730Sstevel@tonic-gate { 7740Sstevel@tonic-gate #if 0 7750Sstevel@tonic-gate /* 7760Sstevel@tonic-gate * If this is the pwchange service, and the pre-auth bit is set, 7770Sstevel@tonic-gate * allow it even if the HW preauth would normally be required. 7780Sstevel@tonic-gate * 7790Sstevel@tonic-gate * Sandia national labs wanted this for some strange reason... we 7800Sstevel@tonic-gate * leave it disabled normally. 7810Sstevel@tonic-gate */ 7820Sstevel@tonic-gate if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) && 7830Sstevel@tonic-gate isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH)) 7840Sstevel@tonic-gate return 0; 7850Sstevel@tonic-gate #endif 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate #ifdef DEBUG 7880Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, 7890Sstevel@tonic-gate "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth", 7900Sstevel@tonic-gate isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ", 7910Sstevel@tonic-gate isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ", 7920Sstevel@tonic-gate isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ", 7930Sstevel@tonic-gate isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no "); 7940Sstevel@tonic-gate #endif 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) && 7970Sstevel@tonic-gate !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH)) 7980Sstevel@tonic-gate return "NEEDED_PREAUTH"; 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) && 8010Sstevel@tonic-gate !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH)) 8020Sstevel@tonic-gate return "NEEDED_HW_PREAUTH"; 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate return 0; 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate 8072881Smp153739 void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client, 8082881Smp153739 krb5_db_entry *server, krb5_data *e_data) 8090Sstevel@tonic-gate { 8100Sstevel@tonic-gate int hw_only; 8110Sstevel@tonic-gate krb5_preauth_systems *ap; 8120Sstevel@tonic-gate krb5_pa_data **pa_data, **pa; 8130Sstevel@tonic-gate krb5_data *edat; 8140Sstevel@tonic-gate krb5_error_code retval; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* Zero these out in case we need to abort */ 8170Sstevel@tonic-gate e_data->length = 0; 8180Sstevel@tonic-gate e_data->data = 0; 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH); 821*7934SMark.Phalan@Sun.COM pa_data = malloc(sizeof(krb5_pa_data *) * (n_preauth_systems+1)); 8220Sstevel@tonic-gate if (pa_data == 0) 8230Sstevel@tonic-gate return; 824*7934SMark.Phalan@Sun.COM memset(pa_data, 0, sizeof(krb5_pa_data *) * (n_preauth_systems+1)); 8250Sstevel@tonic-gate pa = pa_data; 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate for (ap = preauth_systems; ap->type != -1; ap++) { 8280Sstevel@tonic-gate if (hw_only && !(ap->flags & PA_HARDWARE)) 8290Sstevel@tonic-gate continue; 8300Sstevel@tonic-gate if (ap->flags & PA_PSEUDO) 8310Sstevel@tonic-gate continue; 8320Sstevel@tonic-gate *pa = malloc(sizeof(krb5_pa_data)); 8330Sstevel@tonic-gate if (*pa == 0) 8340Sstevel@tonic-gate goto errout; 8350Sstevel@tonic-gate memset(*pa, 0, sizeof(krb5_pa_data)); 8360Sstevel@tonic-gate (*pa)->magic = KV5M_PA_DATA; 8370Sstevel@tonic-gate (*pa)->pa_type = ap->type; 8380Sstevel@tonic-gate if (ap->get_edata) { 839*7934SMark.Phalan@Sun.COM retval = (ap->get_edata)(kdc_context, request, client, server, 840*7934SMark.Phalan@Sun.COM get_entry_data, ap->plugin_context, *pa); 8410Sstevel@tonic-gate if (retval) { 8420Sstevel@tonic-gate /* just failed on this type, continue */ 8430Sstevel@tonic-gate free(*pa); 8440Sstevel@tonic-gate *pa = 0; 8450Sstevel@tonic-gate continue; 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate pa++; 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate if (pa_data[0] == 0) { 8510Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO, 8520Sstevel@tonic-gate "%spreauth required but hint list is empty", 8530Sstevel@tonic-gate hw_only ? "hw" : ""); 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate retval = encode_krb5_padata_sequence((const krb5_pa_data **) pa_data, 8560Sstevel@tonic-gate &edat); 8570Sstevel@tonic-gate if (retval) 8580Sstevel@tonic-gate goto errout; 8590Sstevel@tonic-gate *e_data = *edat; 8600Sstevel@tonic-gate free(edat); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate errout: 8630Sstevel@tonic-gate krb5_free_pa_data(kdc_context, pa_data); 8640Sstevel@tonic-gate return; 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 868*7934SMark.Phalan@Sun.COM * Add authorization data returned from preauth modules to the ticket 869*7934SMark.Phalan@Sun.COM * It is assumed that ad is a "null-terminated" array of krb5_authdata ptrs 870*7934SMark.Phalan@Sun.COM */ 871*7934SMark.Phalan@Sun.COM static krb5_error_code 872*7934SMark.Phalan@Sun.COM add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad) 873*7934SMark.Phalan@Sun.COM { 874*7934SMark.Phalan@Sun.COM krb5_authdata **newad; 875*7934SMark.Phalan@Sun.COM int oldones, newones; 876*7934SMark.Phalan@Sun.COM int i; 877*7934SMark.Phalan@Sun.COM 878*7934SMark.Phalan@Sun.COM if (enc_tkt_part == NULL || ad == NULL) 879*7934SMark.Phalan@Sun.COM return EINVAL; 880*7934SMark.Phalan@Sun.COM 881*7934SMark.Phalan@Sun.COM for (newones = 0; ad[newones] != NULL; newones++); 882*7934SMark.Phalan@Sun.COM if (newones == 0) 883*7934SMark.Phalan@Sun.COM return 0; /* nothing to add */ 884*7934SMark.Phalan@Sun.COM 885*7934SMark.Phalan@Sun.COM if (enc_tkt_part->authorization_data == NULL) 886*7934SMark.Phalan@Sun.COM oldones = 0; 887*7934SMark.Phalan@Sun.COM else 888*7934SMark.Phalan@Sun.COM for (oldones = 0; 889*7934SMark.Phalan@Sun.COM enc_tkt_part->authorization_data[oldones] != NULL; oldones++); 890*7934SMark.Phalan@Sun.COM 891*7934SMark.Phalan@Sun.COM newad = malloc((oldones + newones + 1) * sizeof(krb5_authdata *)); 892*7934SMark.Phalan@Sun.COM if (newad == NULL) 893*7934SMark.Phalan@Sun.COM return ENOMEM; 894*7934SMark.Phalan@Sun.COM 895*7934SMark.Phalan@Sun.COM /* Copy any existing pointers */ 896*7934SMark.Phalan@Sun.COM for (i = 0; i < oldones; i++) 897*7934SMark.Phalan@Sun.COM newad[i] = enc_tkt_part->authorization_data[i]; 898*7934SMark.Phalan@Sun.COM 899*7934SMark.Phalan@Sun.COM /* Add the new ones */ 900*7934SMark.Phalan@Sun.COM for (i = 0; i < newones; i++) 901*7934SMark.Phalan@Sun.COM newad[oldones+i] = ad[i]; 902*7934SMark.Phalan@Sun.COM 903*7934SMark.Phalan@Sun.COM /* Terminate the new list */ 904*7934SMark.Phalan@Sun.COM newad[oldones+i] = NULL; 905*7934SMark.Phalan@Sun.COM 906*7934SMark.Phalan@Sun.COM /* Free any existing list */ 907*7934SMark.Phalan@Sun.COM if (enc_tkt_part->authorization_data != NULL) 908*7934SMark.Phalan@Sun.COM free(enc_tkt_part->authorization_data); 909*7934SMark.Phalan@Sun.COM 910*7934SMark.Phalan@Sun.COM /* Install our new list */ 911*7934SMark.Phalan@Sun.COM enc_tkt_part->authorization_data = newad; 912*7934SMark.Phalan@Sun.COM 913*7934SMark.Phalan@Sun.COM return 0; 914*7934SMark.Phalan@Sun.COM } 915*7934SMark.Phalan@Sun.COM 916*7934SMark.Phalan@Sun.COM /* 9170Sstevel@tonic-gate * This routine is called to verify the preauthentication information 9180Sstevel@tonic-gate * for a V5 request. 919*7934SMark.Phalan@Sun.COM * 9200Sstevel@tonic-gate * Returns 0 if the pre-authentication is valid, non-zero to indicate 9210Sstevel@tonic-gate * an error code of some sort. 9220Sstevel@tonic-gate */ 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate krb5_error_code 925*7934SMark.Phalan@Sun.COM check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt, 926*7934SMark.Phalan@Sun.COM krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, 927*7934SMark.Phalan@Sun.COM void **padata_context, krb5_data *e_data) 9280Sstevel@tonic-gate { 9290Sstevel@tonic-gate krb5_error_code retval = 0; 9300Sstevel@tonic-gate krb5_pa_data **padata; 9310Sstevel@tonic-gate krb5_preauth_systems *pa_sys; 932*7934SMark.Phalan@Sun.COM void **pa_context; 933*7934SMark.Phalan@Sun.COM krb5_data *pa_e_data = NULL, *tmp_e_data = NULL; 934*7934SMark.Phalan@Sun.COM int pa_ok = 0, pa_found = 0; 935*7934SMark.Phalan@Sun.COM krb5_error_code saved_retval = 0; 936*7934SMark.Phalan@Sun.COM int use_saved_retval = 0; 937*7934SMark.Phalan@Sun.COM const char *emsg; 938*7934SMark.Phalan@Sun.COM krb5_authdata **tmp_authz_data = NULL; 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate if (request->padata == 0) 9410Sstevel@tonic-gate return 0; 9420Sstevel@tonic-gate 943*7934SMark.Phalan@Sun.COM if (make_padata_context(context, padata_context) != 0) { 944*7934SMark.Phalan@Sun.COM return KRB5KRB_ERR_GENERIC; 945*7934SMark.Phalan@Sun.COM } 946*7934SMark.Phalan@Sun.COM 9470Sstevel@tonic-gate #ifdef DEBUG 9480Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, "checking padata"); 9490Sstevel@tonic-gate #endif 9500Sstevel@tonic-gate for (padata = request->padata; *padata; padata++) { 9510Sstevel@tonic-gate #ifdef DEBUG 9520Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*padata)->pa_type); 9530Sstevel@tonic-gate #endif 9540Sstevel@tonic-gate if (find_pa_system((*padata)->pa_type, &pa_sys)) 9550Sstevel@tonic-gate continue; 956*7934SMark.Phalan@Sun.COM if (find_pa_context(pa_sys, *padata_context, &pa_context)) 957*7934SMark.Phalan@Sun.COM continue; 9580Sstevel@tonic-gate #ifdef DEBUG 9590Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", pa_sys->name); 9600Sstevel@tonic-gate #endif 9610Sstevel@tonic-gate if (pa_sys->verify_padata == 0) 9620Sstevel@tonic-gate continue; 9630Sstevel@tonic-gate pa_found++; 964*7934SMark.Phalan@Sun.COM retval = pa_sys->verify_padata(context, client, req_pkt, request, 965*7934SMark.Phalan@Sun.COM enc_tkt_reply, *padata, 966*7934SMark.Phalan@Sun.COM get_entry_data, pa_sys->plugin_context, 967*7934SMark.Phalan@Sun.COM pa_context, &tmp_e_data, &tmp_authz_data); 9680Sstevel@tonic-gate if (retval) { 969*7934SMark.Phalan@Sun.COM emsg = krb5_get_error_message (context, retval); 9700Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO, "preauth (%s) verify failure: %s", 971*7934SMark.Phalan@Sun.COM pa_sys->name, emsg); 972*7934SMark.Phalan@Sun.COM krb5_free_error_message (context, emsg); 973*7934SMark.Phalan@Sun.COM /* Ignore authorization data returned from modules that fail */ 974*7934SMark.Phalan@Sun.COM if (tmp_authz_data != NULL) { 975*7934SMark.Phalan@Sun.COM krb5_free_authdata(context, tmp_authz_data); 976*7934SMark.Phalan@Sun.COM tmp_authz_data = NULL; 977*7934SMark.Phalan@Sun.COM } 9780Sstevel@tonic-gate if (pa_sys->flags & PA_REQUIRED) { 979*7934SMark.Phalan@Sun.COM /* free up any previous edata we might have been saving */ 980*7934SMark.Phalan@Sun.COM if (pa_e_data != NULL) 981*7934SMark.Phalan@Sun.COM krb5_free_data(context, pa_e_data); 982*7934SMark.Phalan@Sun.COM pa_e_data = tmp_e_data; 983*7934SMark.Phalan@Sun.COM tmp_e_data = NULL; 984*7934SMark.Phalan@Sun.COM use_saved_retval = 0; /* Make sure we use the current retval */ 9850Sstevel@tonic-gate pa_ok = 0; 9860Sstevel@tonic-gate break; 9870Sstevel@tonic-gate } 988*7934SMark.Phalan@Sun.COM /* 989*7934SMark.Phalan@Sun.COM * We'll return edata from either the first PA_REQUIRED module 990*7934SMark.Phalan@Sun.COM * that fails, or the first non-PA_REQUIRED module that fails. 991*7934SMark.Phalan@Sun.COM * Hang on to edata from the first non-PA_REQUIRED module. 992*7934SMark.Phalan@Sun.COM * If we've already got one saved, simply discard this one. 993*7934SMark.Phalan@Sun.COM */ 994*7934SMark.Phalan@Sun.COM if (tmp_e_data != NULL) { 995*7934SMark.Phalan@Sun.COM if (pa_e_data == NULL) { 996*7934SMark.Phalan@Sun.COM /* save the first error code and e-data */ 997*7934SMark.Phalan@Sun.COM pa_e_data = tmp_e_data; 998*7934SMark.Phalan@Sun.COM tmp_e_data = NULL; 999*7934SMark.Phalan@Sun.COM saved_retval = retval; 1000*7934SMark.Phalan@Sun.COM use_saved_retval = 1; 1001*7934SMark.Phalan@Sun.COM } else { 1002*7934SMark.Phalan@Sun.COM /* discard this extra e-data from non-PA_REQUIRED module */ 1003*7934SMark.Phalan@Sun.COM krb5_free_data(context, tmp_e_data); 1004*7934SMark.Phalan@Sun.COM tmp_e_data = NULL; 1005*7934SMark.Phalan@Sun.COM } 1006*7934SMark.Phalan@Sun.COM } 10070Sstevel@tonic-gate } else { 10080Sstevel@tonic-gate #ifdef DEBUG 10090Sstevel@tonic-gate krb5_klog_syslog (LOG_DEBUG, ".. .. ok"); 10100Sstevel@tonic-gate #endif 1011*7934SMark.Phalan@Sun.COM /* Ignore any edata returned on success */ 1012*7934SMark.Phalan@Sun.COM if (tmp_e_data != NULL) { 1013*7934SMark.Phalan@Sun.COM krb5_free_data(context, tmp_e_data); 1014*7934SMark.Phalan@Sun.COM tmp_e_data = NULL; 1015*7934SMark.Phalan@Sun.COM } 1016*7934SMark.Phalan@Sun.COM /* Add any authorization data to the ticket */ 1017*7934SMark.Phalan@Sun.COM if (tmp_authz_data != NULL) { 1018*7934SMark.Phalan@Sun.COM add_authorization_data(enc_tkt_reply, tmp_authz_data); 1019*7934SMark.Phalan@Sun.COM free(tmp_authz_data); 1020*7934SMark.Phalan@Sun.COM tmp_authz_data = NULL; 1021*7934SMark.Phalan@Sun.COM } 10220Sstevel@tonic-gate pa_ok = 1; 1023*7934SMark.Phalan@Sun.COM if (pa_sys->flags & PA_SUFFICIENT) 10240Sstevel@tonic-gate break; 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate } 1027*7934SMark.Phalan@Sun.COM 1028*7934SMark.Phalan@Sun.COM /* Don't bother copying and returning e-data on success */ 1029*7934SMark.Phalan@Sun.COM if (pa_ok && pa_e_data != NULL) { 1030*7934SMark.Phalan@Sun.COM krb5_free_data(context, pa_e_data); 1031*7934SMark.Phalan@Sun.COM pa_e_data = NULL; 1032*7934SMark.Phalan@Sun.COM } 1033*7934SMark.Phalan@Sun.COM /* Return any e-data from the preauth that caused us to exit the loop */ 1034*7934SMark.Phalan@Sun.COM if (pa_e_data != NULL) { 1035*7934SMark.Phalan@Sun.COM e_data->data = malloc(pa_e_data->length); 1036*7934SMark.Phalan@Sun.COM if (e_data->data == NULL) { 1037*7934SMark.Phalan@Sun.COM krb5_free_data(context, pa_e_data); 1038*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */ 1039*7934SMark.Phalan@Sun.COM return ENOMEM; 1040*7934SMark.Phalan@Sun.COM } 1041*7934SMark.Phalan@Sun.COM memcpy(e_data->data, pa_e_data->data, pa_e_data->length); 1042*7934SMark.Phalan@Sun.COM e_data->length = pa_e_data->length; 1043*7934SMark.Phalan@Sun.COM krb5_free_data(context, pa_e_data); 1044*7934SMark.Phalan@Sun.COM pa_e_data = NULL; 1045*7934SMark.Phalan@Sun.COM if (use_saved_retval != 0) 1046*7934SMark.Phalan@Sun.COM retval = saved_retval; 1047*7934SMark.Phalan@Sun.COM } 1048*7934SMark.Phalan@Sun.COM 10490Sstevel@tonic-gate if (pa_ok) 10500Sstevel@tonic-gate return 0; 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate /* pa system was not found, but principal doesn't require preauth */ 10530Sstevel@tonic-gate if (!pa_found && 1054*7934SMark.Phalan@Sun.COM !isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) && 1055*7934SMark.Phalan@Sun.COM !isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH)) 10560Sstevel@tonic-gate return 0; 10570Sstevel@tonic-gate 1058*7934SMark.Phalan@Sun.COM if (!pa_found) { 1059*7934SMark.Phalan@Sun.COM emsg = krb5_get_error_message(context, retval); 1060*7934SMark.Phalan@Sun.COM krb5_klog_syslog (LOG_INFO, "no valid preauth type found: %s", emsg); 1061*7934SMark.Phalan@Sun.COM krb5_free_error_message(context, emsg); 1062*7934SMark.Phalan@Sun.COM } 1063*7934SMark.Phalan@Sun.COM /* The following switch statement allows us 1064*7934SMark.Phalan@Sun.COM * to return some preauth system errors back to the client. 1065*7934SMark.Phalan@Sun.COM */ 1066*7934SMark.Phalan@Sun.COM switch(retval) { 1067*7934SMark.Phalan@Sun.COM case KRB5KRB_AP_ERR_BAD_INTEGRITY: 10682881Smp153739 case KRB5KRB_AP_ERR_SKEW: 1069*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_ETYPE_NOSUPP: 1070*7934SMark.Phalan@Sun.COM /* rfc 4556 */ 1071*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_CLIENT_NOT_TRUSTED: 1072*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_INVALID_SIG: 1073*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED: 1074*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE: 1075*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_INVALID_CERTIFICATE: 1076*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_REVOKED_CERTIFICATE: 1077*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN: 1078*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_CLIENT_NAME_MISMATCH: 1079*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE: 1080*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED: 1081*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED: 1082*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED: 1083*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED: 1084*7934SMark.Phalan@Sun.COM /* earlier drafts of what became rfc 4556 */ 1085*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_CERTIFICATE_MISMATCH: 1086*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_KDC_NOT_TRUSTED: 1087*7934SMark.Phalan@Sun.COM case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE: 1088*7934SMark.Phalan@Sun.COM /* This value is shared with KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */ 1089*7934SMark.Phalan@Sun.COM /* case KRB5KDC_ERR_KEY_TOO_WEAK: */ 10902881Smp153739 return retval; 10912881Smp153739 default: 10922881Smp153739 return KRB5KDC_ERR_PREAUTH_FAILED; 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate /* 10970Sstevel@tonic-gate * return_padata creates any necessary preauthentication 10980Sstevel@tonic-gate * structures which should be returned by the KDC to the client 10990Sstevel@tonic-gate */ 11000Sstevel@tonic-gate krb5_error_code 1101*7934SMark.Phalan@Sun.COM return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt, 11022881Smp153739 krb5_kdc_req *request, krb5_kdc_rep *reply, 1103*7934SMark.Phalan@Sun.COM krb5_key_data *client_key, krb5_keyblock *encrypting_key, 1104*7934SMark.Phalan@Sun.COM void **padata_context) 11050Sstevel@tonic-gate { 11060Sstevel@tonic-gate krb5_error_code retval; 11070Sstevel@tonic-gate krb5_pa_data ** padata; 11080Sstevel@tonic-gate krb5_pa_data ** send_pa_list; 11090Sstevel@tonic-gate krb5_pa_data ** send_pa; 11100Sstevel@tonic-gate krb5_pa_data * pa = 0; 11110Sstevel@tonic-gate krb5_preauth_systems * ap; 1112*7934SMark.Phalan@Sun.COM int * pa_order; 1113*7934SMark.Phalan@Sun.COM int * pa_type; 11140Sstevel@tonic-gate int size = 0; 1115*7934SMark.Phalan@Sun.COM void ** pa_context; 1116*7934SMark.Phalan@Sun.COM krb5_boolean key_modified; 1117*7934SMark.Phalan@Sun.COM krb5_keyblock original_key; 1118*7934SMark.Phalan@Sun.COM if ((!*padata_context)&& (make_padata_context(context, padata_context) != 0)) { 1119*7934SMark.Phalan@Sun.COM return KRB5KRB_ERR_GENERIC; 1120*7934SMark.Phalan@Sun.COM } 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate for (ap = preauth_systems; ap->type != -1; ap++) { 11230Sstevel@tonic-gate if (ap->return_padata) 11240Sstevel@tonic-gate size++; 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL) 11280Sstevel@tonic-gate return ENOMEM; 1129*7934SMark.Phalan@Sun.COM if ((pa_order = malloc((size+1) * sizeof(int))) == NULL) { 1130*7934SMark.Phalan@Sun.COM free(send_pa_list); 1131*7934SMark.Phalan@Sun.COM return ENOMEM; 1132*7934SMark.Phalan@Sun.COM } 1133*7934SMark.Phalan@Sun.COM sort_pa_order(context, request, pa_order); 1134*7934SMark.Phalan@Sun.COM 1135*7934SMark.Phalan@Sun.COM retval = krb5_copy_keyblock_contents(context, encrypting_key, 1136*7934SMark.Phalan@Sun.COM &original_key); 1137*7934SMark.Phalan@Sun.COM if (retval) { 1138*7934SMark.Phalan@Sun.COM free(send_pa_list); 1139*7934SMark.Phalan@Sun.COM free(pa_order); 1140*7934SMark.Phalan@Sun.COM return retval; 1141*7934SMark.Phalan@Sun.COM } 1142*7934SMark.Phalan@Sun.COM key_modified = FALSE; 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate send_pa = send_pa_list; 11450Sstevel@tonic-gate *send_pa = 0; 1146*7934SMark.Phalan@Sun.COM 1147*7934SMark.Phalan@Sun.COM for (pa_type = pa_order; *pa_type != -1; pa_type++) { 1148*7934SMark.Phalan@Sun.COM ap = &preauth_systems[*pa_type]; 1149*7934SMark.Phalan@Sun.COM if (!key_modified) 1150*7934SMark.Phalan@Sun.COM if (original_key.enctype != encrypting_key->enctype) 1151*7934SMark.Phalan@Sun.COM key_modified = TRUE; 1152*7934SMark.Phalan@Sun.COM if (!key_modified) 1153*7934SMark.Phalan@Sun.COM if (original_key.length != encrypting_key->length) 1154*7934SMark.Phalan@Sun.COM key_modified = TRUE; 1155*7934SMark.Phalan@Sun.COM if (!key_modified) 1156*7934SMark.Phalan@Sun.COM if (memcmp(original_key.contents, encrypting_key->contents, 1157*7934SMark.Phalan@Sun.COM original_key.length) != 0) 1158*7934SMark.Phalan@Sun.COM key_modified = TRUE; 1159*7934SMark.Phalan@Sun.COM if (key_modified && (ap->flags & PA_REPLACES_KEY)) 1160*7934SMark.Phalan@Sun.COM continue; 11610Sstevel@tonic-gate if (ap->return_padata == 0) 11620Sstevel@tonic-gate continue; 1163*7934SMark.Phalan@Sun.COM if (find_pa_context(ap, *padata_context, &pa_context)) 1164*7934SMark.Phalan@Sun.COM continue; 11650Sstevel@tonic-gate pa = 0; 11660Sstevel@tonic-gate if (request->padata) { 11670Sstevel@tonic-gate for (padata = request->padata; *padata; padata++) { 11680Sstevel@tonic-gate if ((*padata)->pa_type == ap->type) { 11690Sstevel@tonic-gate pa = *padata; 11700Sstevel@tonic-gate break; 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate } 1174*7934SMark.Phalan@Sun.COM if ((retval = ap->return_padata(context, pa, client, req_pkt, request, reply, 1175*7934SMark.Phalan@Sun.COM client_key, encrypting_key, send_pa, 1176*7934SMark.Phalan@Sun.COM get_entry_data, ap->plugin_context, 1177*7934SMark.Phalan@Sun.COM pa_context))) { 11780Sstevel@tonic-gate goto cleanup; 1179*7934SMark.Phalan@Sun.COM } 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate if (*send_pa) 11820Sstevel@tonic-gate send_pa++; 11830Sstevel@tonic-gate *send_pa = 0; 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate retval = 0; 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate if (send_pa_list[0]) { 11890Sstevel@tonic-gate reply->padata = send_pa_list; 11900Sstevel@tonic-gate send_pa_list = 0; 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate cleanup: 11940Sstevel@tonic-gate if (send_pa_list) 11950Sstevel@tonic-gate krb5_free_pa_data(context, send_pa_list); 1196*7934SMark.Phalan@Sun.COM 1197*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */ 1198*7934SMark.Phalan@Sun.COM krb5_free_keyblock_contents(context, &original_key); 1199*7934SMark.Phalan@Sun.COM free(pa_order); 1200*7934SMark.Phalan@Sun.COM 12010Sstevel@tonic-gate return (retval); 12020Sstevel@tonic-gate } 12032881Smp153739 12040Sstevel@tonic-gate static krb5_boolean 12050Sstevel@tonic-gate enctype_requires_etype_info_2(krb5_enctype enctype) 12060Sstevel@tonic-gate { 12070Sstevel@tonic-gate switch(enctype) { 12080Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC: 12090Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD4: 12100Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5: 12110Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA1: 12120Sstevel@tonic-gate case ENCTYPE_DES3_CBC_RAW: 12130Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC: 12140Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC_EXP : 12150Sstevel@tonic-gate return 0; 12160Sstevel@tonic-gate default: 12170Sstevel@tonic-gate if (krb5_c_valid_enctype(enctype)) 12182881Smp153739 return 1; 12190Sstevel@tonic-gate else return 0; 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate static krb5_boolean 12240Sstevel@tonic-gate request_contains_enctype (krb5_context context, const krb5_kdc_req *request, 12250Sstevel@tonic-gate krb5_enctype enctype) 12260Sstevel@tonic-gate { 12270Sstevel@tonic-gate int i; 12280Sstevel@tonic-gate for (i =0; i < request->nktypes; i++) 12290Sstevel@tonic-gate if (request->ktype[i] == enctype) 12300Sstevel@tonic-gate return 1; 12310Sstevel@tonic-gate return 0; 12320Sstevel@tonic-gate } 12330Sstevel@tonic-gate 12342881Smp153739 12350Sstevel@tonic-gate static krb5_error_code 12362881Smp153739 verify_enc_timestamp(krb5_context context, krb5_db_entry *client, 1237*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 12382881Smp153739 krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, 1239*7934SMark.Phalan@Sun.COM krb5_pa_data *pa, 1240*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc ets_get_entry_data, 1241*7934SMark.Phalan@Sun.COM void *pa_system_context, 1242*7934SMark.Phalan@Sun.COM void **pa_request_context, 1243*7934SMark.Phalan@Sun.COM krb5_data **e_data, 1244*7934SMark.Phalan@Sun.COM krb5_authdata ***authz_data) 12450Sstevel@tonic-gate { 12460Sstevel@tonic-gate krb5_pa_enc_ts * pa_enc = 0; 12470Sstevel@tonic-gate krb5_error_code retval; 12480Sstevel@tonic-gate krb5_data scratch; 12490Sstevel@tonic-gate krb5_data enc_ts_data; 12500Sstevel@tonic-gate krb5_enc_data *enc_data = 0; 12510Sstevel@tonic-gate krb5_keyblock key; 12520Sstevel@tonic-gate krb5_key_data * client_key; 12530Sstevel@tonic-gate krb5_int32 start; 12540Sstevel@tonic-gate krb5_timestamp timenow; 1255*7934SMark.Phalan@Sun.COM krb5_error_code decrypt_err = 0; 12562881Smp153739 12570Sstevel@tonic-gate (void) memset(&key, 0, sizeof(krb5_keyblock)); 12580Sstevel@tonic-gate scratch.data = (char *) pa->contents; 12590Sstevel@tonic-gate scratch.length = pa->length; 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate enc_ts_data.data = 0; 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0) 12640Sstevel@tonic-gate goto cleanup; 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate enc_ts_data.length = enc_data->ciphertext.length; 12670Sstevel@tonic-gate if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL) 12680Sstevel@tonic-gate goto cleanup; 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate start = 0; 12710Sstevel@tonic-gate decrypt_err = 0; 12720Sstevel@tonic-gate while (1) { 12730Sstevel@tonic-gate if ((retval = krb5_dbe_search_enctype(context, client, 12740Sstevel@tonic-gate &start, enc_data->enctype, 12750Sstevel@tonic-gate -1, 0, &client_key))) 12760Sstevel@tonic-gate goto cleanup; 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock, 12790Sstevel@tonic-gate client_key, &key, NULL))) 12800Sstevel@tonic-gate goto cleanup; 12810Sstevel@tonic-gate 12820Sstevel@tonic-gate key.enctype = enc_data->enctype; 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, 12850Sstevel@tonic-gate 0, enc_data, &enc_ts_data); 12860Sstevel@tonic-gate krb5_free_keyblock_contents(context, &key); 12870Sstevel@tonic-gate if (retval == 0) 12880Sstevel@tonic-gate break; 12890Sstevel@tonic-gate else 12900Sstevel@tonic-gate decrypt_err = retval; 12910Sstevel@tonic-gate } 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0) 12940Sstevel@tonic-gate goto cleanup; 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate if ((retval = krb5_timeofday(context, &timenow)) != 0) 12970Sstevel@tonic-gate goto cleanup; 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate if (labs(timenow - pa_enc->patimestamp) > context->clockskew) { 13000Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_SKEW; 13010Sstevel@tonic-gate goto cleanup; 13020Sstevel@tonic-gate } 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH); 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate retval = 0; 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate cleanup: 13090Sstevel@tonic-gate if (enc_data) { 13100Sstevel@tonic-gate krb5_free_data_contents(context, &enc_data->ciphertext); 13110Sstevel@tonic-gate free(enc_data); 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate krb5_free_data_contents(context, &enc_ts_data); 13140Sstevel@tonic-gate if (pa_enc) 13150Sstevel@tonic-gate free(pa_enc); 13160Sstevel@tonic-gate /* 13170Sstevel@tonic-gate * If we get NO_MATCHING_KEY and decryption previously failed, and 13180Sstevel@tonic-gate * we failed to find any other keys of the correct enctype after 13190Sstevel@tonic-gate * that failed decryption, it probably means that the password was 13200Sstevel@tonic-gate * incorrect. 13210Sstevel@tonic-gate */ 13220Sstevel@tonic-gate if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0) 13230Sstevel@tonic-gate retval = decrypt_err; 13240Sstevel@tonic-gate return retval; 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate static krb5_error_code 13280Sstevel@tonic-gate _make_etype_info_entry(krb5_context context, 13292881Smp153739 krb5_kdc_req *request, krb5_key_data *client_key, 13302881Smp153739 krb5_enctype etype, krb5_etype_info_entry **entry, 13312881Smp153739 int etype_info2) 13320Sstevel@tonic-gate { 13330Sstevel@tonic-gate krb5_data salt; 13340Sstevel@tonic-gate krb5_etype_info_entry * tmp_entry; 13350Sstevel@tonic-gate krb5_error_code retval; 13360Sstevel@tonic-gate 13370Sstevel@tonic-gate if ((tmp_entry = malloc(sizeof(krb5_etype_info_entry))) == NULL) 13380Sstevel@tonic-gate return ENOMEM; 13390Sstevel@tonic-gate 13400Sstevel@tonic-gate salt.data = 0; 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate tmp_entry->magic = KV5M_ETYPE_INFO_ENTRY; 13430Sstevel@tonic-gate tmp_entry->etype = etype; 13440Sstevel@tonic-gate tmp_entry->length = KRB5_ETYPE_NO_SALT; 13450Sstevel@tonic-gate tmp_entry->salt = 0; 13460Sstevel@tonic-gate tmp_entry->s2kparams.data = NULL; 13470Sstevel@tonic-gate tmp_entry->s2kparams.length = 0; 13480Sstevel@tonic-gate retval = get_salt_from_key(context, request->client, 13490Sstevel@tonic-gate client_key, &salt); 13500Sstevel@tonic-gate if (retval) 13510Sstevel@tonic-gate goto fail; 13520Sstevel@tonic-gate if (etype_info2 && client_key->key_data_ver > 1 && 13530Sstevel@tonic-gate client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) { 13540Sstevel@tonic-gate switch (etype) { 13550Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC: 13560Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD4: 13570Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5: 13582881Smp153739 tmp_entry->s2kparams.data = malloc(1); 13592881Smp153739 if (tmp_entry->s2kparams.data == NULL) { 13600Sstevel@tonic-gate retval = ENOMEM; 13610Sstevel@tonic-gate goto fail; 13622881Smp153739 } 13632881Smp153739 tmp_entry->s2kparams.length = 1; 13642881Smp153739 tmp_entry->s2kparams.data[0] = 1; 13652881Smp153739 break; 13660Sstevel@tonic-gate default: 13672881Smp153739 break; 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate if (salt.length >= 0) { 13720Sstevel@tonic-gate tmp_entry->length = salt.length; 13730Sstevel@tonic-gate tmp_entry->salt = (unsigned char *) salt.data; 13740Sstevel@tonic-gate salt.data = 0; 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate *entry = tmp_entry; 13770Sstevel@tonic-gate return 0; 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate fail: 13800Sstevel@tonic-gate if (tmp_entry) { 13810Sstevel@tonic-gate if (tmp_entry->s2kparams.data) 13822881Smp153739 free(tmp_entry->s2kparams.data); 13830Sstevel@tonic-gate free(tmp_entry); 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate if (salt.data) 13860Sstevel@tonic-gate free(salt.data); 13870Sstevel@tonic-gate return retval; 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate /* 13900Sstevel@tonic-gate * This function returns the etype information for a particular 13910Sstevel@tonic-gate * client, to be passed back in the preauth list in the KRB_ERROR 13920Sstevel@tonic-gate * message. It supports generating both etype_info and etype_info2 13932881Smp153739 * as most of the work is the same. 13940Sstevel@tonic-gate */ 13950Sstevel@tonic-gate static krb5_error_code 13960Sstevel@tonic-gate etype_info_helper(krb5_context context, krb5_kdc_req *request, 13972881Smp153739 krb5_db_entry *client, krb5_db_entry *server, 13982881Smp153739 krb5_pa_data *pa_data, int etype_info2) 13990Sstevel@tonic-gate { 14000Sstevel@tonic-gate krb5_etype_info_entry ** entry = 0; 14010Sstevel@tonic-gate krb5_key_data *client_key; 14020Sstevel@tonic-gate krb5_error_code retval; 14030Sstevel@tonic-gate krb5_data * scratch; 14040Sstevel@tonic-gate krb5_enctype db_etype; 14052881Smp153739 int i = 0; 14062881Smp153739 int start = 0; 14070Sstevel@tonic-gate int seen_des = 0; 14080Sstevel@tonic-gate 14092881Smp153739 entry = malloc((client->n_key_data * 2 + 1) * sizeof(krb5_etype_info_entry *)); 14100Sstevel@tonic-gate if (entry == NULL) 14110Sstevel@tonic-gate return ENOMEM; 14120Sstevel@tonic-gate entry[0] = NULL; 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate while (1) { 14150Sstevel@tonic-gate retval = krb5_dbe_search_enctype(context, client, &start, -1, 14162881Smp153739 -1, 0, &client_key); 14170Sstevel@tonic-gate if (retval == KRB5_KDB_NO_MATCHING_KEY) 14182881Smp153739 break; 14190Sstevel@tonic-gate if (retval) 14202881Smp153739 goto cleanup; 14210Sstevel@tonic-gate db_etype = client_key->key_data_type[0]; 14220Sstevel@tonic-gate if (db_etype == ENCTYPE_DES_CBC_MD4) 14232881Smp153739 db_etype = ENCTYPE_DES_CBC_MD5; 14242881Smp153739 14250Sstevel@tonic-gate if (request_contains_enctype(context, request, db_etype)) { 14262881Smp153739 assert(etype_info2 || 14272881Smp153739 !enctype_requires_etype_info_2(db_etype)); 14282881Smp153739 if ((retval = _make_etype_info_entry(context, request, client_key, 14292881Smp153739 db_etype, &entry[i], etype_info2)) != 0) { 14300Sstevel@tonic-gate goto cleanup; 14312881Smp153739 } 14322881Smp153739 entry[i+1] = 0; 14332881Smp153739 i++; 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate 14362881Smp153739 /* 14372881Smp153739 * If there is a des key in the kdb, try the "similar" enctypes, 14382881Smp153739 * avoid duplicate entries. 14390Sstevel@tonic-gate */ 14400Sstevel@tonic-gate if (!seen_des) { 14412881Smp153739 switch (db_etype) { 14422881Smp153739 case ENCTYPE_DES_CBC_MD5: 14430Sstevel@tonic-gate db_etype = ENCTYPE_DES_CBC_CRC; 14440Sstevel@tonic-gate break; 14452881Smp153739 case ENCTYPE_DES_CBC_CRC: 14460Sstevel@tonic-gate db_etype = ENCTYPE_DES_CBC_MD5; 14470Sstevel@tonic-gate break; 14482881Smp153739 default: 14490Sstevel@tonic-gate continue; 14500Sstevel@tonic-gate 14512881Smp153739 } 14522881Smp153739 if (request_contains_enctype(context, request, db_etype)) { 14530Sstevel@tonic-gate if ((retval = _make_etype_info_entry(context, request, 14542881Smp153739 client_key, db_etype, &entry[i], etype_info2)) != 0) { 14552881Smp153739 goto cleanup; 14560Sstevel@tonic-gate } 14572881Smp153739 entry[i+1] = 0; 14580Sstevel@tonic-gate i++; 14592881Smp153739 } 14602881Smp153739 seen_des++; 14610Sstevel@tonic-gate } 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate if (etype_info2) 14640Sstevel@tonic-gate retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, 14652881Smp153739 &scratch); 14662881Smp153739 else retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry, 14672881Smp153739 &scratch); 14680Sstevel@tonic-gate if (retval) 14690Sstevel@tonic-gate goto cleanup; 14700Sstevel@tonic-gate pa_data->contents = (unsigned char *)scratch->data; 14710Sstevel@tonic-gate pa_data->length = scratch->length; 14720Sstevel@tonic-gate free(scratch); 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate retval = 0; 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate cleanup: 14770Sstevel@tonic-gate if (entry) 14780Sstevel@tonic-gate krb5_free_etype_info(context, entry); 14790Sstevel@tonic-gate return retval; 14800Sstevel@tonic-gate } 14810Sstevel@tonic-gate 14820Sstevel@tonic-gate static krb5_error_code 14830Sstevel@tonic-gate get_etype_info(krb5_context context, krb5_kdc_req *request, 14842881Smp153739 krb5_db_entry *client, krb5_db_entry *server, 1485*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc etype_get_entry_data, 1486*7934SMark.Phalan@Sun.COM void *pa_system_context, 14872881Smp153739 krb5_pa_data *pa_data) 14880Sstevel@tonic-gate { 14890Sstevel@tonic-gate int i; 14900Sstevel@tonic-gate for (i=0; i < request->nktypes; i++) { 14912881Smp153739 if (enctype_requires_etype_info_2(request->ktype[i])) 14922881Smp153739 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will 14932881Smp153739 * skip this 14942881Smp153739 * type*/ 14950Sstevel@tonic-gate } 14960Sstevel@tonic-gate return etype_info_helper(context, request, client, server, pa_data, 0); 14970Sstevel@tonic-gate } 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate static krb5_error_code 15000Sstevel@tonic-gate get_etype_info2(krb5_context context, krb5_kdc_req *request, 15012881Smp153739 krb5_db_entry *client, krb5_db_entry *server, 1502*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc etype_get_entry_data, 1503*7934SMark.Phalan@Sun.COM void *pa_system_context, 15042881Smp153739 krb5_pa_data *pa_data) 15050Sstevel@tonic-gate { 15060Sstevel@tonic-gate return etype_info_helper( context, request, client, server, pa_data, 1); 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate static krb5_error_code 1510*7934SMark.Phalan@Sun.COM etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata, 1511*7934SMark.Phalan@Sun.COM krb5_db_entry *client, 1512*7934SMark.Phalan@Sun.COM krb5_kdc_req *request, krb5_kdc_rep *reply, 1513*7934SMark.Phalan@Sun.COM krb5_key_data *client_key, 1514*7934SMark.Phalan@Sun.COM krb5_keyblock *encrypting_key, 1515*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 1516*7934SMark.Phalan@Sun.COM int etype_info2) 15170Sstevel@tonic-gate { 1518*7934SMark.Phalan@Sun.COM int i; 15190Sstevel@tonic-gate krb5_error_code retval; 15200Sstevel@tonic-gate krb5_pa_data *tmp_padata; 15210Sstevel@tonic-gate krb5_etype_info_entry **entry = NULL; 15220Sstevel@tonic-gate krb5_data *scratch = NULL; 1523*7934SMark.Phalan@Sun.COM 1524*7934SMark.Phalan@Sun.COM /* 1525*7934SMark.Phalan@Sun.COM * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer" 1526*7934SMark.Phalan@Sun.COM * enctypes. 1527*7934SMark.Phalan@Sun.COM */ 1528*7934SMark.Phalan@Sun.COM if (!etype_info2) { 1529*7934SMark.Phalan@Sun.COM for (i = 0; i < request->nktypes; i++) { 1530*7934SMark.Phalan@Sun.COM if (enctype_requires_etype_info_2(request->ktype[i])) { 1531*7934SMark.Phalan@Sun.COM *send_pa = NULL; 1532*7934SMark.Phalan@Sun.COM return 0; 1533*7934SMark.Phalan@Sun.COM } 1534*7934SMark.Phalan@Sun.COM } 1535*7934SMark.Phalan@Sun.COM } 1536*7934SMark.Phalan@Sun.COM 15370Sstevel@tonic-gate tmp_padata = malloc( sizeof(krb5_pa_data)); 15380Sstevel@tonic-gate if (tmp_padata == NULL) 15390Sstevel@tonic-gate return ENOMEM; 1540*7934SMark.Phalan@Sun.COM if (etype_info2) 1541*7934SMark.Phalan@Sun.COM tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2; 1542*7934SMark.Phalan@Sun.COM else 1543*7934SMark.Phalan@Sun.COM tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO; 1544*7934SMark.Phalan@Sun.COM 15450Sstevel@tonic-gate entry = malloc(2 * sizeof(krb5_etype_info_entry *)); 15460Sstevel@tonic-gate if (entry == NULL) { 15470Sstevel@tonic-gate retval = ENOMEM; 15480Sstevel@tonic-gate goto cleanup; 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate entry[0] = NULL; 15510Sstevel@tonic-gate entry[1] = NULL; 1552*7934SMark.Phalan@Sun.COM retval = _make_etype_info_entry(context, request, 1553*7934SMark.Phalan@Sun.COM client_key, encrypting_key->enctype, 1554*7934SMark.Phalan@Sun.COM entry, etype_info2); 15550Sstevel@tonic-gate if (retval) 15560Sstevel@tonic-gate goto cleanup; 1557*7934SMark.Phalan@Sun.COM 1558*7934SMark.Phalan@Sun.COM if (etype_info2) 1559*7934SMark.Phalan@Sun.COM retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, &scratch); 1560*7934SMark.Phalan@Sun.COM else 1561*7934SMark.Phalan@Sun.COM retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry, &scratch); 1562*7934SMark.Phalan@Sun.COM 15630Sstevel@tonic-gate if (retval) 15640Sstevel@tonic-gate goto cleanup; 15650Sstevel@tonic-gate tmp_padata->contents = (uchar_t *)scratch->data; 15660Sstevel@tonic-gate tmp_padata->length = scratch->length; 15670Sstevel@tonic-gate *send_pa = tmp_padata; 15680Sstevel@tonic-gate 15692881Smp153739 /* For cleanup - we no longer own the contents of the krb5_data 15700Sstevel@tonic-gate * only to pointer to the krb5_data 15710Sstevel@tonic-gate */ 15722881Smp153739 scratch->data = 0; 15730Sstevel@tonic-gate 15740Sstevel@tonic-gate cleanup: 15750Sstevel@tonic-gate if (entry) 15760Sstevel@tonic-gate krb5_free_etype_info(context, entry); 15770Sstevel@tonic-gate if (retval) { 15780Sstevel@tonic-gate if (tmp_padata) 15792881Smp153739 free(tmp_padata); 15800Sstevel@tonic-gate } 15810Sstevel@tonic-gate if (scratch) 15822881Smp153739 krb5_free_data(context, scratch); 15830Sstevel@tonic-gate return retval; 15840Sstevel@tonic-gate } 15850Sstevel@tonic-gate 1586*7934SMark.Phalan@Sun.COM static krb5_error_code 1587*7934SMark.Phalan@Sun.COM return_etype_info2(krb5_context context, krb5_pa_data * padata, 1588*7934SMark.Phalan@Sun.COM krb5_db_entry *client, 1589*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 1590*7934SMark.Phalan@Sun.COM krb5_kdc_req *request, krb5_kdc_rep *reply, 1591*7934SMark.Phalan@Sun.COM krb5_key_data *client_key, 1592*7934SMark.Phalan@Sun.COM krb5_keyblock *encrypting_key, 1593*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 1594*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc etype_get_entry_data, 1595*7934SMark.Phalan@Sun.COM void *pa_system_context, 1596*7934SMark.Phalan@Sun.COM void **pa_request_context) 1597*7934SMark.Phalan@Sun.COM { 1598*7934SMark.Phalan@Sun.COM return etype_info_as_rep_helper(context, padata, client, request, reply, 1599*7934SMark.Phalan@Sun.COM client_key, encrypting_key, send_pa, 1); 1600*7934SMark.Phalan@Sun.COM } 1601*7934SMark.Phalan@Sun.COM 1602*7934SMark.Phalan@Sun.COM 1603*7934SMark.Phalan@Sun.COM static krb5_error_code 1604*7934SMark.Phalan@Sun.COM return_etype_info(krb5_context context, krb5_pa_data * padata, 1605*7934SMark.Phalan@Sun.COM krb5_db_entry *client, 1606*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 1607*7934SMark.Phalan@Sun.COM krb5_kdc_req *request, krb5_kdc_rep *reply, 1608*7934SMark.Phalan@Sun.COM krb5_key_data *client_key, 1609*7934SMark.Phalan@Sun.COM krb5_keyblock *encrypting_key, 1610*7934SMark.Phalan@Sun.COM krb5_pa_data **send_pa, 1611*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc etypeget_entry_data, 1612*7934SMark.Phalan@Sun.COM void *pa_system_context, 1613*7934SMark.Phalan@Sun.COM void **pa_request_context) 1614*7934SMark.Phalan@Sun.COM { 1615*7934SMark.Phalan@Sun.COM return etype_info_as_rep_helper(context, padata, client, request, reply, 1616*7934SMark.Phalan@Sun.COM client_key, encrypting_key, send_pa, 0); 1617*7934SMark.Phalan@Sun.COM } 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate static krb5_error_code 16202881Smp153739 return_pw_salt(krb5_context context, krb5_pa_data *in_padata, 1621*7934SMark.Phalan@Sun.COM krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request, 16222881Smp153739 krb5_kdc_rep *reply, krb5_key_data *client_key, 1623*7934SMark.Phalan@Sun.COM krb5_keyblock *encrypting_key, krb5_pa_data **send_pa, 1624*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc etype_get_entry_data, 1625*7934SMark.Phalan@Sun.COM void *pa_system_context, 1626*7934SMark.Phalan@Sun.COM void **pa_request_context) 16270Sstevel@tonic-gate { 16280Sstevel@tonic-gate krb5_error_code retval; 16290Sstevel@tonic-gate krb5_pa_data * padata; 16300Sstevel@tonic-gate krb5_data * scratch; 16310Sstevel@tonic-gate krb5_data salt_data; 16320Sstevel@tonic-gate int i; 16332881Smp153739 16340Sstevel@tonic-gate for (i = 0; i < request->nktypes; i++) { 16350Sstevel@tonic-gate if (enctype_requires_etype_info_2(request->ktype[i])) 16362881Smp153739 return 0; 16370Sstevel@tonic-gate } 16380Sstevel@tonic-gate if (client_key->key_data_ver == 1 || 16390Sstevel@tonic-gate client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL) 16400Sstevel@tonic-gate return 0; 16410Sstevel@tonic-gate 16420Sstevel@tonic-gate if ((padata = malloc(sizeof(krb5_pa_data))) == NULL) 16430Sstevel@tonic-gate return ENOMEM; 16440Sstevel@tonic-gate padata->magic = KV5M_PA_DATA; 16450Sstevel@tonic-gate padata->pa_type = KRB5_PADATA_PW_SALT; 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate switch (client_key->key_data_type[1]) { 16480Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_V4: 16490Sstevel@tonic-gate /* send an empty (V4) salt */ 16500Sstevel@tonic-gate padata->contents = 0; 16510Sstevel@tonic-gate padata->length = 0; 16520Sstevel@tonic-gate break; 16530Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_NOREALM: 16540Sstevel@tonic-gate if ((retval = krb5_principal2salt_norealm(kdc_context, 16550Sstevel@tonic-gate request->client, 16560Sstevel@tonic-gate &salt_data))) 16570Sstevel@tonic-gate goto cleanup; 16580Sstevel@tonic-gate padata->contents = (krb5_octet *)salt_data.data; 16590Sstevel@tonic-gate padata->length = salt_data.length; 16600Sstevel@tonic-gate break; 16610Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_AFS3: 16620Sstevel@tonic-gate /* send an AFS style realm-based salt */ 16630Sstevel@tonic-gate /* for now, just pass the realm back and let the client 16640Sstevel@tonic-gate do the work. In the future, add a kdc configuration 16650Sstevel@tonic-gate variable that specifies the old cell name. */ 16660Sstevel@tonic-gate padata->pa_type = KRB5_PADATA_AFS3_SALT; 16670Sstevel@tonic-gate /* it would be just like ONLYREALM, but we need to pass the 0 */ 16680Sstevel@tonic-gate scratch = krb5_princ_realm(kdc_context, request->client); 16690Sstevel@tonic-gate if ((padata->contents = malloc(scratch->length+1)) == NULL) { 16700Sstevel@tonic-gate retval = ENOMEM; 16710Sstevel@tonic-gate goto cleanup; 16720Sstevel@tonic-gate } 16730Sstevel@tonic-gate memcpy(padata->contents, scratch->data, scratch->length); 16740Sstevel@tonic-gate padata->length = scratch->length+1; 16750Sstevel@tonic-gate padata->contents[scratch->length] = 0; 16760Sstevel@tonic-gate break; 16770Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_ONLYREALM: 16780Sstevel@tonic-gate scratch = krb5_princ_realm(kdc_context, request->client); 16790Sstevel@tonic-gate if ((padata->contents = malloc(scratch->length)) == NULL) { 16800Sstevel@tonic-gate retval = ENOMEM; 16810Sstevel@tonic-gate goto cleanup; 16820Sstevel@tonic-gate } 16830Sstevel@tonic-gate memcpy(padata->contents, scratch->data, scratch->length); 16840Sstevel@tonic-gate padata->length = scratch->length; 16850Sstevel@tonic-gate break; 16860Sstevel@tonic-gate case KRB5_KDB_SALTTYPE_SPECIAL: 16870Sstevel@tonic-gate if ((padata->contents = malloc(client_key->key_data_length[1])) 16880Sstevel@tonic-gate == NULL) { 16890Sstevel@tonic-gate retval = ENOMEM; 16900Sstevel@tonic-gate goto cleanup; 16910Sstevel@tonic-gate } 16920Sstevel@tonic-gate memcpy(padata->contents, client_key->key_data_contents[1], 16930Sstevel@tonic-gate client_key->key_data_length[1]); 16940Sstevel@tonic-gate padata->length = client_key->key_data_length[1]; 16950Sstevel@tonic-gate break; 16960Sstevel@tonic-gate default: 16970Sstevel@tonic-gate free(padata); 16980Sstevel@tonic-gate return 0; 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate *send_pa = padata; 17020Sstevel@tonic-gate return 0; 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate cleanup: 17050Sstevel@tonic-gate free(padata); 17060Sstevel@tonic-gate return retval; 17070Sstevel@tonic-gate } 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate static krb5_error_code 17102881Smp153739 return_sam_data(krb5_context context, krb5_pa_data *in_padata, 1711*7934SMark.Phalan@Sun.COM krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request, 17122881Smp153739 krb5_kdc_rep *reply, krb5_key_data *client_key, 1713*7934SMark.Phalan@Sun.COM krb5_keyblock *encrypting_key, krb5_pa_data **send_pa, 1714*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc sam_get_entry_data, 1715*7934SMark.Phalan@Sun.COM void *pa_system_context, 1716*7934SMark.Phalan@Sun.COM void **pa_request_context) 17170Sstevel@tonic-gate { 17180Sstevel@tonic-gate krb5_error_code retval; 17190Sstevel@tonic-gate krb5_data scratch; 17200Sstevel@tonic-gate int i; 17210Sstevel@tonic-gate 17220Sstevel@tonic-gate krb5_sam_response *sr = 0; 17230Sstevel@tonic-gate krb5_predicted_sam_response *psr = 0; 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate if (in_padata == 0) 17260Sstevel@tonic-gate return 0; 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate /* 17290Sstevel@tonic-gate * We start by doing the same thing verify_sam_response() does: 17300Sstevel@tonic-gate * extract the psr from the padata (which is an sr). Nothing 17310Sstevel@tonic-gate * here should generate errors! We've already successfully done 17320Sstevel@tonic-gate * all this once. 17330Sstevel@tonic-gate */ 17340Sstevel@tonic-gate 17350Sstevel@tonic-gate scratch.data = (char *) in_padata->contents; /* SUNWresync121 XXX */ 17360Sstevel@tonic-gate scratch.length = in_padata->length; 17370Sstevel@tonic-gate 17380Sstevel@tonic-gate if ((retval = decode_krb5_sam_response(&scratch, &sr))) { 17390Sstevel@tonic-gate com_err("krb5kdc", retval, 17400Sstevel@tonic-gate gettext("return_sam_data(): decode_krb5_sam_response failed")); 17410Sstevel@tonic-gate goto cleanup; 17420Sstevel@tonic-gate } 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate { 17450Sstevel@tonic-gate krb5_enc_data tmpdata; 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate tmpdata.enctype = ENCTYPE_UNKNOWN; 17480Sstevel@tonic-gate tmpdata.ciphertext = sr->sam_track_id; 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate scratch.length = tmpdata.ciphertext.length; 17510Sstevel@tonic-gate if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 17520Sstevel@tonic-gate retval = ENOMEM; 17530Sstevel@tonic-gate goto cleanup; 17540Sstevel@tonic-gate } 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0, 17570Sstevel@tonic-gate &tmpdata, &scratch))) { 17580Sstevel@tonic-gate com_err("krb5kdc", retval, 17590Sstevel@tonic-gate gettext("return_sam_data(): decrypt track_id failed")); 17600Sstevel@tonic-gate free(scratch.data); 17610Sstevel@tonic-gate goto cleanup; 17620Sstevel@tonic-gate } 17630Sstevel@tonic-gate } 17640Sstevel@tonic-gate 17650Sstevel@tonic-gate if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) { 17660Sstevel@tonic-gate com_err("krb5kdc", retval, 17670Sstevel@tonic-gate gettext( 17680Sstevel@tonic-gate "return_sam_data(): decode_krb5_predicted_sam_response failed")); 17690Sstevel@tonic-gate free(scratch.data); 17700Sstevel@tonic-gate goto cleanup; 17710Sstevel@tonic-gate } 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate /* We could use sr->sam_flags, but it may be absent or altered. */ 17740Sstevel@tonic-gate if (psr->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) { 17750Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 17760Sstevel@tonic-gate gettext("Unsupported SAM flag must-pk-encrypt-sad")); 17770Sstevel@tonic-gate goto cleanup; 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate if (psr->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) { 17800Sstevel@tonic-gate /* No key munging */ 17810Sstevel@tonic-gate goto cleanup; 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate if (psr->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) { 17840Sstevel@tonic-gate /* Use sam_key instead of client key */ 17850Sstevel@tonic-gate krb5_free_keyblock_contents(context, encrypting_key); 17860Sstevel@tonic-gate krb5_copy_keyblock_contents(context, &psr->sam_key, encrypting_key); 17870Sstevel@tonic-gate /* XXX Attach a useful pa_data */ 17880Sstevel@tonic-gate goto cleanup; 17890Sstevel@tonic-gate } 17900Sstevel@tonic-gate 17910Sstevel@tonic-gate /* Otherwise (no flags set), we XOR the keys */ 17920Sstevel@tonic-gate /* XXX The passwords-04 draft is underspecified here wrt different 17930Sstevel@tonic-gate key types. We will do what I hope to get into the -05 draft. */ 17940Sstevel@tonic-gate { 17950Sstevel@tonic-gate krb5_octet *p = encrypting_key->contents; 17960Sstevel@tonic-gate krb5_octet *q = psr->sam_key.contents; 17970Sstevel@tonic-gate int length = ((encrypting_key->length < psr->sam_key.length) 17980Sstevel@tonic-gate ? encrypting_key->length 17990Sstevel@tonic-gate : psr->sam_key.length); 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate for (i = 0; i < length; i++) 18020Sstevel@tonic-gate p[i] ^= q[i]; 18030Sstevel@tonic-gate } 18040Sstevel@tonic-gate 18050Sstevel@tonic-gate /* Post-mixing key correction */ 18060Sstevel@tonic-gate switch (encrypting_key->enctype) { 18070Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC: 18080Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD4: 18090Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5: 18100Sstevel@tonic-gate case ENCTYPE_DES_CBC_RAW: 18110Sstevel@tonic-gate mit_des_fixup_key_parity(encrypting_key->contents); 18120Sstevel@tonic-gate if (mit_des_is_weak_key(encrypting_key->contents)) 18130Sstevel@tonic-gate ((krb5_octet *) encrypting_key->contents)[7] ^= 0xf0; 18140Sstevel@tonic-gate break; 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */ 18170Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA: /* XXX deprecated? */ 18180Sstevel@tonic-gate case ENCTYPE_DES3_CBC_RAW: 18190Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA1: 18200Sstevel@tonic-gate for (i = 0; i < 3; i++) { 18210Sstevel@tonic-gate mit_des_fixup_key_parity(encrypting_key->contents + i * 8); 18220Sstevel@tonic-gate if (mit_des_is_weak_key(encrypting_key->contents + i * 8)) 18230Sstevel@tonic-gate ((krb5_octet *) encrypting_key->contents)[7 + i * 8] ^= 0xf0; 18240Sstevel@tonic-gate } 18250Sstevel@tonic-gate break; 18260Sstevel@tonic-gate 18270Sstevel@tonic-gate default: 18280Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 18290Sstevel@tonic-gate gettext("Unimplemented keytype for SAM key mixing")); 18300Sstevel@tonic-gate goto cleanup; 18310Sstevel@tonic-gate } 18320Sstevel@tonic-gate 18330Sstevel@tonic-gate /* XXX Attach a useful pa_data */ 18340Sstevel@tonic-gate cleanup: 18350Sstevel@tonic-gate if (sr) 18360Sstevel@tonic-gate krb5_free_sam_response(context, sr); 18370Sstevel@tonic-gate if (psr) 18380Sstevel@tonic-gate krb5_free_predicted_sam_response(context, psr); 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate return retval; 18410Sstevel@tonic-gate } 18420Sstevel@tonic-gate 18430Sstevel@tonic-gate static struct { 18440Sstevel@tonic-gate char* name; 18450Sstevel@tonic-gate int sam_type; 18460Sstevel@tonic-gate } *sam_ptr, sam_inst_map[] = { 18470Sstevel@tonic-gate #if 0 /* SUNWresync121 - unsupported hardware and kdc.log annoyance */ 18480Sstevel@tonic-gate { "SNK4", PA_SAM_TYPE_DIGI_PATH, }, 18490Sstevel@tonic-gate { "SECURID", PA_SAM_TYPE_SECURID, }, 18500Sstevel@tonic-gate { "GRAIL", PA_SAM_TYPE_GRAIL, }, 18510Sstevel@tonic-gate #endif 18520Sstevel@tonic-gate { 0, 0 }, 18530Sstevel@tonic-gate }; 18540Sstevel@tonic-gate 18550Sstevel@tonic-gate static krb5_error_code 18562881Smp153739 get_sam_edata(krb5_context context, krb5_kdc_req *request, 18572881Smp153739 krb5_db_entry *client, krb5_db_entry *server, 1858*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc sam_get_entry_data, 1859*7934SMark.Phalan@Sun.COM void *pa_system_context, krb5_pa_data *pa_data) 18600Sstevel@tonic-gate { 18610Sstevel@tonic-gate krb5_error_code retval; 18620Sstevel@tonic-gate krb5_sam_challenge sc; 18630Sstevel@tonic-gate krb5_predicted_sam_response psr; 18640Sstevel@tonic-gate krb5_data * scratch; 18650Sstevel@tonic-gate krb5_keyblock encrypting_key; 18660Sstevel@tonic-gate char response[9]; 18670Sstevel@tonic-gate char inputblock[8]; 18680Sstevel@tonic-gate krb5_data predict_response; 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate (void) memset(&encrypting_key, 0, sizeof(krb5_keyblock)); 18710Sstevel@tonic-gate (void) memset(&sc, 0, sizeof(sc)); 18720Sstevel@tonic-gate (void) memset(&psr, 0, sizeof(psr)); 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate /* Given the client name we can figure out what type of preauth 18750Sstevel@tonic-gate they need. The spec is currently for querying the database for 18760Sstevel@tonic-gate names that match the types of preauth used. Later we should 18770Sstevel@tonic-gate make this mapping show up in kdc.conf. In the meantime, we 18780Sstevel@tonic-gate hardcode the following: 18790Sstevel@tonic-gate /SNK4 -- Digital Pathways SNK/4 preauth. 18800Sstevel@tonic-gate /GRAIL -- experimental preauth 18810Sstevel@tonic-gate The first one found is used. See sam_inst_map above. 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate For SNK4 in particular, the key in the database is the key for 18840Sstevel@tonic-gate the device; kadmin needs a special interface for it. 18850Sstevel@tonic-gate */ 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate { 18882881Smp153739 int npr = 1; 18892881Smp153739 krb5_boolean more; 18900Sstevel@tonic-gate krb5_db_entry assoc; 18910Sstevel@tonic-gate krb5_key_data *assoc_key; 18920Sstevel@tonic-gate krb5_principal newp; 18930Sstevel@tonic-gate int probeslot; 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate sc.sam_type = 0; 18960Sstevel@tonic-gate 18970Sstevel@tonic-gate retval = krb5_copy_principal(kdc_context, request->client, &newp); 18980Sstevel@tonic-gate if (retval) { 18990Sstevel@tonic-gate com_err(gettext("krb5kdc"), 19000Sstevel@tonic-gate retval, 19010Sstevel@tonic-gate gettext("copying client name for preauth probe")); 19020Sstevel@tonic-gate return retval; 19030Sstevel@tonic-gate } 19040Sstevel@tonic-gate 19050Sstevel@tonic-gate probeslot = krb5_princ_size(context, newp)++; 19060Sstevel@tonic-gate krb5_princ_name(kdc_context, newp) = 19070Sstevel@tonic-gate realloc(krb5_princ_name(kdc_context, newp), 19080Sstevel@tonic-gate krb5_princ_size(context, newp) * sizeof(krb5_data)); 19090Sstevel@tonic-gate 19100Sstevel@tonic-gate for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) { 19110Sstevel@tonic-gate krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name; 19120Sstevel@tonic-gate krb5_princ_component(kdc_context,newp,probeslot)->length = 19130Sstevel@tonic-gate strlen(sam_ptr->name); 19140Sstevel@tonic-gate npr = 1; 19150Sstevel@tonic-gate retval = krb5_db_get_principal(kdc_context, newp, &assoc, &npr, (uint *)&more); 19162881Smp153739 if(!retval && npr) { 19170Sstevel@tonic-gate sc.sam_type = sam_ptr->sam_type; 19180Sstevel@tonic-gate break; 19190Sstevel@tonic-gate } 19200Sstevel@tonic-gate } 19210Sstevel@tonic-gate 19220Sstevel@tonic-gate krb5_princ_component(kdc_context,newp,probeslot)->data = 0; 19230Sstevel@tonic-gate krb5_princ_component(kdc_context,newp,probeslot)->length = 0; 19240Sstevel@tonic-gate krb5_princ_size(context, newp)--; 19250Sstevel@tonic-gate 19260Sstevel@tonic-gate krb5_free_principal(kdc_context, newp); 19270Sstevel@tonic-gate 19280Sstevel@tonic-gate /* if sc.sam_type is set, it worked */ 19290Sstevel@tonic-gate if (sc.sam_type) { 19300Sstevel@tonic-gate /* so use assoc to get the key out! */ 19310Sstevel@tonic-gate { 19320Sstevel@tonic-gate /* here's what do_tgs_req does */ 19330Sstevel@tonic-gate retval = krb5_dbe_find_enctype(kdc_context, &assoc, 19340Sstevel@tonic-gate ENCTYPE_DES_CBC_RAW, 19350Sstevel@tonic-gate KRB5_KDB_SALTTYPE_NORMAL, 19360Sstevel@tonic-gate 0, /* Get highest kvno */ 19370Sstevel@tonic-gate &assoc_key); 19380Sstevel@tonic-gate if (retval) { 19390Sstevel@tonic-gate char *sname; 19400Sstevel@tonic-gate krb5_unparse_name(kdc_context, request->client, &sname); 19410Sstevel@tonic-gate com_err(gettext("krb5kdc"), 19420Sstevel@tonic-gate retval, 19430Sstevel@tonic-gate gettext("snk4 finding the enctype and key <%s>"), 19440Sstevel@tonic-gate sname); 19450Sstevel@tonic-gate free(sname); 19460Sstevel@tonic-gate return retval; 19470Sstevel@tonic-gate } 19480Sstevel@tonic-gate /* convert server.key into a real key */ 19490Sstevel@tonic-gate retval = krb5_dbekd_decrypt_key_data(kdc_context, 19500Sstevel@tonic-gate &master_keyblock, 19510Sstevel@tonic-gate assoc_key, &encrypting_key, 19520Sstevel@tonic-gate NULL); 19530Sstevel@tonic-gate if (retval) { 19540Sstevel@tonic-gate com_err(gettext("krb5kdc"), 19550Sstevel@tonic-gate retval, 19560Sstevel@tonic-gate gettext("snk4 pulling out key entry")); 19570Sstevel@tonic-gate return retval; 19580Sstevel@tonic-gate } 19590Sstevel@tonic-gate /* now we can use encrypting_key... */ 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate } else { 19620Sstevel@tonic-gate /* SAM is not an option - so don't return as hint */ 19630Sstevel@tonic-gate return KRB5_PREAUTH_BAD_TYPE; 19640Sstevel@tonic-gate } 19650Sstevel@tonic-gate } 19660Sstevel@tonic-gate sc.magic = KV5M_SAM_CHALLENGE; 19670Sstevel@tonic-gate psr.sam_flags = sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY; 19680Sstevel@tonic-gate 19690Sstevel@tonic-gate /* Replay prevention */ 19700Sstevel@tonic-gate if ((retval = krb5_copy_principal(context, request->client, &psr.client))) 19710Sstevel@tonic-gate return retval; 19720Sstevel@tonic-gate #ifdef USE_RCACHE 19730Sstevel@tonic-gate if ((retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))) 19740Sstevel@tonic-gate return retval; 19750Sstevel@tonic-gate #endif /* USE_RCACHE */ 19760Sstevel@tonic-gate 19770Sstevel@tonic-gate switch (sc.sam_type) { 19780Sstevel@tonic-gate case PA_SAM_TYPE_GRAIL: 19790Sstevel@tonic-gate sc.sam_type_name.data = "Experimental System"; 19800Sstevel@tonic-gate sc.sam_type_name.length = strlen(sc.sam_type_name.data); 19810Sstevel@tonic-gate sc.sam_challenge_label.data = "experimental challenge label"; 19820Sstevel@tonic-gate sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 19830Sstevel@tonic-gate sc.sam_challenge.data = "12345"; 19840Sstevel@tonic-gate sc.sam_challenge.length = strlen(sc.sam_challenge.data); 19850Sstevel@tonic-gate 19860Sstevel@tonic-gate #if 0 /* Enable this to test "normal" (no flags set) mode. */ 19870Sstevel@tonic-gate psr.sam_flags = sc.sam_flags = 0; 19880Sstevel@tonic-gate #endif 19890Sstevel@tonic-gate 19900Sstevel@tonic-gate psr.magic = KV5M_PREDICTED_SAM_RESPONSE; 19910Sstevel@tonic-gate /* string2key on sc.sam_challenge goes in here */ 19920Sstevel@tonic-gate /* eblock is just to set the enctype */ 19930Sstevel@tonic-gate { 19940Sstevel@tonic-gate const krb5_enctype type = ENCTYPE_DES_CBC_MD5; 19950Sstevel@tonic-gate 19960Sstevel@tonic-gate if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge, 19970Sstevel@tonic-gate 0 /* salt */, &psr.sam_key))) 19980Sstevel@tonic-gate goto cleanup; 19990Sstevel@tonic-gate 20000Sstevel@tonic-gate if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch))) 20010Sstevel@tonic-gate goto cleanup; 20020Sstevel@tonic-gate 20030Sstevel@tonic-gate { 20040Sstevel@tonic-gate size_t enclen; 20050Sstevel@tonic-gate krb5_enc_data tmpdata; 20060Sstevel@tonic-gate 20070Sstevel@tonic-gate if ((retval = krb5_c_encrypt_length(context, 20080Sstevel@tonic-gate psr_key.enctype, 20090Sstevel@tonic-gate scratch->length, &enclen))) 20100Sstevel@tonic-gate goto cleanup; 20110Sstevel@tonic-gate 20120Sstevel@tonic-gate if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) { 20130Sstevel@tonic-gate retval = ENOMEM; 20140Sstevel@tonic-gate goto cleanup; 20150Sstevel@tonic-gate } 20160Sstevel@tonic-gate tmpdata.ciphertext.length = enclen; 20170Sstevel@tonic-gate 20180Sstevel@tonic-gate if ((retval = krb5_c_encrypt(context, &psr_key, 20190Sstevel@tonic-gate /* XXX */ 0, 0, scratch, &tmpdata))) 20200Sstevel@tonic-gate goto cleanup; 20210Sstevel@tonic-gate 20220Sstevel@tonic-gate sc.sam_track_id = tmpdata.ciphertext; 20230Sstevel@tonic-gate } 20240Sstevel@tonic-gate } 20250Sstevel@tonic-gate 20260Sstevel@tonic-gate sc.sam_response_prompt.data = "response prompt"; 20270Sstevel@tonic-gate sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data); 20280Sstevel@tonic-gate sc.sam_pk_for_sad.length = 0; 20290Sstevel@tonic-gate sc.sam_nonce = 0; 20300Sstevel@tonic-gate /* Generate checksum */ 20310Sstevel@tonic-gate /*krb5_checksum_size(context, ctype)*/ 20320Sstevel@tonic-gate /*krb5_calculate_checksum(context,ctype,in,in_length,seed, 20330Sstevel@tonic-gate seed_length,outcksum) */ 20340Sstevel@tonic-gate /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed, 20350Sstevel@tonic-gate seed_length) */ 20360Sstevel@tonic-gate #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */ 20370Sstevel@tonic-gate sc.sam_cksum.contents = (krb5_octet *) 20380Sstevel@tonic-gate malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES)); 20390Sstevel@tonic-gate if (sc.sam_cksum.contents == NULL) return(ENOMEM); 20400Sstevel@tonic-gate 20410Sstevel@tonic-gate retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES, 20420Sstevel@tonic-gate sc.sam_challenge.data, 20430Sstevel@tonic-gate sc.sam_challenge.length, 20440Sstevel@tonic-gate psr.sam_key.contents, /* key */ 20450Sstevel@tonic-gate psr.sam_key.length, /* key length */ 20460Sstevel@tonic-gate &sc.sam_cksum); 20470Sstevel@tonic-gate if (retval) { free(sc.sam_cksum.contents); return(retval); } 20480Sstevel@tonic-gate #endif /* 0 */ 20490Sstevel@tonic-gate 20500Sstevel@tonic-gate retval = encode_krb5_sam_challenge(&sc, &scratch); 20510Sstevel@tonic-gate if (retval) goto cleanup; 20520Sstevel@tonic-gate pa_data->magic = KV5M_PA_DATA; 20530Sstevel@tonic-gate pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE; 20540Sstevel@tonic-gate pa_data->contents = (unsigned char *) scratch->data; 20550Sstevel@tonic-gate pa_data->length = scratch->length; 20560Sstevel@tonic-gate 20570Sstevel@tonic-gate retval = 0; 20580Sstevel@tonic-gate break; 20590Sstevel@tonic-gate case PA_SAM_TYPE_DIGI_PATH: 20600Sstevel@tonic-gate sc.sam_type_name.data = "Digital Pathways"; 20610Sstevel@tonic-gate sc.sam_type_name.length = strlen(sc.sam_type_name.data); 20620Sstevel@tonic-gate #if 1 20630Sstevel@tonic-gate sc.sam_challenge_label.data = "Enter the following on your keypad"; 20640Sstevel@tonic-gate sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 20650Sstevel@tonic-gate #endif 20660Sstevel@tonic-gate /* generate digit string, take it mod 1000000 (six digits.) */ 20670Sstevel@tonic-gate { 20680Sstevel@tonic-gate int j; 20690Sstevel@tonic-gate krb5_keyblock session_key; 20700Sstevel@tonic-gate char outputblock[8]; 20710Sstevel@tonic-gate int i; 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate (void) memset(&session_key, 0, sizeof(krb5_keyblock)); 20742881Smp153739 20750Sstevel@tonic-gate (void) memset(inputblock, 0, 8); 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC, 20780Sstevel@tonic-gate &session_key); 20790Sstevel@tonic-gate 20800Sstevel@tonic-gate if (retval) { 20810Sstevel@tonic-gate /* random key failed */ 20820Sstevel@tonic-gate com_err(gettext("krb5kdc"), 20830Sstevel@tonic-gate retval, 20840Sstevel@tonic-gate gettext("generating random challenge for preauth")); 20850Sstevel@tonic-gate return retval; 20860Sstevel@tonic-gate } 20870Sstevel@tonic-gate /* now session_key has a key which we can pick bits out of */ 20880Sstevel@tonic-gate /* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */ 20890Sstevel@tonic-gate if (session_key.length != 8) { 20900Sstevel@tonic-gate retval = KRB5KDC_ERR_ETYPE_NOSUPP, 20910Sstevel@tonic-gate com_err(gettext("krb5kdc"), 20920Sstevel@tonic-gate retval = KRB5KDC_ERR_ETYPE_NOSUPP, 20930Sstevel@tonic-gate gettext("keytype didn't match code expectations")); 20940Sstevel@tonic-gate return retval; 20950Sstevel@tonic-gate } 20960Sstevel@tonic-gate for(i = 0; i<6; i++) { 20970Sstevel@tonic-gate inputblock[i] = '0' + ((session_key.contents[i]/2) % 10); 20980Sstevel@tonic-gate } 20990Sstevel@tonic-gate if (session_key.contents) 21000Sstevel@tonic-gate krb5_free_keyblock_contents(kdc_context, &session_key); 21010Sstevel@tonic-gate 21020Sstevel@tonic-gate /* retval = krb5_finish_key(kdc_context, &eblock); */ 21030Sstevel@tonic-gate /* now we have inputblock containing the 8 byte input to DES... */ 21040Sstevel@tonic-gate sc.sam_challenge.data = inputblock; 21050Sstevel@tonic-gate sc.sam_challenge.length = 6; 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate encrypting_key.enctype = ENCTYPE_DES_CBC_RAW; 21080Sstevel@tonic-gate 21090Sstevel@tonic-gate if (retval) { 21100Sstevel@tonic-gate com_err(gettext("krb5kdc"), 21110Sstevel@tonic-gate retval, 21120Sstevel@tonic-gate gettext("snk4 processing key")); 21130Sstevel@tonic-gate } 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate { 21160Sstevel@tonic-gate krb5_data plain; 21170Sstevel@tonic-gate krb5_enc_data cipher; 21180Sstevel@tonic-gate 21190Sstevel@tonic-gate plain.length = 8; 21200Sstevel@tonic-gate plain.data = inputblock; 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate /* XXX I know this is enough because of the fixed raw enctype. 21230Sstevel@tonic-gate if it's not, the underlying code will return a reasonable 21240Sstevel@tonic-gate error, which should never happen */ 21250Sstevel@tonic-gate cipher.ciphertext.length = 8; 21260Sstevel@tonic-gate cipher.ciphertext.data = outputblock; 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key, 21290Sstevel@tonic-gate /* XXX */ 0, 0, &plain, &cipher))) { 21300Sstevel@tonic-gate com_err(gettext("krb5kdc"), 21310Sstevel@tonic-gate retval, 21320Sstevel@tonic-gate gettext("snk4 response generation failed")); 21330Sstevel@tonic-gate return retval; 21340Sstevel@tonic-gate } 21350Sstevel@tonic-gate } 21360Sstevel@tonic-gate 21370Sstevel@tonic-gate /* now output block is the raw bits of the response; convert it 21380Sstevel@tonic-gate to display form */ 21390Sstevel@tonic-gate for (j=0; j<4; j++) { 21400Sstevel@tonic-gate char n[2]; 21410Sstevel@tonic-gate int k; 21420Sstevel@tonic-gate n[0] = outputblock[j] & 0xf; 21430Sstevel@tonic-gate n[1] = (outputblock[j]>>4) & 0xf; 21440Sstevel@tonic-gate for (k=0; k<2; k++) { 21450Sstevel@tonic-gate if(n[k] > 9) n[k] = ((n[k]-1)>>2); 21460Sstevel@tonic-gate /* This is equivalent to: 21470Sstevel@tonic-gate if(n[k]>=0xa && n[k]<=0xc) n[k] = 2; 21480Sstevel@tonic-gate if(n[k]>=0xd && n[k]<=0xf) n[k] = 3; 21490Sstevel@tonic-gate */ 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */ 21520Sstevel@tonic-gate /* for v5, we just generate a string */ 21530Sstevel@tonic-gate response[2*j+0] = '0' + n[1]; 21540Sstevel@tonic-gate response[2*j+1] = '0' + n[0]; 21550Sstevel@tonic-gate /* and now, response has what we work with. */ 21560Sstevel@tonic-gate } 21570Sstevel@tonic-gate response[8] = 0; 21580Sstevel@tonic-gate predict_response.data = response; 21590Sstevel@tonic-gate predict_response.length = 8; 21600Sstevel@tonic-gate #if 0 /* for debugging, hack the output too! */ 21610Sstevel@tonic-gate sc.sam_challenge_label.data = response; 21620Sstevel@tonic-gate sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data); 21630Sstevel@tonic-gate #endif 21640Sstevel@tonic-gate } 21650Sstevel@tonic-gate 21660Sstevel@tonic-gate psr.magic = KV5M_PREDICTED_SAM_RESPONSE; 21670Sstevel@tonic-gate /* string2key on sc.sam_challenge goes in here */ 21680Sstevel@tonic-gate /* eblock is just to set the enctype */ 21690Sstevel@tonic-gate { 21700Sstevel@tonic-gate retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5, 21710Sstevel@tonic-gate &predict_response, 0 /* salt */, 21720Sstevel@tonic-gate &psr.sam_key); 21730Sstevel@tonic-gate if (retval) goto cleanup; 21740Sstevel@tonic-gate 21750Sstevel@tonic-gate retval = encode_krb5_predicted_sam_response(&psr, &scratch); 21760Sstevel@tonic-gate if (retval) goto cleanup; 21770Sstevel@tonic-gate 21780Sstevel@tonic-gate { 21790Sstevel@tonic-gate size_t enclen; 21800Sstevel@tonic-gate krb5_enc_data tmpdata; 21810Sstevel@tonic-gate 21820Sstevel@tonic-gate if ((retval = krb5_c_encrypt_length(context, 21830Sstevel@tonic-gate psr_key.enctype, 21840Sstevel@tonic-gate scratch->length, &enclen))) 21850Sstevel@tonic-gate goto cleanup; 21860Sstevel@tonic-gate 21870Sstevel@tonic-gate if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) { 21880Sstevel@tonic-gate retval = ENOMEM; 21890Sstevel@tonic-gate goto cleanup; 21900Sstevel@tonic-gate } 21910Sstevel@tonic-gate tmpdata.ciphertext.length = enclen; 21920Sstevel@tonic-gate 21930Sstevel@tonic-gate if ((retval = krb5_c_encrypt(context, &psr_key, 21940Sstevel@tonic-gate /* XXX */ 0, 0, scratch, &tmpdata))) 21950Sstevel@tonic-gate goto cleanup; 21960Sstevel@tonic-gate 21970Sstevel@tonic-gate sc.sam_track_id = tmpdata.ciphertext; 21980Sstevel@tonic-gate } 21990Sstevel@tonic-gate if (retval) goto cleanup; 22000Sstevel@tonic-gate } 22010Sstevel@tonic-gate 22020Sstevel@tonic-gate sc.sam_response_prompt.data = "Enter the displayed response"; 22030Sstevel@tonic-gate sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data); 22040Sstevel@tonic-gate sc.sam_pk_for_sad.length = 0; 22050Sstevel@tonic-gate sc.sam_nonce = 0; 22060Sstevel@tonic-gate /* Generate checksum */ 22070Sstevel@tonic-gate /*krb5_checksum_size(context, ctype)*/ 22080Sstevel@tonic-gate /*krb5_calculate_checksum(context,ctype,in,in_length,seed, 22090Sstevel@tonic-gate seed_length,outcksum) */ 22100Sstevel@tonic-gate /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed, 22110Sstevel@tonic-gate seed_length) */ 22120Sstevel@tonic-gate #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */ 22130Sstevel@tonic-gate sc.sam_cksum.contents = (krb5_octet *) 22140Sstevel@tonic-gate malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES)); 22150Sstevel@tonic-gate if (sc.sam_cksum.contents == NULL) return(ENOMEM); 22160Sstevel@tonic-gate 22170Sstevel@tonic-gate retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES, 22180Sstevel@tonic-gate sc.sam_challenge.data, 22190Sstevel@tonic-gate sc.sam_challenge.length, 22200Sstevel@tonic-gate psr.sam_key.contents, /* key */ 22210Sstevel@tonic-gate psr.sam_key.length, /* key length */ 22220Sstevel@tonic-gate &sc.sam_cksum); 22230Sstevel@tonic-gate if (retval) { free(sc.sam_cksum.contents); return(retval); } 22240Sstevel@tonic-gate #endif /* 0 */ 22250Sstevel@tonic-gate 22260Sstevel@tonic-gate retval = encode_krb5_sam_challenge(&sc, &scratch); 22270Sstevel@tonic-gate if (retval) goto cleanup; 22280Sstevel@tonic-gate pa_data->magic = KV5M_PA_DATA; 22290Sstevel@tonic-gate pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE; 22300Sstevel@tonic-gate pa_data->contents = (unsigned char *) scratch->data; 22310Sstevel@tonic-gate pa_data->length = scratch->length; 22320Sstevel@tonic-gate 22330Sstevel@tonic-gate retval = 0; 22340Sstevel@tonic-gate break; 22350Sstevel@tonic-gate } 22360Sstevel@tonic-gate 22370Sstevel@tonic-gate cleanup: 22380Sstevel@tonic-gate krb5_free_keyblock_contents(context, &encrypting_key); 22390Sstevel@tonic-gate return retval; 22400Sstevel@tonic-gate } 22410Sstevel@tonic-gate 22420Sstevel@tonic-gate static krb5_error_code 22432881Smp153739 verify_sam_response(krb5_context context, krb5_db_entry *client, 2244*7934SMark.Phalan@Sun.COM krb5_data *req_pkt, 22452881Smp153739 krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, 2246*7934SMark.Phalan@Sun.COM krb5_pa_data *pa, 2247*7934SMark.Phalan@Sun.COM preauth_get_entry_data_proc sam_get_entry_data, 2248*7934SMark.Phalan@Sun.COM void *pa_system_context, 2249*7934SMark.Phalan@Sun.COM void **pa_request_context, 2250*7934SMark.Phalan@Sun.COM krb5_data **e_data, 2251*7934SMark.Phalan@Sun.COM krb5_authdata ***authz_data) 22520Sstevel@tonic-gate { 22530Sstevel@tonic-gate krb5_error_code retval; 22540Sstevel@tonic-gate krb5_data scratch; 22550Sstevel@tonic-gate krb5_sam_response *sr = 0; 22560Sstevel@tonic-gate krb5_predicted_sam_response *psr = 0; 22570Sstevel@tonic-gate krb5_enc_sam_response_enc *esre = 0; 22580Sstevel@tonic-gate krb5_timestamp timenow; 22590Sstevel@tonic-gate char *princ_req = 0, *princ_psr = 0; 22600Sstevel@tonic-gate 22610Sstevel@tonic-gate scratch.data = (char *) pa->contents; 22620Sstevel@tonic-gate scratch.length = pa->length; 22630Sstevel@tonic-gate 22640Sstevel@tonic-gate if ((retval = decode_krb5_sam_response(&scratch, &sr))) { 22650Sstevel@tonic-gate scratch.data = 0; 22660Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("decode_krb5_sam_response failed")); 22670Sstevel@tonic-gate goto cleanup; 22680Sstevel@tonic-gate } 22690Sstevel@tonic-gate 22700Sstevel@tonic-gate /* XXX We can only handle the challenge/response model of SAM. 22710Sstevel@tonic-gate See passwords-04, par 4.1, 4.2 */ 22720Sstevel@tonic-gate { 22730Sstevel@tonic-gate krb5_enc_data tmpdata; 22740Sstevel@tonic-gate 22750Sstevel@tonic-gate tmpdata.enctype = ENCTYPE_UNKNOWN; 22760Sstevel@tonic-gate tmpdata.ciphertext = sr->sam_track_id; 22770Sstevel@tonic-gate 22780Sstevel@tonic-gate scratch.length = tmpdata.ciphertext.length; 22790Sstevel@tonic-gate if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 22800Sstevel@tonic-gate retval = ENOMEM; 22810Sstevel@tonic-gate goto cleanup; 22820Sstevel@tonic-gate } 22830Sstevel@tonic-gate 22840Sstevel@tonic-gate if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0, 22850Sstevel@tonic-gate &tmpdata, &scratch))) { 22860Sstevel@tonic-gate com_err(gettext("krb5kdc"), 22870Sstevel@tonic-gate retval, 22880Sstevel@tonic-gate gettext("decrypt track_id failed")); 22890Sstevel@tonic-gate goto cleanup; 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate } 22920Sstevel@tonic-gate 22930Sstevel@tonic-gate if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) { 22940Sstevel@tonic-gate com_err(gettext("krb5kdc"), retval, 22950Sstevel@tonic-gate gettext("decode_krb5_predicted_sam_response failed -- replay attack?")); 22960Sstevel@tonic-gate goto cleanup; 22970Sstevel@tonic-gate } 22980Sstevel@tonic-gate 22990Sstevel@tonic-gate /* Replay detection */ 23000Sstevel@tonic-gate if ((retval = krb5_unparse_name(context, request->client, &princ_req))) 23010Sstevel@tonic-gate goto cleanup; 23020Sstevel@tonic-gate if ((retval = krb5_unparse_name(context, psr->client, &princ_psr))) 23030Sstevel@tonic-gate goto cleanup; 23040Sstevel@tonic-gate if (strcmp(princ_req, princ_psr) != 0) { 23050Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 23060Sstevel@tonic-gate gettext("Principal mismatch in SAM psr! -- replay attack?")); 23070Sstevel@tonic-gate goto cleanup; 23080Sstevel@tonic-gate } 23090Sstevel@tonic-gate 23100Sstevel@tonic-gate if ((retval = krb5_timeofday(context, &timenow))) 23110Sstevel@tonic-gate goto cleanup; 23120Sstevel@tonic-gate 23130Sstevel@tonic-gate #ifdef USE_RCACHE 23140Sstevel@tonic-gate { 23150Sstevel@tonic-gate krb5_donot_replay rep; 23160Sstevel@tonic-gate extern krb5_deltat rc_lifetime; 23170Sstevel@tonic-gate /* 23180Sstevel@tonic-gate * Verify this response came back in a timely manner. 23190Sstevel@tonic-gate * We do this b/c otherwise very old (expunged from the rcache) 23200Sstevel@tonic-gate * psr's would be able to be replayed. 23210Sstevel@tonic-gate */ 23220Sstevel@tonic-gate if (timenow - psr->stime > rc_lifetime) { 23230Sstevel@tonic-gate com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED, 23240Sstevel@tonic-gate gettext("SAM psr came back too late! -- replay attack?")); 23250Sstevel@tonic-gate goto cleanup; 23260Sstevel@tonic-gate } 23270Sstevel@tonic-gate 23280Sstevel@tonic-gate /* Now check the replay cache. */ 23290Sstevel@tonic-gate rep.client = princ_psr; 23300Sstevel@tonic-gate rep.server = "SAM/rc"; /* Should not match any principal name. */ 23310Sstevel@tonic-gate rep.ctime = psr->stime; 23320Sstevel@tonic-gate rep.cusec = psr->susec; 23332881Smp153739 retval = krb5_rc_store(kdc_context, kdc_rcache, &rep); 23342881Smp153739 if (retval) { 23350Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("SAM psr replay attack!")); 23360Sstevel@tonic-gate goto cleanup; 23370Sstevel@tonic-gate } 23380Sstevel@tonic-gate } 23390Sstevel@tonic-gate #endif /* USE_RCACHE */ 23400Sstevel@tonic-gate 23410Sstevel@tonic-gate 23420Sstevel@tonic-gate { 23430Sstevel@tonic-gate free(scratch.data); 23440Sstevel@tonic-gate scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length; 23450Sstevel@tonic-gate if ((scratch.data = (char *) malloc(scratch.length)) == NULL) { 23460Sstevel@tonic-gate retval = ENOMEM; 23470Sstevel@tonic-gate goto cleanup; 23480Sstevel@tonic-gate } 23490Sstevel@tonic-gate 23500Sstevel@tonic-gate if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0, 23510Sstevel@tonic-gate 0, &sr->sam_enc_nonce_or_ts, &scratch))) { 23520Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("decrypt nonce_or_ts failed")); 23530Sstevel@tonic-gate goto cleanup; 23540Sstevel@tonic-gate } 23550Sstevel@tonic-gate } 23560Sstevel@tonic-gate 23570Sstevel@tonic-gate if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) { 23580Sstevel@tonic-gate com_err("krb5kdc", retval, gettext("decode_krb5_enc_sam_response_enc failed")); 23590Sstevel@tonic-gate goto cleanup; 23600Sstevel@tonic-gate } 23610Sstevel@tonic-gate 23620Sstevel@tonic-gate if (esre->sam_timestamp != sr->sam_patimestamp) { 23630Sstevel@tonic-gate retval = KRB5KDC_ERR_PREAUTH_FAILED; 23640Sstevel@tonic-gate goto cleanup; 23650Sstevel@tonic-gate } 23660Sstevel@tonic-gate 23670Sstevel@tonic-gate if (labs(timenow - sr->sam_patimestamp) > context->clockskew) { 23680Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_SKEW; 23690Sstevel@tonic-gate goto cleanup; 23700Sstevel@tonic-gate } 23710Sstevel@tonic-gate 23720Sstevel@tonic-gate setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH); 23730Sstevel@tonic-gate 23740Sstevel@tonic-gate cleanup: 23750Sstevel@tonic-gate if (retval) com_err(gettext("krb5kdc"), 23760Sstevel@tonic-gate retval, 23770Sstevel@tonic-gate gettext("sam verify failure")); 23780Sstevel@tonic-gate if (scratch.data) free(scratch.data); 23790Sstevel@tonic-gate if (sr) free(sr); 23800Sstevel@tonic-gate if (psr) free(psr); 23810Sstevel@tonic-gate if (esre) free(esre); 23822881Smp153739 if (princ_psr) free(princ_psr); 23832881Smp153739 if (princ_req) free(princ_req); 23840Sstevel@tonic-gate 23850Sstevel@tonic-gate return retval; 23860Sstevel@tonic-gate } 2387