xref: /onnv-gate/usr/src/uts/common/io/scsi/adapters/iscsi/radius_auth.c (revision 9414:afbd0f4ab8b4)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*9414SBing.Zhao@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM #include <netinet/in.h>
277836SJohn.Forte@Sun.COM #include <sys/kmem.h>
287836SJohn.Forte@Sun.COM #include <sys/random.h>
297836SJohn.Forte@Sun.COM #include <sys/socket.h>
307836SJohn.Forte@Sun.COM 
317836SJohn.Forte@Sun.COM #include "chap.h"
327836SJohn.Forte@Sun.COM #include <sys/scsi/adapters/iscsi_if.h>
337836SJohn.Forte@Sun.COM #include "iscsi.h"
347836SJohn.Forte@Sun.COM #include <sys/md5.h>
357836SJohn.Forte@Sun.COM #include "radius_packet.h"
367836SJohn.Forte@Sun.COM #include "radius_protocol.h"
377836SJohn.Forte@Sun.COM #include "radius_auth.h"
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM #include <sys/sunddi.h>
407836SJohn.Forte@Sun.COM 
417836SJohn.Forte@Sun.COM /* Forward declaration */
427836SJohn.Forte@Sun.COM /*
437836SJohn.Forte@Sun.COM  * Annotate the radius_attr_t objects with authentication data.
447836SJohn.Forte@Sun.COM  */
457836SJohn.Forte@Sun.COM static
467836SJohn.Forte@Sun.COM void
477836SJohn.Forte@Sun.COM set_radius_attrs(radius_packet_data_t *req,
487836SJohn.Forte@Sun.COM 	char *target_chap_name,
497836SJohn.Forte@Sun.COM 	unsigned char *target_response,
50*9414SBing.Zhao@Sun.COM 	uint32_t response_length,
51*9414SBing.Zhao@Sun.COM 	uint8_t *challenge,
52*9414SBing.Zhao@Sun.COM 	uint32_t challenge_length);
537836SJohn.Forte@Sun.COM 
547836SJohn.Forte@Sun.COM /*
557836SJohn.Forte@Sun.COM  * See radius_auth.h.
567836SJohn.Forte@Sun.COM  */
577836SJohn.Forte@Sun.COM /* ARGSUSED */
587836SJohn.Forte@Sun.COM 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)597836SJohn.Forte@Sun.COM radius_chap_validate(char *target_chap_name,
607836SJohn.Forte@Sun.COM 	char *initiator_chap_name,
617836SJohn.Forte@Sun.COM 	uint8_t *challenge,
62*9414SBing.Zhao@Sun.COM 	uint32_t challenge_length,
637836SJohn.Forte@Sun.COM 	uint8_t *target_response,
64*9414SBing.Zhao@Sun.COM 	uint32_t response_length,
657836SJohn.Forte@Sun.COM 	uint8_t identifier,
667836SJohn.Forte@Sun.COM 	iscsi_ipaddr_t rad_svr_ip_addr,
677836SJohn.Forte@Sun.COM 	uint32_t rad_svr_port,
687836SJohn.Forte@Sun.COM 	uint8_t *rad_svr_shared_secret,
697836SJohn.Forte@Sun.COM 	uint32_t rad_svr_shared_secret_len)
707836SJohn.Forte@Sun.COM {
717836SJohn.Forte@Sun.COM 	chap_validation_status_type validation_status;
727836SJohn.Forte@Sun.COM 	char lbolt[64];
737836SJohn.Forte@Sun.COM 	int rcv_status;
747836SJohn.Forte@Sun.COM 	void *socket;
757836SJohn.Forte@Sun.COM 	radius_packet_data_t req;
767836SJohn.Forte@Sun.COM 	radius_packet_data_t resp;
777836SJohn.Forte@Sun.COM 	MD5_CTX context;
787836SJohn.Forte@Sun.COM 	uint8_t	md5_digest[16];		/* MD5 digest length 16 */
797836SJohn.Forte@Sun.COM 	uint8_t random_number[16];
807836SJohn.Forte@Sun.COM 
817836SJohn.Forte@Sun.COM 	if (rad_svr_shared_secret_len == 0) {
827836SJohn.Forte@Sun.COM 		/* The secret must not be empty (section 3, RFC 2865) */
837836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "empty RADIUS shared secret");
847836SJohn.Forte@Sun.COM 		return (CHAP_VALIDATION_BAD_RADIUS_SECRET);
857836SJohn.Forte@Sun.COM 	}
867836SJohn.Forte@Sun.COM 
877836SJohn.Forte@Sun.COM 	bzero(&req, sizeof (radius_packet_data_t));
887836SJohn.Forte@Sun.COM 
897836SJohn.Forte@Sun.COM 	req.identifier = identifier;
907836SJohn.Forte@Sun.COM 	req.code = RAD_ACCESS_REQ;
917836SJohn.Forte@Sun.COM 	set_radius_attrs(&req,
927836SJohn.Forte@Sun.COM 	    target_chap_name,
937836SJohn.Forte@Sun.COM 	    target_response,
94*9414SBing.Zhao@Sun.COM 	    response_length,
95*9414SBing.Zhao@Sun.COM 	    challenge,
96*9414SBing.Zhao@Sun.COM 	    challenge_length);
977836SJohn.Forte@Sun.COM 
987836SJohn.Forte@Sun.COM 	/* Prepare the request authenticator */
997836SJohn.Forte@Sun.COM 	MD5Init(&context);
1007836SJohn.Forte@Sun.COM 	bzero(&md5_digest, 16);
1017836SJohn.Forte@Sun.COM 	/* First, the shared secret */
1027836SJohn.Forte@Sun.COM 	MD5Update(&context, rad_svr_shared_secret, rad_svr_shared_secret_len);
1037836SJohn.Forte@Sun.COM 	/* Then a unique number - use lbolt plus a random number */
1047836SJohn.Forte@Sun.COM 	bzero(&lbolt, sizeof (lbolt));
1057836SJohn.Forte@Sun.COM 	(void) snprintf(lbolt, sizeof (lbolt), "%lx", ddi_get_lbolt());
1067836SJohn.Forte@Sun.COM 	MD5Update(&context, (uint8_t *)lbolt, strlen(lbolt));
1077836SJohn.Forte@Sun.COM 	bzero(&random_number, sizeof (random_number));
1087836SJohn.Forte@Sun.COM 	(void) random_get_pseudo_bytes(random_number,
1097836SJohn.Forte@Sun.COM 	    sizeof (random_number));
1107836SJohn.Forte@Sun.COM 	MD5Update(&context, random_number, sizeof (random_number));
1117836SJohn.Forte@Sun.COM 	MD5Final(md5_digest, &context);
1127836SJohn.Forte@Sun.COM 	bcopy(md5_digest, &req.authenticator, RAD_AUTHENTICATOR_LEN);
1137836SJohn.Forte@Sun.COM 
1147836SJohn.Forte@Sun.COM 	socket = iscsi_net->socket(AF_INET, SOCK_DGRAM, 0);
1157836SJohn.Forte@Sun.COM 	if (socket == NULL) {
1167836SJohn.Forte@Sun.COM 		/* Error obtaining socket for RADIUS use */
1177836SJohn.Forte@Sun.COM 		return (CHAP_VALIDATION_RADIUS_ACCESS_ERROR);
1187836SJohn.Forte@Sun.COM 	}
1197836SJohn.Forte@Sun.COM 
1207836SJohn.Forte@Sun.COM 	/* Send the authentication access request to the RADIUS server */
1217836SJohn.Forte@Sun.COM 	if (snd_radius_request(socket,
1227836SJohn.Forte@Sun.COM 	    rad_svr_ip_addr,
1237836SJohn.Forte@Sun.COM 	    rad_svr_port,
1247836SJohn.Forte@Sun.COM 	    &req) == -1) {
1257836SJohn.Forte@Sun.COM 		return (CHAP_VALIDATION_RADIUS_ACCESS_ERROR);
1267836SJohn.Forte@Sun.COM 	}
1277836SJohn.Forte@Sun.COM 
1287836SJohn.Forte@Sun.COM 	bzero(&resp, sizeof (radius_packet_data_t));
1297836SJohn.Forte@Sun.COM 	/*  Analyze the response coming through from the same socket. */
1307836SJohn.Forte@Sun.COM 	rcv_status = rcv_radius_response(socket,
1317836SJohn.Forte@Sun.COM 	    rad_svr_shared_secret,
1327836SJohn.Forte@Sun.COM 	    rad_svr_shared_secret_len,
1337836SJohn.Forte@Sun.COM 	    req.authenticator, &resp);
1347836SJohn.Forte@Sun.COM 	if (rcv_status == RAD_RSP_RCVD_SUCCESS) {
1357836SJohn.Forte@Sun.COM 		if (resp.code == RAD_ACCESS_ACPT) {
1367836SJohn.Forte@Sun.COM 			validation_status = CHAP_VALIDATION_PASSED;
1377836SJohn.Forte@Sun.COM 		} else if (resp.code == RAD_ACCESS_REJ) {
1387836SJohn.Forte@Sun.COM 			validation_status = CHAP_VALIDATION_INVALID_RESPONSE;
1397836SJohn.Forte@Sun.COM 		} else {
1407836SJohn.Forte@Sun.COM 			validation_status =
1417836SJohn.Forte@Sun.COM 			    CHAP_VALIDATION_UNKNOWN_RADIUS_CODE;
1427836SJohn.Forte@Sun.COM 		}
1437836SJohn.Forte@Sun.COM 	} else if (rcv_status == RAD_RSP_RCVD_AUTH_FAILED) {
1447836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "RADIUS packet authentication failed");
1457836SJohn.Forte@Sun.COM 		validation_status = CHAP_VALIDATION_BAD_RADIUS_SECRET;
1467836SJohn.Forte@Sun.COM 	} else {
1477836SJohn.Forte@Sun.COM 		validation_status = CHAP_VALIDATION_RADIUS_ACCESS_ERROR;
1487836SJohn.Forte@Sun.COM 	}
1497836SJohn.Forte@Sun.COM 
1507836SJohn.Forte@Sun.COM 	iscsi_net->close(socket);
1517836SJohn.Forte@Sun.COM 	return (validation_status);
1527836SJohn.Forte@Sun.COM }
1537836SJohn.Forte@Sun.COM 
1547836SJohn.Forte@Sun.COM /* See forward declaration. */
1557836SJohn.Forte@Sun.COM 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)1567836SJohn.Forte@Sun.COM set_radius_attrs(radius_packet_data_t *req,
1577836SJohn.Forte@Sun.COM 	char *target_chap_name,
1587836SJohn.Forte@Sun.COM 	unsigned char *target_response,
159*9414SBing.Zhao@Sun.COM 	uint32_t response_length,
160*9414SBing.Zhao@Sun.COM 	uint8_t *challenge,
161*9414SBing.Zhao@Sun.COM 	uint32_t challenge_length)
1627836SJohn.Forte@Sun.COM {
1637836SJohn.Forte@Sun.COM 	req->attrs[0].attr_type_code = RAD_USER_NAME;
1647836SJohn.Forte@Sun.COM 	(void) strncpy((char *)req->attrs[0].attr_value,
1657836SJohn.Forte@Sun.COM 	    (const char *)target_chap_name,
1667836SJohn.Forte@Sun.COM 	    strlen(target_chap_name));
1677836SJohn.Forte@Sun.COM 	req->attrs[0].attr_value_len = strlen(target_chap_name);
1687836SJohn.Forte@Sun.COM 
1697836SJohn.Forte@Sun.COM 	req->attrs[1].attr_type_code = RAD_CHAP_PASSWORD;
170*9414SBing.Zhao@Sun.COM 	bcopy(target_response,
171*9414SBing.Zhao@Sun.COM 	    (char *)req->attrs[1].attr_value,
172*9414SBing.Zhao@Sun.COM 	    min(response_length, sizeof (req->attrs[1].attr_value)));
1737836SJohn.Forte@Sun.COM 	/* A target response is an MD5 hash thus its length has to be 16. */
174*9414SBing.Zhao@Sun.COM 	req->attrs[1].attr_value_len = response_length;
1757836SJohn.Forte@Sun.COM 
1767836SJohn.Forte@Sun.COM 	req->attrs[2].attr_type_code = RAD_CHAP_CHALLENGE;
177*9414SBing.Zhao@Sun.COM 	bcopy(challenge,
178*9414SBing.Zhao@Sun.COM 	    (char *)req->attrs[2].attr_value,
179*9414SBing.Zhao@Sun.COM 	    min(challenge_length, sizeof (req->attrs[2].attr_value)));
180*9414SBing.Zhao@Sun.COM 	req->attrs[2].attr_value_len = challenge_length;
1817836SJohn.Forte@Sun.COM 
1827836SJohn.Forte@Sun.COM 	/* 3 attributes associated with each RADIUS packet. */
1837836SJohn.Forte@Sun.COM 	req->num_of_attrs = 3;
1847836SJohn.Forte@Sun.COM }
185