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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/ddi.h> 27 #include <sys/sunddi.h> 28 #include <sys/iscsit/iscsi_if.h> 29 #include <sys/md5.h> 30 31 #include <sys/idm/idm.h> 32 #include <sys/idm/idm_so.h> 33 #include <sys/iscsit/radius_packet.h> 34 #include <sys/iscsit/radius_protocol.h> 35 36 static void encode_chap_password(int identifier, int chap_passwd_len, 37 uint8_t *chap_passwd, uint8_t *result); 38 39 static size_t iscsit_net_recvmsg(void *socket, struct msghdr *msg, 40 int timeout); 41 42 /* 43 * See radius_packet.h. 44 */ 45 int 46 iscsit_snd_radius_request(void *socket, iscsi_ipaddr_t rsvr_ip_addr, 47 uint32_t rsvr_port, radius_packet_data_t *req_data) 48 { 49 int i; /* Loop counter. */ 50 int data_len; 51 int len; 52 ushort_t total_length; /* Has to be 2 octets in size */ 53 uint8_t *ptr; /* Pointer to RADIUS packet data */ 54 uint8_t *length_ptr; /* Points to the Length field of the */ 55 /* packet. */ 56 uint8_t *data; /* RADIUS data to be sent */ 57 radius_attr_t *req_attr; /* Request attributes */ 58 radius_packet_t *packet; /* Outbound RADIUS packet */ 59 union { 60 struct sockaddr_in s_in4; 61 struct sockaddr_in6 s_in6; 62 } sa_rsvr; /* Socket address of the server */ 63 int err; 64 65 /* 66 * Create a RADIUS packet with minimal length for now. 67 */ 68 total_length = MIN_RAD_PACKET_LEN; 69 data = kmem_zalloc(MAX_RAD_PACKET_LEN, KM_SLEEP); 70 packet = (radius_packet_t *)data; 71 packet->code = req_data->code; 72 packet->identifier = req_data->identifier; 73 bcopy(req_data->authenticator, packet->authenticator, 74 RAD_AUTHENTICATOR_LEN); 75 ptr = packet->data; 76 77 /* Loop over all attributes of the request. */ 78 for (i = 0; i < req_data->num_of_attrs; i++) { 79 if (total_length > MAX_RAD_PACKET_LEN) { 80 /* The packet has exceed its maximum size. */ 81 kmem_free(data, MAX_RAD_PACKET_LEN); 82 return (-1); 83 } 84 85 req_attr = &req_data->attrs[i]; 86 *ptr++ = (req_attr->attr_type_code & 0xFF); 87 length_ptr = ptr; 88 /* Length is 2 octets - RFC 2865 section 3 */ 89 *ptr++ = 2; 90 total_length += 2; 91 92 /* If the attribute is CHAP-Password, encode it. */ 93 if (req_attr->attr_type_code == RAD_CHAP_PASSWORD) { 94 /* 95 * Identifier plus CHAP response. RFC 2865 96 * section 5.3. 97 */ 98 uint8_t encoded_chap_passwd[ 99 RAD_CHAP_PASSWD_STR_LEN + RAD_IDENTIFIER_LEN + 1]; 100 encode_chap_password( 101 req_data->identifier, 102 req_attr->attr_value_len, 103 req_attr->attr_value, 104 encoded_chap_passwd); 105 106 req_attr->attr_value_len = 107 RAD_CHAP_PASSWD_STR_LEN + RAD_IDENTIFIER_LEN; 108 109 bcopy(encoded_chap_passwd, 110 req_attr->attr_value, 111 req_attr->attr_value_len); 112 } 113 114 len = req_attr->attr_value_len; 115 *length_ptr += len; 116 117 bcopy(req_attr->attr_value, ptr, req_attr->attr_value_len); 118 ptr += req_attr->attr_value_len; 119 120 total_length += len; 121 } /* Done looping over all attributes */ 122 123 data_len = total_length; 124 total_length = htons(total_length); 125 bcopy(&total_length, packet->length, sizeof (ushort_t)); 126 127 /* 128 * Send the packet to the RADIUS server. 129 */ 130 bzero((char *)&sa_rsvr, sizeof (sa_rsvr)); 131 if (rsvr_ip_addr.i_insize == sizeof (in_addr_t)) { 132 133 /* IPv4 */ 134 sa_rsvr.s_in4.sin_family = AF_INET; 135 sa_rsvr.s_in4.sin_addr.s_addr = 136 rsvr_ip_addr.i_addr.in4.s_addr; 137 sa_rsvr.s_in4.sin_port = htons((ushort_t)rsvr_port); 138 139 err = idm_sosendto(socket, data, data_len, 140 (struct sockaddr *)&sa_rsvr.s_in4, 141 sizeof (struct sockaddr_in)); 142 kmem_free(data, MAX_RAD_PACKET_LEN); 143 return (err); 144 } else if (rsvr_ip_addr.i_insize == sizeof (in6_addr_t)) { 145 /* IPv6 */ 146 sa_rsvr.s_in6.sin6_family = AF_INET6; 147 bcopy(rsvr_ip_addr.i_addr.in6.s6_addr, 148 sa_rsvr.s_in6.sin6_addr.s6_addr, sizeof (struct in6_addr)); 149 sa_rsvr.s_in6.sin6_port = htons((ushort_t)rsvr_port); 150 151 err = idm_sosendto(socket, data, data_len, 152 (struct sockaddr *)&sa_rsvr.s_in6, 153 sizeof (struct sockaddr_in6)); 154 kmem_free(data, MAX_RAD_PACKET_LEN); 155 return (err); 156 } else { 157 /* Invalid IP address for RADIUS server. */ 158 kmem_free(data, MAX_RAD_PACKET_LEN); 159 return (-1); 160 } 161 } 162 163 /* 164 * See radius_packet.h. 165 */ 166 int 167 iscsit_rcv_radius_response(void *socket, uint8_t *shared_secret, 168 uint32_t shared_secret_len, uint8_t *req_authenticator, 169 radius_packet_data_t *resp_data) 170 { 171 radius_packet_t *packet; 172 MD5_CTX context; 173 uint8_t *tmp_data; 174 uint8_t md5_digest[16]; /* MD5 Digest Length 16 */ 175 uint16_t declared_len = 0; 176 size_t received_len = 0; 177 178 struct iovec iov[1]; 179 struct nmsghdr msg; 180 struct sonode *so = (struct sonode *)socket; 181 int ret = 0; 182 183 tmp_data = kmem_zalloc(MAX_RAD_PACKET_LEN, KM_SLEEP); 184 iov[0].iov_base = (char *)tmp_data; 185 iov[0].iov_len = MAX_RAD_PACKET_LEN; 186 187 bzero(&msg, sizeof (msg)); 188 msg.msg_name = NULL; 189 msg.msg_namelen = 0; 190 msg.msg_control = NULL; 191 msg.msg_controllen = 0; 192 msg.msg_flags = MSG_WAITALL; 193 msg.msg_iov = iov; 194 msg.msg_iovlen = 1; 195 196 (void) VOP_IOCTL(SOTOV(so), I_POP, 0, FKIOCTL, CRED(), &ret, NULL); 197 if (ret != 0) { 198 return (RAD_RSP_RCVD_NO_DATA); 199 } 200 201 received_len = iscsit_net_recvmsg(socket, &msg, RAD_RCV_TIMEOUT); 202 203 if (received_len <= (size_t)0) { 204 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 205 return (RAD_RSP_RCVD_NO_DATA); 206 } 207 208 /* 209 * Check if the received packet length is within allowable range. 210 * RFC 2865 section 3. 211 */ 212 if (received_len < MIN_RAD_PACKET_LEN) { 213 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 214 return (RAD_RSP_RCVD_PROTOCOL_ERR); 215 } else if (received_len > MAX_RAD_PACKET_LEN) { 216 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 217 return (RAD_RSP_RCVD_PROTOCOL_ERR); 218 } 219 220 packet = (radius_packet_t *)tmp_data; 221 bcopy(packet->length, &declared_len, sizeof (ushort_t)); 222 declared_len = ntohs(declared_len); 223 224 /* 225 * Discard packet with received length shorter than declared 226 * length. RFC 2865 section 3. 227 */ 228 if (received_len < declared_len) { 229 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 230 return (RAD_RSP_RCVD_PROTOCOL_ERR); 231 } 232 233 /* 234 * Check if the declared packet length is within allowable range. 235 * RFC 2865 section 3. 236 */ 237 if (declared_len < MIN_RAD_PACKET_LEN) { 238 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 239 return (RAD_RSP_RCVD_PROTOCOL_ERR); 240 } else if (declared_len > MAX_RAD_PACKET_LEN) { 241 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 242 return (RAD_RSP_RCVD_PROTOCOL_ERR); 243 } 244 245 /* 246 * Authenticate the incoming packet, using the following algorithm 247 * (RFC 2865 section 3): 248 * 249 * MD5(Code+ID+Length+RequestAuth+Attributes+Secret) 250 * 251 * Code = RADIUS packet code 252 * ID = RADIUS packet identifier 253 * Length = Declared length of the packet 254 * RequestAuth = The request authenticator 255 * Attributes = The response attributes 256 * Secret = The shared secret 257 */ 258 MD5Init(&context); 259 bzero(&md5_digest, 16); 260 MD5Update(&context, &packet->code, 1); 261 MD5Update(&context, &packet->identifier, 1); 262 MD5Update(&context, packet->length, 2); 263 MD5Update(&context, req_authenticator, RAD_AUTHENTICATOR_LEN); 264 265 /* 266 * Include response attributes only if there is a payload 267 * If the received length is greater than the declared length, 268 * trust the declared length and shorten the packet (i.e., to 269 * treat the octets outside the range of the Length field as 270 * padding - RFC 2865 section 3). 271 */ 272 if (declared_len > RAD_PACKET_HDR_LEN) { 273 /* Response Attributes */ 274 MD5Update(&context, packet->data, 275 declared_len - RAD_PACKET_HDR_LEN); 276 } 277 MD5Update(&context, shared_secret, shared_secret_len); 278 MD5Final(md5_digest, &context); 279 280 if (bcmp(md5_digest, packet->authenticator, RAD_AUTHENTICATOR_LEN) 281 != 0) { 282 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 283 return (RAD_RSP_RCVD_AUTH_FAILED); 284 } 285 286 /* 287 * Annotate the RADIUS packet data with the data we received from 288 * the server. 289 */ 290 resp_data->code = packet->code; 291 resp_data->identifier = packet->identifier; 292 293 kmem_free(tmp_data, MAX_RAD_PACKET_LEN); 294 return (RAD_RSP_RCVD_SUCCESS); 295 } 296 297 /* 298 * encode_chap_password - 299 * 300 * Encode a CHAP-Password attribute. This function basically prepends 301 * the identifier in front of chap_passwd and copy the results to 302 * *result. 303 */ 304 static void 305 encode_chap_password(int identifier, int chap_passwd_len, 306 uint8_t *chap_passwd, uint8_t *result) 307 { 308 result[0] = (uint8_t)identifier; 309 bcopy(chap_passwd, &result[1], chap_passwd_len); 310 } 311 /* 312 * iscsi_net_recvmsg - receive message on socket 313 */ 314 /* ARGSUSED */ 315 static size_t 316 iscsit_net_recvmsg(void *socket, struct msghdr *msg, int timeout) 317 { 318 int idx; 319 int total_len = 0; 320 struct uio uio; 321 uchar_t pri = 0; 322 int prflag = MSG_ANY; 323 rval_t rval; 324 struct sonode *sonode = (struct sonode *)socket; 325 326 /* Initialization of the uio structure. */ 327 bzero(&uio, sizeof (uio)); 328 uio.uio_iov = msg->msg_iov; 329 uio.uio_iovcnt = msg->msg_iovlen; 330 uio.uio_segflg = UIO_SYSSPACE; 331 332 for (idx = 0; idx < msg->msg_iovlen; idx++) { 333 total_len += (msg->msg_iov)[idx].iov_len; 334 } 335 uio.uio_resid = total_len; 336 337 /* If timeout requested on receive */ 338 if (timeout > 0) { 339 boolean_t loopback = B_FALSE; 340 /* And this isn't a loopback connection */ 341 if (sonode->so_laddr.soa_sa->sa_family == AF_INET) { 342 struct sockaddr_in *lin = (struct sockaddr_in *) 343 ((void *)sonode->so_laddr.soa_sa); 344 struct sockaddr_in *fin = (struct sockaddr_in *) 345 ((void *)sonode->so_faddr.soa_sa); 346 347 if ((lin->sin_family == fin->sin_family) && 348 (bcmp(&lin->sin_addr, &fin->sin_addr, 349 sizeof (struct in_addr)) == 0)) { 350 loopback = B_TRUE; 351 } 352 } else { 353 struct sockaddr_in6 *lin6 = (struct sockaddr_in6 *) 354 ((void *)sonode->so_laddr.soa_sa); 355 struct sockaddr_in6 *fin6 = (struct sockaddr_in6 *) 356 ((void *)sonode->so_faddr.soa_sa); 357 358 if ((lin6->sin6_family == fin6->sin6_family) && 359 (bcmp(&lin6->sin6_addr, &fin6->sin6_addr, 360 sizeof (struct in6_addr)) == 0)) { 361 loopback = B_TRUE; 362 } 363 } 364 365 if (loopback == B_FALSE) { 366 /* 367 * Then poll device for up to the timeout 368 * period or the requested data is received. 369 */ 370 if (kstrgetmsg(SOTOV(sonode), 371 NULL, NULL, &pri, &prflag, timeout * 1000, 372 &rval) == ETIME) { 373 return (0); 374 } 375 } 376 } 377 378 /* 379 * Receive the requested data. Block until all 380 * data is received. 381 * 382 * resid occurs only when the connection is 383 * disconnected. In that case it will return 384 * the amount of data that was not received. 385 * In general this is the total amount we 386 * requested. 387 */ 388 (void) sorecvmsg((struct sonode *)socket, msg, &uio); 389 return (total_len - uio.uio_resid); 390 } 391