1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <sys/random.h> 27 #include <sys/conf.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 31 #include <sys/socket.h> 32 #include <inet/tcp.h> 33 34 #include <sys/stmf.h> 35 #include <sys/stmf_ioctl.h> 36 #include <sys/portif.h> 37 #include <sys/idm/idm.h> 38 #include <sys/iscsit/chap.h> 39 40 #include "iscsit.h" 41 #include "radius_auth.h" 42 43 void 44 client_set_numeric_data(auth_key_block_t *keyBlock, 45 int key_type, 46 uint32_t numeric) 47 { 48 auth_key_t *p; 49 50 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 51 52 p = &keyBlock->key[key_type]; 53 p->value.numeric = numeric; 54 p->present = 1; 55 } 56 57 void 58 client_set_string_data(auth_key_block_t *keyBlock, 59 int key_type, 60 char *string) 61 { 62 auth_key_t *p; 63 64 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 65 66 p = &keyBlock->key[key_type]; 67 p->value.string = string; 68 p->present = 1; 69 } 70 71 void 72 client_set_binary_data(auth_key_block_t *keyBlock, 73 int key_type, 74 unsigned char *binary, unsigned int len) 75 { 76 auth_key_t *p; 77 78 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 79 80 p = &keyBlock->key[key_type]; 81 p->value.binary = binary; 82 p->len = len; 83 p->present = 1; 84 } 85 86 void 87 client_get_numeric_data(auth_key_block_t *keyBlock, 88 int key_type, 89 uint32_t *numeric) 90 { 91 auth_key_t *p; 92 93 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 94 95 p = &keyBlock->key[key_type]; 96 *numeric = p->value.numeric; 97 } 98 99 void 100 client_get_string_data(auth_key_block_t *keyBlock, 101 int key_type, 102 char **string) 103 { 104 auth_key_t *p; 105 106 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 107 108 p = &keyBlock->key[key_type]; 109 *string = p->value.string; 110 } 111 112 void 113 client_get_binary_data(auth_key_block_t *keyBlock, 114 int key_type, 115 unsigned char **binary, unsigned int *len) 116 { 117 auth_key_t *p; 118 119 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 120 121 p = &keyBlock->key[key_type]; 122 *binary = p->value.binary; 123 *len = p->len; 124 } 125 126 int 127 client_auth_key_present(auth_key_block_t *keyBlock, 128 int key_type) 129 { 130 auth_key_t *p; 131 132 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 133 134 p = &keyBlock->key[key_type]; 135 136 return (p->present != 0 ? 1 : 0); 137 } 138 139 /*ARGSUSED*/ 140 void 141 client_compute_chap_resp(uchar_t *resp, 142 unsigned int chap_i, 143 uint8_t *password, int password_len, 144 uchar_t *chap_c, unsigned int challenge_len) 145 { 146 MD5_CTX context; 147 148 MD5Init(&context); 149 150 /* 151 * id byte 152 */ 153 resp[0] = (uchar_t)chap_i; 154 MD5Update(&context, resp, 1); 155 156 /* 157 * shared secret 158 */ 159 MD5Update(&context, (uchar_t *)password, password_len); 160 161 /* 162 * challenge value 163 */ 164 MD5Update(&context, chap_c, challenge_len); 165 166 MD5Final(resp, &context); 167 } 168 169 int 170 iscsit_verify_chap_resp(iscsit_conn_login_t *lsm, 171 unsigned int chap_i, 172 uchar_t *chap_c, unsigned int challenge_len, 173 uchar_t *chap_r, unsigned int resp_len) 174 { 175 uchar_t verifyData[iscsitAuthChapResponseLength]; 176 conn_auth_t *auth = &lsm->icl_auth; 177 178 /* Check if RADIUS access is enabled */ 179 if (auth->ca_use_radius == B_TRUE) { 180 chap_validation_status_type chap_valid_status; 181 RADIUS_CONFIG radius_cfg; 182 struct sockaddr_storage *sa = &auth->ca_radius_server; 183 struct sockaddr_in *sin; 184 struct sockaddr_in6 *sin6; 185 186 /* Use RADIUS server to authentication target */ 187 sin = (struct sockaddr_in *)sa; 188 radius_cfg.rad_svr_port = ntohs(sin->sin_port); 189 if (sa->ss_family == AF_INET) { 190 /* IPv4 */ 191 radius_cfg.rad_svr_addr.i_addr.in4.s_addr = 192 sin->sin_addr.s_addr; 193 radius_cfg.rad_svr_addr.i_insize = sizeof (in_addr_t); 194 } else if (sa->ss_family == AF_INET6) { 195 /* IPv6 */ 196 sin6 = (struct sockaddr_in6 *)sa; 197 bcopy(sin6->sin6_addr.s6_addr, 198 radius_cfg.rad_svr_addr.i_addr.in6.s6_addr, 199 sizeof (struct in6_addr)); 200 radius_cfg.rad_svr_addr.i_insize = sizeof (in6_addr_t); 201 } else { 202 return (ISCSI_AUTH_FAILED); 203 } 204 205 bcopy(auth->ca_radius_secret, 206 radius_cfg.rad_svr_shared_secret, 207 MAX_RAD_SHARED_SECRET_LEN); 208 radius_cfg.rad_svr_shared_secret_len = 209 auth->ca_radius_secretlen; 210 211 chap_valid_status = iscsit_radius_chap_validate( 212 auth->ca_ini_chapuser, 213 auth->ca_tgt_chapuser, 214 chap_c, 215 challenge_len, 216 chap_r, 217 resp_len, 218 chap_i, 219 radius_cfg.rad_svr_addr, 220 radius_cfg.rad_svr_port, 221 radius_cfg.rad_svr_shared_secret, 222 radius_cfg.rad_svr_shared_secret_len); 223 224 if (chap_valid_status == CHAP_VALIDATION_PASSED) { 225 return (ISCSI_AUTH_PASSED); 226 } 227 return (ISCSI_AUTH_FAILED); 228 } 229 230 /* Empty chap secret is not allowed */ 231 if (auth->ca_ini_chapsecretlen == 0) { 232 return (ISCSI_AUTH_FAILED); 233 } 234 235 /* only MD5 is supported */ 236 if (resp_len != sizeof (verifyData)) { 237 return (ISCSI_AUTH_FAILED); 238 } 239 240 client_compute_chap_resp( 241 &verifyData[0], 242 chap_i, 243 auth->ca_ini_chapsecret, auth->ca_ini_chapsecretlen, 244 chap_c, challenge_len); 245 246 if (bcmp(chap_r, verifyData, 247 sizeof (verifyData)) != 0) { 248 return (ISCSI_AUTH_FAILED); 249 } 250 251 /* chap response OK */ 252 return (ISCSI_AUTH_PASSED); 253 } 254 255 void 256 auth_random_set_data(uchar_t *data, unsigned int length) 257 { 258 (void) random_get_pseudo_bytes(data, length); 259 } 260