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