1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte * CDDL HEADER START
3fcf3ce44SJohn Forte *
4fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte *
8fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte * and limitations under the License.
12fcf3ce44SJohn Forte *
13fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte *
19fcf3ce44SJohn Forte * CDDL HEADER END
20fcf3ce44SJohn Forte */
21fcf3ce44SJohn Forte /*
22*5df5713fSbing zhao - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23fcf3ce44SJohn Forte * Use is subject to license terms.
24fcf3ce44SJohn Forte */
25fcf3ce44SJohn Forte
26fcf3ce44SJohn Forte #include "iscsi.h"
27fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_if.h>
28fcf3ce44SJohn Forte #include "radius_packet.h"
29fcf3ce44SJohn Forte #include "radius_protocol.h"
30fcf3ce44SJohn Forte #include <sys/int_types.h>
31fcf3ce44SJohn Forte #include <sys/socket.h>
32fcf3ce44SJohn Forte #include <sys/types.h>
33fcf3ce44SJohn Forte #include <sys/sunddi.h>
34fcf3ce44SJohn Forte
35fcf3ce44SJohn Forte static void encode_chap_password(int identifier, int chap_passwd_len,
36fcf3ce44SJohn Forte uint8_t *chap_passwd, uint8_t *result);
37fcf3ce44SJohn Forte
38fcf3ce44SJohn Forte /*
39fcf3ce44SJohn Forte * See radius_packet.h.
40fcf3ce44SJohn Forte */
41fcf3ce44SJohn Forte int
snd_radius_request(void * socket,iscsi_ipaddr_t rsvr_ip_addr,uint32_t rsvr_port,radius_packet_data_t * req_data)42fcf3ce44SJohn Forte snd_radius_request(void *socket, iscsi_ipaddr_t rsvr_ip_addr,
43fcf3ce44SJohn Forte uint32_t rsvr_port, radius_packet_data_t *req_data)
44fcf3ce44SJohn Forte {
45fcf3ce44SJohn Forte int i; /* Loop counter. */
46fcf3ce44SJohn Forte int data_len;
47fcf3ce44SJohn Forte int len;
48fcf3ce44SJohn Forte ushort_t total_length; /* Has to be 2 octets in size */
49fcf3ce44SJohn Forte uint8_t *ptr; /* Pointer to RADIUS packet data */
50fcf3ce44SJohn Forte uint8_t *length_ptr; /* Points to the Length field of the */
51fcf3ce44SJohn Forte /* packet. */
52fcf3ce44SJohn Forte uint8_t *data; /* RADIUS data to be sent */
53fcf3ce44SJohn Forte radius_attr_t *req_attr; /* Request attributes */
54fcf3ce44SJohn Forte radius_packet_t *packet; /* Outbound RADIUS packet */
55fcf3ce44SJohn Forte union {
56fcf3ce44SJohn Forte struct sockaddr_in s_in4;
57fcf3ce44SJohn Forte struct sockaddr_in6 s_in6;
58fcf3ce44SJohn Forte } sa_rsvr; /* Socket address of the server */
59fcf3ce44SJohn Forte struct nmsghdr msg;
60fcf3ce44SJohn Forte struct iovec iov[1];
61fcf3ce44SJohn Forte
62fcf3ce44SJohn Forte /*
63fcf3ce44SJohn Forte * Create a RADIUS packet with minimal length for now.
64fcf3ce44SJohn Forte */
65fcf3ce44SJohn Forte total_length = MIN_RAD_PACKET_LEN;
66fcf3ce44SJohn Forte data = kmem_zalloc(MAX_RAD_PACKET_LEN, KM_SLEEP);
67fcf3ce44SJohn Forte packet = (radius_packet_t *)data;
68fcf3ce44SJohn Forte packet->code = req_data->code;
69fcf3ce44SJohn Forte packet->identifier = req_data->identifier;
70fcf3ce44SJohn Forte bcopy(req_data->authenticator, packet->authenticator,
71fcf3ce44SJohn Forte RAD_AUTHENTICATOR_LEN);
72fcf3ce44SJohn Forte ptr = packet->data;
73fcf3ce44SJohn Forte
74fcf3ce44SJohn Forte /* Loop over all attributes of the request. */
75fcf3ce44SJohn Forte for (i = 0; i < req_data->num_of_attrs; i++) {
76fcf3ce44SJohn Forte if (total_length > MAX_RAD_PACKET_LEN) {
77fcf3ce44SJohn Forte /* The packet has exceed its maximum size. */
78fcf3ce44SJohn Forte kmem_free(data, MAX_RAD_PACKET_LEN);
79fcf3ce44SJohn Forte return (-1);
80fcf3ce44SJohn Forte }
81fcf3ce44SJohn Forte
82fcf3ce44SJohn Forte req_attr = &req_data->attrs[i];
83fcf3ce44SJohn Forte *ptr++ = (req_attr->attr_type_code & 0xFF);
84fcf3ce44SJohn Forte length_ptr = ptr;
85fcf3ce44SJohn Forte /* Length is 2 octets - RFC 2865 section 3 */
86fcf3ce44SJohn Forte *ptr++ = 2;
87fcf3ce44SJohn Forte total_length += 2;
88fcf3ce44SJohn Forte
89fcf3ce44SJohn Forte /* If the attribute is CHAP-Password, encode it. */
90fcf3ce44SJohn Forte if (req_attr->attr_type_code == RAD_CHAP_PASSWORD) {
91fcf3ce44SJohn Forte /*
92fcf3ce44SJohn Forte * Identifier plus CHAP response. RFC 2865
93fcf3ce44SJohn Forte * section 5.3.
94fcf3ce44SJohn Forte */
95fcf3ce44SJohn Forte uint8_t encoded_chap_passwd[RAD_CHAP_PASSWD_STR_LEN +
96fcf3ce44SJohn Forte RAD_IDENTIFIER_LEN + 1];
97fcf3ce44SJohn Forte encode_chap_password
98fcf3ce44SJohn Forte (req_data->identifier,
99fcf3ce44SJohn Forte req_attr->attr_value_len,
100fcf3ce44SJohn Forte req_attr->attr_value,
101fcf3ce44SJohn Forte encoded_chap_passwd);
102fcf3ce44SJohn Forte
103fcf3ce44SJohn Forte req_attr->attr_value_len = RAD_CHAP_PASSWD_STR_LEN +
104fcf3ce44SJohn Forte RAD_IDENTIFIER_LEN;
105fcf3ce44SJohn Forte
106fcf3ce44SJohn Forte bcopy(encoded_chap_passwd,
107fcf3ce44SJohn Forte req_attr->attr_value,
108fcf3ce44SJohn Forte req_attr->attr_value_len);
109fcf3ce44SJohn Forte }
110fcf3ce44SJohn Forte
111fcf3ce44SJohn Forte len = req_attr->attr_value_len;
112fcf3ce44SJohn Forte *length_ptr += len;
113fcf3ce44SJohn Forte
114fcf3ce44SJohn Forte bcopy(req_attr->attr_value, ptr, req_attr->attr_value_len);
115fcf3ce44SJohn Forte ptr += req_attr->attr_value_len;
116fcf3ce44SJohn Forte
117fcf3ce44SJohn Forte total_length += len;
118fcf3ce44SJohn Forte } /* Done looping over all attributes */
119fcf3ce44SJohn Forte
120fcf3ce44SJohn Forte data_len = total_length;
121fcf3ce44SJohn Forte total_length = htons(total_length);
122fcf3ce44SJohn Forte bcopy(&total_length, packet->length, sizeof (ushort_t));
123fcf3ce44SJohn Forte
124fcf3ce44SJohn Forte /*
125fcf3ce44SJohn Forte * Send the packet to the RADIUS server.
126fcf3ce44SJohn Forte */
127fcf3ce44SJohn Forte bzero((char *)&sa_rsvr, sizeof (sa_rsvr));
128fcf3ce44SJohn Forte if (rsvr_ip_addr.i_insize == sizeof (in_addr_t)) {
129fcf3ce44SJohn Forte int recv_len;
130fcf3ce44SJohn Forte
131fcf3ce44SJohn Forte /* IPv4 */
132fcf3ce44SJohn Forte sa_rsvr.s_in4.sin_family = AF_INET;
133fcf3ce44SJohn Forte sa_rsvr.s_in4.sin_addr.s_addr =
134fcf3ce44SJohn Forte rsvr_ip_addr.i_addr.in4.s_addr;
135fcf3ce44SJohn Forte sa_rsvr.s_in4.sin_port = htons((ushort_t)rsvr_port);
136fcf3ce44SJohn Forte
137fcf3ce44SJohn Forte iov[0].iov_base = (char *)data;
138fcf3ce44SJohn Forte iov[0].iov_len = data_len;
139fcf3ce44SJohn Forte
140fcf3ce44SJohn Forte bzero(&msg, sizeof (msg));
141fcf3ce44SJohn Forte msg.msg_name = (struct sockaddr *)&sa_rsvr.s_in4;
142fcf3ce44SJohn Forte msg.msg_namelen = sizeof (struct sockaddr_in);
143fcf3ce44SJohn Forte msg.msg_iov = iov;
144fcf3ce44SJohn Forte msg.msg_iovlen = 1;
145fcf3ce44SJohn Forte
146fcf3ce44SJohn Forte recv_len = iscsi_net->sendmsg(socket, &msg);
147fcf3ce44SJohn Forte kmem_free(data, MAX_RAD_PACKET_LEN);
148fcf3ce44SJohn Forte return (recv_len == data_len ? 0 : -1);
149fcf3ce44SJohn Forte } else if (rsvr_ip_addr.i_insize == sizeof (in6_addr_t)) {
150fcf3ce44SJohn Forte /* No IPv6 support for now. */
151fcf3ce44SJohn Forte return (-1);
152fcf3ce44SJohn Forte } else {
153fcf3ce44SJohn Forte /* Invalid IP address for RADIUS server. */
154fcf3ce44SJohn Forte kmem_free(data, MAX_RAD_PACKET_LEN);
155fcf3ce44SJohn Forte return (-1);
156fcf3ce44SJohn Forte }
157fcf3ce44SJohn Forte }
158fcf3ce44SJohn Forte
159fcf3ce44SJohn Forte /*
160fcf3ce44SJohn Forte * See radius_packet.h.
161fcf3ce44SJohn Forte */
162fcf3ce44SJohn Forte int
rcv_radius_response(void * socket,uint8_t * shared_secret,uint32_t shared_secret_len,uint8_t * req_authenticator,radius_packet_data_t * resp_data)163fcf3ce44SJohn Forte rcv_radius_response(void *socket, uint8_t *shared_secret,
164fcf3ce44SJohn Forte uint32_t shared_secret_len, uint8_t *req_authenticator,
165fcf3ce44SJohn Forte radius_packet_data_t *resp_data)
166fcf3ce44SJohn Forte {
167fcf3ce44SJohn Forte int rcv_len = 0;
168fcf3ce44SJohn Forte radius_packet_t *packet;
169fcf3ce44SJohn Forte MD5_CTX context;
170fcf3ce44SJohn Forte uint8_t *tmp_data;
171fcf3ce44SJohn Forte uint8_t md5_digest[16]; /* MD5 Digest Length 16 */
172fcf3ce44SJohn Forte uint16_t declared_len = 0;
173fcf3ce44SJohn Forte ushort_t len;
174fcf3ce44SJohn Forte struct nmsghdr msg;
175fcf3ce44SJohn Forte struct iovec iov[1];
176fcf3ce44SJohn Forte
177fcf3ce44SJohn Forte tmp_data = kmem_zalloc(MAX_RAD_PACKET_LEN, KM_SLEEP);
178fcf3ce44SJohn Forte
179fcf3ce44SJohn Forte iov[0].iov_base = (char *)tmp_data;
180fcf3ce44SJohn Forte iov[0].iov_len = MAX_RAD_PACKET_LEN;
181fcf3ce44SJohn Forte
182fcf3ce44SJohn Forte bzero(&msg, sizeof (msg));
183fcf3ce44SJohn Forte msg.msg_name = NULL;
184fcf3ce44SJohn Forte msg.msg_namelen = 0;
185fcf3ce44SJohn Forte msg.msg_control = NULL;
186fcf3ce44SJohn Forte msg.msg_controllen = 0;
187fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL;
188fcf3ce44SJohn Forte msg.msg_iov = iov;
189fcf3ce44SJohn Forte msg.msg_iovlen = 1;
190fcf3ce44SJohn Forte
191fcf3ce44SJohn Forte rcv_len = iscsi_net->recvmsg(socket, &msg, RAD_RCV_TIMEOUT);
192fcf3ce44SJohn Forte if (rcv_len == 0) {
193fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
194fcf3ce44SJohn Forte return (RAD_RSP_RCVD_NO_DATA);
195fcf3ce44SJohn Forte }
196fcf3ce44SJohn Forte
197fcf3ce44SJohn Forte DTRACE_PROBE1(rcv_rad_resp_summary, int, rcv_len);
198fcf3ce44SJohn Forte
199fcf3ce44SJohn Forte packet = (radius_packet_t *)tmp_data;
200fcf3ce44SJohn Forte bcopy(packet->length, &len, sizeof (ushort_t));
201fcf3ce44SJohn Forte declared_len = ntohs(len);
202fcf3ce44SJohn Forte
203fcf3ce44SJohn Forte DTRACE_PROBE1(rcv_rad_resp_data, uint16_t, declared_len);
204fcf3ce44SJohn Forte
205fcf3ce44SJohn Forte /*
206fcf3ce44SJohn Forte * Check if the received packet length is within allowable range.
207fcf3ce44SJohn Forte * RFC 2865 section 3.
208fcf3ce44SJohn Forte */
209fcf3ce44SJohn Forte if (rcv_len < MIN_RAD_PACKET_LEN) {
210fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
211fcf3ce44SJohn Forte return (RAD_RSP_RCVD_PROTOCOL_ERR);
212fcf3ce44SJohn Forte } else if (rcv_len > MAX_RAD_PACKET_LEN) {
213fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
214fcf3ce44SJohn Forte return (RAD_RSP_RCVD_PROTOCOL_ERR);
215fcf3ce44SJohn Forte }
216fcf3ce44SJohn Forte
217fcf3ce44SJohn Forte /*
218fcf3ce44SJohn Forte * Check if the declared packet length is within allowable range.
219fcf3ce44SJohn Forte * RFC 2865 section 3.
220fcf3ce44SJohn Forte */
221fcf3ce44SJohn Forte if (declared_len < MIN_RAD_PACKET_LEN) {
222fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
223fcf3ce44SJohn Forte return (RAD_RSP_RCVD_PROTOCOL_ERR);
224fcf3ce44SJohn Forte } else if (declared_len > MAX_RAD_PACKET_LEN) {
225fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
226fcf3ce44SJohn Forte return (RAD_RSP_RCVD_PROTOCOL_ERR);
227fcf3ce44SJohn Forte }
228fcf3ce44SJohn Forte
229fcf3ce44SJohn Forte /*
230fcf3ce44SJohn Forte * Discard packet with received length shorter than declared
231fcf3ce44SJohn Forte * length. RFC 2865 section 3.
232fcf3ce44SJohn Forte */
233fcf3ce44SJohn Forte if (rcv_len < declared_len) {
234fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
235fcf3ce44SJohn Forte return (RAD_RSP_RCVD_PROTOCOL_ERR);
236fcf3ce44SJohn Forte }
237fcf3ce44SJohn Forte
238fcf3ce44SJohn Forte /*
239fcf3ce44SJohn Forte * Authenticate the incoming packet, using the following algorithm
240fcf3ce44SJohn Forte * (RFC 2865 section 3):
241fcf3ce44SJohn Forte *
242fcf3ce44SJohn Forte * MD5(Code+ID+Length+RequestAuth+Attributes+Secret)
243fcf3ce44SJohn Forte *
244fcf3ce44SJohn Forte * Code = RADIUS packet code
245fcf3ce44SJohn Forte * ID = RADIUS packet identifier
246fcf3ce44SJohn Forte * Length = Declared length of the packet
247fcf3ce44SJohn Forte * RequestAuth = The request authenticator
248fcf3ce44SJohn Forte * Attributes = The response attributes
249fcf3ce44SJohn Forte * Secret = The shared secret
250fcf3ce44SJohn Forte */
251fcf3ce44SJohn Forte MD5Init(&context);
252fcf3ce44SJohn Forte bzero(&md5_digest, 16);
253fcf3ce44SJohn Forte MD5Update(&context, &packet->code, 1);
254fcf3ce44SJohn Forte MD5Update(&context, &packet->identifier, 1);
255fcf3ce44SJohn Forte MD5Update(&context, packet->length, 2);
256fcf3ce44SJohn Forte MD5Update(&context, req_authenticator, RAD_AUTHENTICATOR_LEN);
257fcf3ce44SJohn Forte /* Include response attributes only if there is a payload */
258fcf3ce44SJohn Forte if (declared_len > RAD_PACKET_HDR_LEN) {
259fcf3ce44SJohn Forte /* Response Attributes */
260fcf3ce44SJohn Forte MD5Update(&context, packet->data,
261fcf3ce44SJohn Forte declared_len - RAD_PACKET_HDR_LEN);
262fcf3ce44SJohn Forte }
263fcf3ce44SJohn Forte MD5Update(&context, shared_secret, shared_secret_len);
264fcf3ce44SJohn Forte MD5Final(md5_digest, &context);
265fcf3ce44SJohn Forte
266fcf3ce44SJohn Forte if (bcmp(md5_digest, packet->authenticator, RAD_AUTHENTICATOR_LEN)
267fcf3ce44SJohn Forte != 0) {
268fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
269fcf3ce44SJohn Forte return (RAD_RSP_RCVD_AUTH_FAILED);
270fcf3ce44SJohn Forte }
271fcf3ce44SJohn Forte
272fcf3ce44SJohn Forte /*
273fcf3ce44SJohn Forte * If the received length is greater than the declared length,
274fcf3ce44SJohn Forte * trust the declared length and shorten the packet (i.e., to
275fcf3ce44SJohn Forte * treat the octets outside the range of the Length field as
276fcf3ce44SJohn Forte * padding - RFC 2865 section 3).
277fcf3ce44SJohn Forte */
278fcf3ce44SJohn Forte if (rcv_len > declared_len) {
279fcf3ce44SJohn Forte /* Clear the padding data. */
280fcf3ce44SJohn Forte bzero(tmp_data + declared_len, rcv_len - declared_len);
281fcf3ce44SJohn Forte rcv_len = declared_len;
282fcf3ce44SJohn Forte }
283fcf3ce44SJohn Forte
284fcf3ce44SJohn Forte /*
285fcf3ce44SJohn Forte * Annotate the RADIUS packet data with the data we received from
286fcf3ce44SJohn Forte * the server.
287fcf3ce44SJohn Forte */
288fcf3ce44SJohn Forte resp_data->code = packet->code;
289fcf3ce44SJohn Forte resp_data->identifier = packet->identifier;
290fcf3ce44SJohn Forte
291fcf3ce44SJohn Forte kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
292fcf3ce44SJohn Forte return (RAD_RSP_RCVD_SUCCESS);
293fcf3ce44SJohn Forte }
294fcf3ce44SJohn Forte
295fcf3ce44SJohn Forte /*
296fcf3ce44SJohn Forte * encode_chap_password -
297fcf3ce44SJohn Forte *
298fcf3ce44SJohn Forte * Encode a CHAP-Password attribute. This function basically prepends
299fcf3ce44SJohn Forte * the identifier in front of chap_passwd and copy the results to
300fcf3ce44SJohn Forte * *result.
301fcf3ce44SJohn Forte */
302fcf3ce44SJohn Forte static void
encode_chap_password(int identifier,int chap_passwd_len,uint8_t * chap_passwd,uint8_t * result)303fcf3ce44SJohn Forte encode_chap_password(int identifier, int chap_passwd_len,
304fcf3ce44SJohn Forte uint8_t *chap_passwd, uint8_t *result)
305fcf3ce44SJohn Forte {
306fcf3ce44SJohn Forte int i;
307fcf3ce44SJohn Forte uint8_t *p;
308fcf3ce44SJohn Forte uint8_t tmp_result[RAD_CHAP_PASSWD_STR_LEN +
309fcf3ce44SJohn Forte RAD_IDENTIFIER_LEN + 1];
310fcf3ce44SJohn Forte
311fcf3ce44SJohn Forte p = tmp_result;
312fcf3ce44SJohn Forte *p = identifier; /* Identifier is 1 octet */
313fcf3ce44SJohn Forte p++;
314fcf3ce44SJohn Forte for (i = 0; i < chap_passwd_len; i++) {
315fcf3ce44SJohn Forte *p = chap_passwd[i];
316fcf3ce44SJohn Forte p++;
317fcf3ce44SJohn Forte }
318fcf3ce44SJohn Forte
319fcf3ce44SJohn Forte bcopy(tmp_result, result,
320fcf3ce44SJohn Forte RAD_CHAP_PASSWD_STR_LEN + RAD_IDENTIFIER_LEN);
321fcf3ce44SJohn Forte }
322