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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/random.h> 28 #include <sys/conf.h> 29 #include <sys/ddi.h> 30 #include <sys/sunddi.h> 31 32 #include <sys/socket.h> 33 #include <inet/tcp.h> 34 35 #include <sys/stmf.h> 36 #include <sys/stmf_ioctl.h> 37 #include <sys/portif.h> 38 #include <sys/idm/idm.h> 39 40 #include <iscsit.h> 41 42 #include <sys/iscsit/chap.h> 43 #include <radius_auth.h> 44 45 void 46 client_set_numeric_data(auth_key_block_t *keyBlock, 47 int key_type, 48 uint32_t numeric) 49 { 50 auth_key_t *p; 51 52 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 53 54 p = &keyBlock->key[key_type]; 55 p->value.numeric = numeric; 56 p->present = 1; 57 } 58 59 void 60 client_set_string_data(auth_key_block_t *keyBlock, 61 int key_type, 62 char *string) 63 { 64 auth_key_t *p; 65 66 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 67 68 p = &keyBlock->key[key_type]; 69 p->value.string = string; 70 p->present = 1; 71 } 72 73 void 74 client_set_binary_data(auth_key_block_t *keyBlock, 75 int key_type, 76 unsigned char *binary, unsigned int len) 77 { 78 auth_key_t *p; 79 80 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 81 82 p = &keyBlock->key[key_type]; 83 p->value.binary = binary; 84 p->len = len; 85 p->present = 1; 86 } 87 88 void 89 client_get_numeric_data(auth_key_block_t *keyBlock, 90 int key_type, 91 uint32_t *numeric) 92 { 93 auth_key_t *p; 94 95 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 96 97 p = &keyBlock->key[key_type]; 98 *numeric = p->value.numeric; 99 } 100 101 void 102 client_get_string_data(auth_key_block_t *keyBlock, 103 int key_type, 104 char **string) 105 { 106 auth_key_t *p; 107 108 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 109 110 p = &keyBlock->key[key_type]; 111 *string = p->value.string; 112 } 113 114 void 115 client_get_binary_data(auth_key_block_t *keyBlock, 116 int key_type, 117 unsigned char **binary, unsigned int *len) 118 { 119 auth_key_t *p; 120 121 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 122 123 p = &keyBlock->key[key_type]; 124 *binary = p->value.binary; 125 *len = p->len; 126 } 127 128 int 129 client_auth_key_present(auth_key_block_t *keyBlock, 130 int key_type) 131 { 132 auth_key_t *p; 133 134 ASSERT(key_type < AUTH_KEY_TYPE_MAX); 135 136 p = &keyBlock->key[key_type]; 137 138 return (p->present != 0 ? 1 : 0); 139 } 140 141 /*ARGSUSED*/ 142 void 143 client_compute_chap_resp(uchar_t *resp, 144 unsigned int chap_i, 145 uint8_t *password, int password_len, 146 uchar_t *chap_c, unsigned int challenge_len) 147 { 148 MD5_CTX context; 149 150 MD5Init(&context); 151 152 /* 153 * id byte 154 */ 155 resp[0] = (uchar_t)chap_i; 156 MD5Update(&context, resp, 1); 157 158 /* 159 * shared secret 160 */ 161 MD5Update(&context, (uchar_t *)password, password_len); 162 163 /* 164 * challenge value 165 */ 166 MD5Update(&context, chap_c, challenge_len); 167 168 MD5Final(resp, &context); 169 } 170 171 int 172 iscsit_verify_chap_resp(iscsit_conn_login_t *lsm, 173 unsigned int chap_i, 174 uchar_t *chap_c, unsigned int challenge_len, 175 uchar_t *chap_r, unsigned int resp_len) 176 { 177 uchar_t verifyData[iscsitAuthChapResponseLength]; 178 conn_auth_t *auth = &lsm->icl_auth; 179 180 /* Check if RADIUS access is enabled */ 181 if (auth->ca_use_radius == B_TRUE) { 182 chap_validation_status_type chap_valid_status; 183 RADIUS_CONFIG radius_cfg; 184 struct sockaddr_storage *sa = &auth->ca_radius_server; 185 struct sockaddr_in *sin; 186 struct sockaddr_in6 *sin6; 187 188 /* Use RADIUS server to authentication target */ 189 sin = (struct sockaddr_in *)sa; 190 radius_cfg.rad_svr_port = ntohs(sin->sin_port); 191 if (sa->ss_family == AF_INET) { 192 /* IPv4 */ 193 radius_cfg.rad_svr_addr.i_addr.in4.s_addr = 194 sin->sin_addr.s_addr; 195 radius_cfg.rad_svr_addr.i_insize = sizeof (in_addr_t); 196 } else if (sa->ss_family == AF_INET6) { 197 /* IPv6 */ 198 sin6 = (struct sockaddr_in6 *)sa; 199 bcopy(sin6->sin6_addr.s6_addr, 200 radius_cfg.rad_svr_addr.i_addr.in6.s6_addr, 201 sizeof (struct in6_addr)); 202 radius_cfg.rad_svr_addr.i_insize = sizeof (in6_addr_t); 203 } else { 204 return (ISCSI_AUTH_FAILED); 205 } 206 207 bcopy(auth->ca_radius_secret, 208 radius_cfg.rad_svr_shared_secret, 209 MAX_RAD_SHARED_SECRET_LEN); 210 radius_cfg.rad_svr_shared_secret_len = 211 auth->ca_radius_secretlen; 212 213 chap_valid_status = iscsit_radius_chap_validate( 214 auth->ca_ini_chapuser, 215 auth->ca_tgt_chapuser, 216 chap_c, 217 challenge_len, 218 chap_r, 219 resp_len, 220 chap_i, 221 radius_cfg.rad_svr_addr, 222 radius_cfg.rad_svr_port, 223 radius_cfg.rad_svr_shared_secret, 224 radius_cfg.rad_svr_shared_secret_len); 225 226 if (chap_valid_status == CHAP_VALIDATION_PASSED) { 227 return (ISCSI_AUTH_PASSED); 228 } 229 return (ISCSI_AUTH_FAILED); 230 } 231 232 /* Empty chap secret is not allowed */ 233 if (auth->ca_ini_chapsecretlen == 0) { 234 return (ISCSI_AUTH_FAILED); 235 } 236 237 /* only MD5 is supported */ 238 if (resp_len != sizeof (verifyData)) { 239 return (ISCSI_AUTH_FAILED); 240 } 241 242 client_compute_chap_resp( 243 &verifyData[0], 244 chap_i, 245 auth->ca_ini_chapsecret, auth->ca_ini_chapsecretlen, 246 chap_c, challenge_len); 247 248 if (bcmp(chap_r, verifyData, 249 sizeof (verifyData)) != 0) { 250 return (ISCSI_AUTH_FAILED); 251 } 252 253 /* chap response OK */ 254 return (ISCSI_AUTH_PASSED); 255 } 256 257 void 258 auth_random_set_data(uchar_t *data, unsigned int length) 259 { 260 (void) random_get_pseudo_bytes(data, length); 261 } 262