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.
231a1a84a3SPeter 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"
331a1a84a3SPeter 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
iscsiAuthClientChapAuthRequest(IscsiAuthClient * client,char * username,unsigned int id,uchar_t * challengeData,unsigned int challengeLength,uchar_t * responseData,unsigned int responseLength)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. */
114*5df5713fSbing zhao - Sun Microsystems - Beijing China 		chap_valid_status = chap_validate_tgt(
115*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    isp->sess_auth.username_in,
116*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    isp->sess_auth.username,
117*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    challengeData,
118*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    challengeLength,
119*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    responseData,
120*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    responseLength,
121*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    id,
122*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    RADIUS_AUTHENTICATION,
123*5df5713fSbing zhao - Sun Microsystems - Beijing China 		    (void *)&radius_cfg);
124fcf3ce44SJohn Forte 
125fcf3ce44SJohn Forte 		switch (chap_valid_status) {
126fcf3ce44SJohn Forte 			case CHAP_VALIDATION_PASSED:
127fcf3ce44SJohn Forte 				authStatus = iscsiAuthStatusPass;
128fcf3ce44SJohn Forte 				break;
129fcf3ce44SJohn Forte 			case CHAP_VALIDATION_INVALID_RESPONSE:
130fcf3ce44SJohn Forte 				authStatus = iscsiAuthStatusFail;
131fcf3ce44SJohn Forte 				break;
132fcf3ce44SJohn Forte 			case CHAP_VALIDATION_DUP_SECRET:
133fcf3ce44SJohn Forte 				authStatus = iscsiAuthStatusFail;
134fcf3ce44SJohn Forte 				break;
135fcf3ce44SJohn Forte 			case CHAP_VALIDATION_RADIUS_ACCESS_ERROR:
136fcf3ce44SJohn Forte 				authStatus = iscsiAuthStatusFail;
137fcf3ce44SJohn Forte 				break;
138fcf3ce44SJohn Forte 			case CHAP_VALIDATION_BAD_RADIUS_SECRET:
139fcf3ce44SJohn Forte 				authStatus = iscsiAuthStatusFail;
140fcf3ce44SJohn Forte 				break;
141fcf3ce44SJohn Forte 			default:
142fcf3ce44SJohn Forte 				authStatus = iscsiAuthStatusFail;
143fcf3ce44SJohn Forte 				break;
144fcf3ce44SJohn Forte 		}
145fcf3ce44SJohn Forte 		return (authStatus);
146fcf3ce44SJohn Forte 	} else {
147fcf3ce44SJohn Forte 		/* Use target secret (if defined) to authenticate target */
148fcf3ce44SJohn Forte 		if ((isp->sess_auth.password_length_in < 1) ||
149fcf3ce44SJohn Forte 		    (isp->sess_auth.password_in == NULL) ||
150fcf3ce44SJohn Forte 		    (isp->sess_auth.password_in[0] == '\0')) {
151fcf3ce44SJohn Forte 			/* No target secret defined - invalid condition */
152fcf3ce44SJohn Forte 			return (iscsiAuthStatusFail);
153fcf3ce44SJohn Forte 		}
154fcf3ce44SJohn Forte 
155fcf3ce44SJohn Forte 		/*
156fcf3ce44SJohn Forte 		 * challenge length is I->T, and shouldn't need to
157fcf3ce44SJohn Forte 		 * be checked
158fcf3ce44SJohn Forte 		 */
159fcf3ce44SJohn Forte 		if (responseLength != sizeof (verifyData)) {
160fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi session(%u) failed "
161fcf3ce44SJohn Forte 			    "authentication, received incorrect CHAP response "
162fcf3ce44SJohn Forte 			    "from target", isp->sess_oid);
163fcf3ce44SJohn Forte 			return (iscsiAuthStatusFail);
164fcf3ce44SJohn Forte 		}
165fcf3ce44SJohn Forte 
166fcf3ce44SJohn Forte 		iscsiAuthMd5Init(&context);
167fcf3ce44SJohn Forte 
168fcf3ce44SJohn Forte 		/*
169fcf3ce44SJohn Forte 		 * id byte
170fcf3ce44SJohn Forte 		 */
171fcf3ce44SJohn Forte 		verifyData[0] = id;
172fcf3ce44SJohn Forte 		iscsiAuthMd5Update(&context, verifyData, 1);
173fcf3ce44SJohn Forte 
174fcf3ce44SJohn Forte 		/*
175fcf3ce44SJohn Forte 		 * shared secret
176fcf3ce44SJohn Forte 		 */
177fcf3ce44SJohn Forte 		iscsiAuthMd5Update(&context,
178fcf3ce44SJohn Forte 		    (uchar_t *)isp->sess_auth.password_in,
179fcf3ce44SJohn Forte 		    isp->sess_auth.password_length_in);
180fcf3ce44SJohn Forte 
181fcf3ce44SJohn Forte 		/*
182fcf3ce44SJohn Forte 		 * challenge value
183fcf3ce44SJohn Forte 		 */
184fcf3ce44SJohn Forte 		iscsiAuthMd5Update(&context,
185fcf3ce44SJohn Forte 		    (uchar_t *)challengeData,
186fcf3ce44SJohn Forte 		    challengeLength);
187fcf3ce44SJohn Forte 
188fcf3ce44SJohn Forte 		iscsiAuthMd5Final(verifyData, &context);
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte 		if (bcmp(responseData, verifyData,
191fcf3ce44SJohn Forte 		    sizeof (verifyData)) == 0) {
192fcf3ce44SJohn Forte 			return (iscsiAuthStatusPass);
193fcf3ce44SJohn Forte 		}
194fcf3ce44SJohn Forte 
195fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi session(%u) failed authentication, "
196fcf3ce44SJohn Forte 		    "received incorrect CHAP response from target",
197fcf3ce44SJohn Forte 		    isp->sess_oid);
198fcf3ce44SJohn Forte 	}
199fcf3ce44SJohn Forte 
200fcf3ce44SJohn Forte 	return (iscsiAuthStatusFail);
201fcf3ce44SJohn Forte }
202fcf3ce44SJohn Forte 
203fcf3ce44SJohn Forte /* ARGSUSED */
204fcf3ce44SJohn Forte void
iscsiAuthClientChapAuthCancel(IscsiAuthClient * client)205fcf3ce44SJohn Forte iscsiAuthClientChapAuthCancel(IscsiAuthClient * client)
206fcf3ce44SJohn Forte {
207fcf3ce44SJohn Forte }
208fcf3ce44SJohn Forte 
209fcf3ce44SJohn Forte 
210fcf3ce44SJohn Forte int
iscsiAuthClientTextToNumber(const char * text,unsigned long * pNumber)211fcf3ce44SJohn Forte iscsiAuthClientTextToNumber(const char *text, unsigned long *pNumber)
212fcf3ce44SJohn Forte {
213fcf3ce44SJohn Forte 	char *pEnd;
214fcf3ce44SJohn Forte 	unsigned long number;
215fcf3ce44SJohn Forte 
216fcf3ce44SJohn Forte 	if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
217fcf3ce44SJohn Forte 		if (ddi_strtoul(text + 2, &pEnd, 16, &number) != 0) {
218fcf3ce44SJohn Forte 			return (1); /* Error */
219fcf3ce44SJohn Forte 		}
220fcf3ce44SJohn Forte 	} else {
221fcf3ce44SJohn Forte 		if (ddi_strtoul(text, &pEnd, 10, &number) != 0) {
222fcf3ce44SJohn Forte 			return (1); /* Error */
223fcf3ce44SJohn Forte 		}
224fcf3ce44SJohn Forte 	}
225fcf3ce44SJohn Forte 
226fcf3ce44SJohn Forte 	if (*text != '\0' && *pEnd == '\0') {
227fcf3ce44SJohn Forte 		*pNumber = number;
228fcf3ce44SJohn Forte 		return (0);	/* No error */
229fcf3ce44SJohn Forte 	} else {
230fcf3ce44SJohn Forte 		return (1);	/* Error */
231fcf3ce44SJohn Forte 	}
232fcf3ce44SJohn Forte }
233fcf3ce44SJohn Forte 
234fcf3ce44SJohn Forte /* ARGSUSED */
235fcf3ce44SJohn Forte void
iscsiAuthClientNumberToText(unsigned long number,char * text,unsigned int length)236fcf3ce44SJohn Forte iscsiAuthClientNumberToText(unsigned long number, char *text,
237fcf3ce44SJohn Forte     unsigned int length)
238fcf3ce44SJohn Forte {
239fcf3ce44SJohn Forte 	(void) sprintf(text, "%lu", number);
240fcf3ce44SJohn Forte }
241fcf3ce44SJohn Forte 
242fcf3ce44SJohn Forte 
243fcf3ce44SJohn Forte void
iscsiAuthRandomSetData(uchar_t * data,unsigned int length)244fcf3ce44SJohn Forte iscsiAuthRandomSetData(uchar_t *data, unsigned int length)
245fcf3ce44SJohn Forte {
246fcf3ce44SJohn Forte 	(void) random_get_pseudo_bytes(data, length);
247fcf3ce44SJohn Forte }
248fcf3ce44SJohn Forte 
249fcf3ce44SJohn Forte 
250fcf3ce44SJohn Forte void
iscsiAuthMd5Init(IscsiAuthMd5Context * context)251fcf3ce44SJohn Forte iscsiAuthMd5Init(IscsiAuthMd5Context * context)
252fcf3ce44SJohn Forte {
253fcf3ce44SJohn Forte 	MD5Init(context);
254fcf3ce44SJohn Forte }
255fcf3ce44SJohn Forte 
256fcf3ce44SJohn Forte 
257fcf3ce44SJohn Forte void
iscsiAuthMd5Update(IscsiAuthMd5Context * context,uchar_t * data,unsigned int length)258fcf3ce44SJohn Forte iscsiAuthMd5Update(IscsiAuthMd5Context *context, uchar_t *data,
259fcf3ce44SJohn Forte     unsigned int length)
260fcf3ce44SJohn Forte {
261fcf3ce44SJohn Forte 	MD5Update(context, data, length);
262fcf3ce44SJohn Forte }
263fcf3ce44SJohn Forte 
264fcf3ce44SJohn Forte 
265fcf3ce44SJohn Forte void
iscsiAuthMd5Final(uchar_t * hash,IscsiAuthMd5Context * context)266fcf3ce44SJohn Forte iscsiAuthMd5Final(uchar_t *hash, IscsiAuthMd5Context *context)
267fcf3ce44SJohn Forte {
268fcf3ce44SJohn Forte 	MD5Final(hash, context);
269fcf3ce44SJohn Forte }
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 
272fcf3ce44SJohn Forte int
iscsiAuthClientData(uchar_t * outData,unsigned int * outLength,uchar_t * inData,unsigned int inLength)273fcf3ce44SJohn Forte iscsiAuthClientData(uchar_t *outData, unsigned int *outLength,
274fcf3ce44SJohn Forte     uchar_t *inData, unsigned int inLength)
275fcf3ce44SJohn Forte {
276fcf3ce44SJohn Forte 	if (*outLength < inLength) {
277fcf3ce44SJohn Forte 		return (1);	/* error */
278fcf3ce44SJohn Forte 	}
279fcf3ce44SJohn Forte 	bcopy(inData, outData, inLength);
280fcf3ce44SJohn Forte 	*outLength = inLength;
281fcf3ce44SJohn Forte 	return (0);		/* no error */
282fcf3ce44SJohn Forte }
283