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 <netinet/in.h>
27fcf3ce44SJohn Forte #include <sys/kmem.h>
28fcf3ce44SJohn Forte #include <sys/random.h>
29fcf3ce44SJohn Forte #include <sys/socket.h>
30fcf3ce44SJohn Forte 
31fcf3ce44SJohn Forte #include "chap.h"
32fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_if.h>
33fcf3ce44SJohn Forte #include "iscsi.h"
34fcf3ce44SJohn Forte #include <sys/md5.h>
35fcf3ce44SJohn Forte #include "radius_packet.h"
36fcf3ce44SJohn Forte #include "radius_protocol.h"
37fcf3ce44SJohn Forte #include "radius_auth.h"
38fcf3ce44SJohn Forte 
39fcf3ce44SJohn Forte #include <sys/sunddi.h>
40fcf3ce44SJohn Forte 
41fcf3ce44SJohn Forte /* Forward declaration */
42fcf3ce44SJohn Forte /*
43fcf3ce44SJohn Forte  * Annotate the radius_attr_t objects with authentication data.
44fcf3ce44SJohn Forte  */
45fcf3ce44SJohn Forte static
46fcf3ce44SJohn Forte void
47fcf3ce44SJohn Forte set_radius_attrs(radius_packet_data_t *req,
48fcf3ce44SJohn Forte 	char *target_chap_name,
49fcf3ce44SJohn Forte 	unsigned char *target_response,
50*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint32_t response_length,
51*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint8_t *challenge,
52*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint32_t challenge_length);
53fcf3ce44SJohn Forte 
54fcf3ce44SJohn Forte /*
55fcf3ce44SJohn Forte  * See radius_auth.h.
56fcf3ce44SJohn Forte  */
57fcf3ce44SJohn Forte /* ARGSUSED */
58fcf3ce44SJohn Forte chap_validation_status_type
radius_chap_validate(char * target_chap_name,char * initiator_chap_name,uint8_t * challenge,uint32_t challenge_length,uint8_t * target_response,uint32_t response_length,uint8_t identifier,iscsi_ipaddr_t rad_svr_ip_addr,uint32_t rad_svr_port,uint8_t * rad_svr_shared_secret,uint32_t rad_svr_shared_secret_len)59fcf3ce44SJohn Forte radius_chap_validate(char *target_chap_name,
60fcf3ce44SJohn Forte 	char *initiator_chap_name,
61fcf3ce44SJohn Forte 	uint8_t *challenge,
62*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint32_t challenge_length,
63fcf3ce44SJohn Forte 	uint8_t *target_response,
64*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint32_t response_length,
65fcf3ce44SJohn Forte 	uint8_t identifier,
66fcf3ce44SJohn Forte 	iscsi_ipaddr_t rad_svr_ip_addr,
67fcf3ce44SJohn Forte 	uint32_t rad_svr_port,
68fcf3ce44SJohn Forte 	uint8_t *rad_svr_shared_secret,
69fcf3ce44SJohn Forte 	uint32_t rad_svr_shared_secret_len)
70fcf3ce44SJohn Forte {
71fcf3ce44SJohn Forte 	chap_validation_status_type validation_status;
72fcf3ce44SJohn Forte 	char lbolt[64];
73fcf3ce44SJohn Forte 	int rcv_status;
74fcf3ce44SJohn Forte 	void *socket;
75fcf3ce44SJohn Forte 	radius_packet_data_t req;
76fcf3ce44SJohn Forte 	radius_packet_data_t resp;
77fcf3ce44SJohn Forte 	MD5_CTX context;
78fcf3ce44SJohn Forte 	uint8_t	md5_digest[16];		/* MD5 digest length 16 */
79fcf3ce44SJohn Forte 	uint8_t random_number[16];
80fcf3ce44SJohn Forte 
81fcf3ce44SJohn Forte 	if (rad_svr_shared_secret_len == 0) {
82fcf3ce44SJohn Forte 		/* The secret must not be empty (section 3, RFC 2865) */
83fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "empty RADIUS shared secret");
84fcf3ce44SJohn Forte 		return (CHAP_VALIDATION_BAD_RADIUS_SECRET);
85fcf3ce44SJohn Forte 	}
86fcf3ce44SJohn Forte 
87fcf3ce44SJohn Forte 	bzero(&req, sizeof (radius_packet_data_t));
88fcf3ce44SJohn Forte 
89fcf3ce44SJohn Forte 	req.identifier = identifier;
90fcf3ce44SJohn Forte 	req.code = RAD_ACCESS_REQ;
91fcf3ce44SJohn Forte 	set_radius_attrs(&req,
92fcf3ce44SJohn Forte 	    target_chap_name,
93fcf3ce44SJohn Forte 	    target_response,
94*5df5713fSbing zhao - Sun Microsystems - Beijing China 	    response_length,
95*5df5713fSbing zhao - Sun Microsystems - Beijing China 	    challenge,
96*5df5713fSbing zhao - Sun Microsystems - Beijing China 	    challenge_length);
97fcf3ce44SJohn Forte 
98fcf3ce44SJohn Forte 	/* Prepare the request authenticator */
99fcf3ce44SJohn Forte 	MD5Init(&context);
100fcf3ce44SJohn Forte 	bzero(&md5_digest, 16);
101fcf3ce44SJohn Forte 	/* First, the shared secret */
102fcf3ce44SJohn Forte 	MD5Update(&context, rad_svr_shared_secret, rad_svr_shared_secret_len);
103fcf3ce44SJohn Forte 	/* Then a unique number - use lbolt plus a random number */
104fcf3ce44SJohn Forte 	bzero(&lbolt, sizeof (lbolt));
105fcf3ce44SJohn Forte 	(void) snprintf(lbolt, sizeof (lbolt), "%lx", ddi_get_lbolt());
106fcf3ce44SJohn Forte 	MD5Update(&context, (uint8_t *)lbolt, strlen(lbolt));
107fcf3ce44SJohn Forte 	bzero(&random_number, sizeof (random_number));
108fcf3ce44SJohn Forte 	(void) random_get_pseudo_bytes(random_number,
109fcf3ce44SJohn Forte 	    sizeof (random_number));
110fcf3ce44SJohn Forte 	MD5Update(&context, random_number, sizeof (random_number));
111fcf3ce44SJohn Forte 	MD5Final(md5_digest, &context);
112fcf3ce44SJohn Forte 	bcopy(md5_digest, &req.authenticator, RAD_AUTHENTICATOR_LEN);
113fcf3ce44SJohn Forte 
114fcf3ce44SJohn Forte 	socket = iscsi_net->socket(AF_INET, SOCK_DGRAM, 0);
115fcf3ce44SJohn Forte 	if (socket == NULL) {
116fcf3ce44SJohn Forte 		/* Error obtaining socket for RADIUS use */
117fcf3ce44SJohn Forte 		return (CHAP_VALIDATION_RADIUS_ACCESS_ERROR);
118fcf3ce44SJohn Forte 	}
119fcf3ce44SJohn Forte 
120fcf3ce44SJohn Forte 	/* Send the authentication access request to the RADIUS server */
121fcf3ce44SJohn Forte 	if (snd_radius_request(socket,
122fcf3ce44SJohn Forte 	    rad_svr_ip_addr,
123fcf3ce44SJohn Forte 	    rad_svr_port,
124fcf3ce44SJohn Forte 	    &req) == -1) {
125fcf3ce44SJohn Forte 		return (CHAP_VALIDATION_RADIUS_ACCESS_ERROR);
126fcf3ce44SJohn Forte 	}
127fcf3ce44SJohn Forte 
128fcf3ce44SJohn Forte 	bzero(&resp, sizeof (radius_packet_data_t));
129fcf3ce44SJohn Forte 	/*  Analyze the response coming through from the same socket. */
130fcf3ce44SJohn Forte 	rcv_status = rcv_radius_response(socket,
131fcf3ce44SJohn Forte 	    rad_svr_shared_secret,
132fcf3ce44SJohn Forte 	    rad_svr_shared_secret_len,
133fcf3ce44SJohn Forte 	    req.authenticator, &resp);
134fcf3ce44SJohn Forte 	if (rcv_status == RAD_RSP_RCVD_SUCCESS) {
135fcf3ce44SJohn Forte 		if (resp.code == RAD_ACCESS_ACPT) {
136fcf3ce44SJohn Forte 			validation_status = CHAP_VALIDATION_PASSED;
137fcf3ce44SJohn Forte 		} else if (resp.code == RAD_ACCESS_REJ) {
138fcf3ce44SJohn Forte 			validation_status = CHAP_VALIDATION_INVALID_RESPONSE;
139fcf3ce44SJohn Forte 		} else {
140fcf3ce44SJohn Forte 			validation_status =
141fcf3ce44SJohn Forte 			    CHAP_VALIDATION_UNKNOWN_RADIUS_CODE;
142fcf3ce44SJohn Forte 		}
143fcf3ce44SJohn Forte 	} else if (rcv_status == RAD_RSP_RCVD_AUTH_FAILED) {
144fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "RADIUS packet authentication failed");
145fcf3ce44SJohn Forte 		validation_status = CHAP_VALIDATION_BAD_RADIUS_SECRET;
146fcf3ce44SJohn Forte 	} else {
147fcf3ce44SJohn Forte 		validation_status = CHAP_VALIDATION_RADIUS_ACCESS_ERROR;
148fcf3ce44SJohn Forte 	}
149fcf3ce44SJohn Forte 
150fcf3ce44SJohn Forte 	iscsi_net->close(socket);
151fcf3ce44SJohn Forte 	return (validation_status);
152fcf3ce44SJohn Forte }
153fcf3ce44SJohn Forte 
154fcf3ce44SJohn Forte /* See forward declaration. */
155fcf3ce44SJohn Forte static void
set_radius_attrs(radius_packet_data_t * req,char * target_chap_name,unsigned char * target_response,uint32_t response_length,uint8_t * challenge,uint32_t challenge_length)156fcf3ce44SJohn Forte set_radius_attrs(radius_packet_data_t *req,
157fcf3ce44SJohn Forte 	char *target_chap_name,
158fcf3ce44SJohn Forte 	unsigned char *target_response,
159*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint32_t response_length,
160*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint8_t *challenge,
161*5df5713fSbing zhao - Sun Microsystems - Beijing China 	uint32_t challenge_length)
162fcf3ce44SJohn Forte {
163fcf3ce44SJohn Forte 	req->attrs[0].attr_type_code = RAD_USER_NAME;
164fcf3ce44SJohn Forte 	(void) strncpy((char *)req->attrs[0].attr_value,
165fcf3ce44SJohn Forte 	    (const char *)target_chap_name,
166fcf3ce44SJohn Forte 	    strlen(target_chap_name));
167fcf3ce44SJohn Forte 	req->attrs[0].attr_value_len = strlen(target_chap_name);
168fcf3ce44SJohn Forte 
169fcf3ce44SJohn Forte 	req->attrs[1].attr_type_code = RAD_CHAP_PASSWORD;
170*5df5713fSbing zhao - Sun Microsystems - Beijing China 	bcopy(target_response,
171*5df5713fSbing zhao - Sun Microsystems - Beijing China 	    (char *)req->attrs[1].attr_value,
172*5df5713fSbing zhao - Sun Microsystems - Beijing China 	    min(response_length, sizeof (req->attrs[1].attr_value)));
173fcf3ce44SJohn Forte 	/* A target response is an MD5 hash thus its length has to be 16. */
174*5df5713fSbing zhao - Sun Microsystems - Beijing China 	req->attrs[1].attr_value_len = response_length;
175fcf3ce44SJohn Forte 
176fcf3ce44SJohn Forte 	req->attrs[2].attr_type_code = RAD_CHAP_CHALLENGE;
177*5df5713fSbing zhao - Sun Microsystems - Beijing China 	bcopy(challenge,
178*5df5713fSbing zhao - Sun Microsystems - Beijing China 	    (char *)req->attrs[2].attr_value,
179*5df5713fSbing zhao - Sun Microsystems - Beijing China 	    min(challenge_length, sizeof (req->attrs[2].attr_value)));
180*5df5713fSbing zhao - Sun Microsystems - Beijing China 	req->attrs[2].attr_value_len = challenge_length;
181fcf3ce44SJohn Forte 
182fcf3ce44SJohn Forte 	/* 3 attributes associated with each RADIUS packet. */
183fcf3ce44SJohn Forte 	req->num_of_attrs = 3;
184fcf3ce44SJohn Forte }
185