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 /* 22fcf3ce44SJohn Forte * Copyright 2000 by Cisco Systems, Inc. All rights reserved. 23*1a1a84a3SPeter Dunlap * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24fcf3ce44SJohn Forte * Use is subject to license terms. 25fcf3ce44SJohn Forte * 26fcf3ce44SJohn Forte * iSCSI Pseudo HBA Driver 27fcf3ce44SJohn Forte */ 28fcf3ce44SJohn Forte 29fcf3ce44SJohn Forte #include <sys/random.h> 30fcf3ce44SJohn Forte 31fcf3ce44SJohn Forte #include "chap.h" 32fcf3ce44SJohn Forte #include "iscsi.h" 33*1a1a84a3SPeter Dunlap #include <sys/iscsi_protocol.h> 34fcf3ce44SJohn Forte #include "iscsiAuthClient.h" 35fcf3ce44SJohn Forte #include "persistent.h" 36fcf3ce44SJohn Forte 37fcf3ce44SJohn Forte /* 38fcf3ce44SJohn Forte * Authenticate a target's CHAP response. 39fcf3ce44SJohn Forte * 40fcf3ce44SJohn Forte * username - Incoming username from the the target. 41fcf3ce44SJohn Forte * responseData - Incoming response data from the target. 42fcf3ce44SJohn Forte */ 43fcf3ce44SJohn Forte int 44fcf3ce44SJohn Forte iscsiAuthClientChapAuthRequest(IscsiAuthClient *client, 45fcf3ce44SJohn Forte char *username, unsigned int id, uchar_t *challengeData, 46fcf3ce44SJohn Forte unsigned int challengeLength, uchar_t *responseData, 47fcf3ce44SJohn Forte unsigned int responseLength) 48fcf3ce44SJohn Forte { 49fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)client->userHandle; 50fcf3ce44SJohn Forte IscsiAuthMd5Context context; 51fcf3ce44SJohn Forte uchar_t verifyData[16]; 52fcf3ce44SJohn Forte iscsi_radius_props_t p_radius_cfg; 53fcf3ce44SJohn Forte 54fcf3ce44SJohn Forte if (isp == NULL) { 55fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 56fcf3ce44SJohn Forte } 57fcf3ce44SJohn Forte 58fcf3ce44SJohn Forte /* 59fcf3ce44SJohn Forte * the expected credentials are in the session 60fcf3ce44SJohn Forte */ 61fcf3ce44SJohn Forte if (isp->sess_auth.username_in == NULL) { 62fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) failed authentication, " 63fcf3ce44SJohn Forte "no incoming username configured to authenticate target", 64fcf3ce44SJohn Forte isp->sess_oid); 65fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 66fcf3ce44SJohn Forte } 67fcf3ce44SJohn Forte if (strcmp(username, isp->sess_auth.username_in) != 0) { 68fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) failed authentication, " 69fcf3ce44SJohn Forte "received incorrect username from target", 70fcf3ce44SJohn Forte isp->sess_oid); 71fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 72fcf3ce44SJohn Forte } 73fcf3ce44SJohn Forte 74fcf3ce44SJohn Forte /* Check if RADIUS access is enabled */ 75fcf3ce44SJohn Forte if (persistent_radius_get(&p_radius_cfg) == ISCSI_NVFILE_SUCCESS && 76fcf3ce44SJohn Forte p_radius_cfg.r_radius_access == B_TRUE) { 77fcf3ce44SJohn Forte chap_validation_status_type chap_valid_status; 78fcf3ce44SJohn Forte int authStatus; 79fcf3ce44SJohn Forte RADIUS_CONFIG radius_cfg; 80fcf3ce44SJohn Forte 81fcf3ce44SJohn Forte if (p_radius_cfg.r_radius_config_valid == B_FALSE) { 82fcf3ce44SJohn Forte /* 83fcf3ce44SJohn Forte * Radius enabled but configuration invalid - 84fcf3ce44SJohn Forte * invalid condition 85fcf3ce44SJohn Forte */ 86fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 87fcf3ce44SJohn Forte } 88fcf3ce44SJohn Forte 89fcf3ce44SJohn Forte /* Use RADIUS server to authentication target */ 90fcf3ce44SJohn Forte if (p_radius_cfg.r_insize == sizeof (in_addr_t)) { 91fcf3ce44SJohn Forte /* IPv4 */ 92fcf3ce44SJohn Forte radius_cfg.rad_svr_addr.i_addr.in4.s_addr = 93fcf3ce44SJohn Forte p_radius_cfg.r_addr.u_in4.s_addr; 94fcf3ce44SJohn Forte radius_cfg.rad_svr_addr.i_insize 95fcf3ce44SJohn Forte = sizeof (in_addr_t); 96fcf3ce44SJohn Forte } else if (p_radius_cfg.r_insize == sizeof (in6_addr_t)) { 97fcf3ce44SJohn Forte /* IPv6 */ 98fcf3ce44SJohn Forte bcopy(p_radius_cfg.r_addr.u_in6.s6_addr, 99fcf3ce44SJohn Forte radius_cfg.rad_svr_addr.i_addr.in6.s6_addr, 100fcf3ce44SJohn Forte 16); 101fcf3ce44SJohn Forte radius_cfg.rad_svr_addr.i_insize = sizeof (in6_addr_t); 102fcf3ce44SJohn Forte } else { 103fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 104fcf3ce44SJohn Forte } 105fcf3ce44SJohn Forte 106fcf3ce44SJohn Forte radius_cfg.rad_svr_port = p_radius_cfg.r_port; 107fcf3ce44SJohn Forte bcopy(p_radius_cfg.r_shared_secret, 108fcf3ce44SJohn Forte radius_cfg.rad_svr_shared_secret, 109fcf3ce44SJohn Forte MAX_RAD_SHARED_SECRET_LEN); 110fcf3ce44SJohn Forte radius_cfg.rad_svr_shared_secret_len = 111fcf3ce44SJohn Forte p_radius_cfg.r_shared_secret_len; 112fcf3ce44SJohn Forte 113fcf3ce44SJohn Forte /* Entry point to the CHAP authentication module. */ 114fcf3ce44SJohn Forte chap_valid_status = chap_validate(isp->sess_auth.username_in, 115fcf3ce44SJohn Forte isp->sess_auth.username, challengeData, responseData, 116fcf3ce44SJohn Forte id, RADIUS_AUTHENTICATION, (void *)&radius_cfg); 117fcf3ce44SJohn Forte 118fcf3ce44SJohn Forte switch (chap_valid_status) { 119fcf3ce44SJohn Forte case CHAP_VALIDATION_PASSED: 120fcf3ce44SJohn Forte authStatus = iscsiAuthStatusPass; 121fcf3ce44SJohn Forte break; 122fcf3ce44SJohn Forte case CHAP_VALIDATION_INVALID_RESPONSE: 123fcf3ce44SJohn Forte authStatus = iscsiAuthStatusFail; 124fcf3ce44SJohn Forte break; 125fcf3ce44SJohn Forte case CHAP_VALIDATION_DUP_SECRET: 126fcf3ce44SJohn Forte authStatus = iscsiAuthStatusFail; 127fcf3ce44SJohn Forte break; 128fcf3ce44SJohn Forte case CHAP_VALIDATION_RADIUS_ACCESS_ERROR: 129fcf3ce44SJohn Forte authStatus = iscsiAuthStatusFail; 130fcf3ce44SJohn Forte break; 131fcf3ce44SJohn Forte case CHAP_VALIDATION_BAD_RADIUS_SECRET: 132fcf3ce44SJohn Forte authStatus = iscsiAuthStatusFail; 133fcf3ce44SJohn Forte break; 134fcf3ce44SJohn Forte default: 135fcf3ce44SJohn Forte authStatus = iscsiAuthStatusFail; 136fcf3ce44SJohn Forte break; 137fcf3ce44SJohn Forte } 138fcf3ce44SJohn Forte return (authStatus); 139fcf3ce44SJohn Forte } else { 140fcf3ce44SJohn Forte /* Use target secret (if defined) to authenticate target */ 141fcf3ce44SJohn Forte if ((isp->sess_auth.password_length_in < 1) || 142fcf3ce44SJohn Forte (isp->sess_auth.password_in == NULL) || 143fcf3ce44SJohn Forte (isp->sess_auth.password_in[0] == '\0')) { 144fcf3ce44SJohn Forte /* No target secret defined - invalid condition */ 145fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 146fcf3ce44SJohn Forte } 147fcf3ce44SJohn Forte 148fcf3ce44SJohn Forte /* 149fcf3ce44SJohn Forte * challenge length is I->T, and shouldn't need to 150fcf3ce44SJohn Forte * be checked 151fcf3ce44SJohn Forte */ 152fcf3ce44SJohn Forte if (responseLength != sizeof (verifyData)) { 153fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) failed " 154fcf3ce44SJohn Forte "authentication, received incorrect CHAP response " 155fcf3ce44SJohn Forte "from target", isp->sess_oid); 156fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 157fcf3ce44SJohn Forte } 158fcf3ce44SJohn Forte 159fcf3ce44SJohn Forte iscsiAuthMd5Init(&context); 160fcf3ce44SJohn Forte 161fcf3ce44SJohn Forte /* 162fcf3ce44SJohn Forte * id byte 163fcf3ce44SJohn Forte */ 164fcf3ce44SJohn Forte verifyData[0] = id; 165fcf3ce44SJohn Forte iscsiAuthMd5Update(&context, verifyData, 1); 166fcf3ce44SJohn Forte 167fcf3ce44SJohn Forte /* 168fcf3ce44SJohn Forte * shared secret 169fcf3ce44SJohn Forte */ 170fcf3ce44SJohn Forte iscsiAuthMd5Update(&context, 171fcf3ce44SJohn Forte (uchar_t *)isp->sess_auth.password_in, 172fcf3ce44SJohn Forte isp->sess_auth.password_length_in); 173fcf3ce44SJohn Forte 174fcf3ce44SJohn Forte /* 175fcf3ce44SJohn Forte * challenge value 176fcf3ce44SJohn Forte */ 177fcf3ce44SJohn Forte iscsiAuthMd5Update(&context, 178fcf3ce44SJohn Forte (uchar_t *)challengeData, 179fcf3ce44SJohn Forte challengeLength); 180fcf3ce44SJohn Forte 181fcf3ce44SJohn Forte iscsiAuthMd5Final(verifyData, &context); 182fcf3ce44SJohn Forte 183fcf3ce44SJohn Forte if (bcmp(responseData, verifyData, 184fcf3ce44SJohn Forte sizeof (verifyData)) == 0) { 185fcf3ce44SJohn Forte return (iscsiAuthStatusPass); 186fcf3ce44SJohn Forte } 187fcf3ce44SJohn Forte 188fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) failed authentication, " 189fcf3ce44SJohn Forte "received incorrect CHAP response from target", 190fcf3ce44SJohn Forte isp->sess_oid); 191fcf3ce44SJohn Forte } 192fcf3ce44SJohn Forte 193fcf3ce44SJohn Forte return (iscsiAuthStatusFail); 194fcf3ce44SJohn Forte } 195fcf3ce44SJohn Forte 196fcf3ce44SJohn Forte /* ARGSUSED */ 197fcf3ce44SJohn Forte void 198fcf3ce44SJohn Forte iscsiAuthClientChapAuthCancel(IscsiAuthClient * client) 199fcf3ce44SJohn Forte { 200fcf3ce44SJohn Forte } 201fcf3ce44SJohn Forte 202fcf3ce44SJohn Forte 203fcf3ce44SJohn Forte int 204fcf3ce44SJohn Forte iscsiAuthClientTextToNumber(const char *text, unsigned long *pNumber) 205fcf3ce44SJohn Forte { 206fcf3ce44SJohn Forte char *pEnd; 207fcf3ce44SJohn Forte unsigned long number; 208fcf3ce44SJohn Forte 209fcf3ce44SJohn Forte if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) { 210fcf3ce44SJohn Forte if (ddi_strtoul(text + 2, &pEnd, 16, &number) != 0) { 211fcf3ce44SJohn Forte return (1); /* Error */ 212fcf3ce44SJohn Forte } 213fcf3ce44SJohn Forte } else { 214fcf3ce44SJohn Forte if (ddi_strtoul(text, &pEnd, 10, &number) != 0) { 215fcf3ce44SJohn Forte return (1); /* Error */ 216fcf3ce44SJohn Forte } 217fcf3ce44SJohn Forte } 218fcf3ce44SJohn Forte 219fcf3ce44SJohn Forte if (*text != '\0' && *pEnd == '\0') { 220fcf3ce44SJohn Forte *pNumber = number; 221fcf3ce44SJohn Forte return (0); /* No error */ 222fcf3ce44SJohn Forte } else { 223fcf3ce44SJohn Forte return (1); /* Error */ 224fcf3ce44SJohn Forte } 225fcf3ce44SJohn Forte } 226fcf3ce44SJohn Forte 227fcf3ce44SJohn Forte /* ARGSUSED */ 228fcf3ce44SJohn Forte void 229fcf3ce44SJohn Forte iscsiAuthClientNumberToText(unsigned long number, char *text, 230fcf3ce44SJohn Forte unsigned int length) 231fcf3ce44SJohn Forte { 232fcf3ce44SJohn Forte (void) sprintf(text, "%lu", number); 233fcf3ce44SJohn Forte } 234fcf3ce44SJohn Forte 235fcf3ce44SJohn Forte 236fcf3ce44SJohn Forte void 237fcf3ce44SJohn Forte iscsiAuthRandomSetData(uchar_t *data, unsigned int length) 238fcf3ce44SJohn Forte { 239fcf3ce44SJohn Forte (void) random_get_pseudo_bytes(data, length); 240fcf3ce44SJohn Forte } 241fcf3ce44SJohn Forte 242fcf3ce44SJohn Forte 243fcf3ce44SJohn Forte void 244fcf3ce44SJohn Forte iscsiAuthMd5Init(IscsiAuthMd5Context * context) 245fcf3ce44SJohn Forte { 246fcf3ce44SJohn Forte MD5Init(context); 247fcf3ce44SJohn Forte } 248fcf3ce44SJohn Forte 249fcf3ce44SJohn Forte 250fcf3ce44SJohn Forte void 251fcf3ce44SJohn Forte iscsiAuthMd5Update(IscsiAuthMd5Context *context, uchar_t *data, 252fcf3ce44SJohn Forte unsigned int length) 253fcf3ce44SJohn Forte { 254fcf3ce44SJohn Forte MD5Update(context, data, length); 255fcf3ce44SJohn Forte } 256fcf3ce44SJohn Forte 257fcf3ce44SJohn Forte 258fcf3ce44SJohn Forte void 259fcf3ce44SJohn Forte iscsiAuthMd5Final(uchar_t *hash, IscsiAuthMd5Context *context) 260fcf3ce44SJohn Forte { 261fcf3ce44SJohn Forte MD5Final(hash, context); 262fcf3ce44SJohn Forte } 263fcf3ce44SJohn Forte 264fcf3ce44SJohn Forte 265fcf3ce44SJohn Forte int 266fcf3ce44SJohn Forte iscsiAuthClientData(uchar_t *outData, unsigned int *outLength, 267fcf3ce44SJohn Forte uchar_t *inData, unsigned int inLength) 268fcf3ce44SJohn Forte { 269fcf3ce44SJohn Forte if (*outLength < inLength) { 270fcf3ce44SJohn Forte return (1); /* error */ 271fcf3ce44SJohn Forte } 272fcf3ce44SJohn Forte bcopy(inData, outData, inLength); 273fcf3ce44SJohn Forte *outLength = inLength; 274fcf3ce44SJohn Forte return (0); /* no error */ 275fcf3ce44SJohn Forte } 276