1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#include <sys/cpuvar.h>
26#include <sys/types.h>
27#include <sys/conf.h>
28#include <sys/file.h>
29#include <sys/ddi.h>
30#include <sys/sunddi.h>
31#include <sys/modctl.h>
32
33#include <sys/socket.h>
34#include <sys/strsubr.h>
35#include <sys/sysmacros.h>
36
37#include <sys/stmf.h>
38#include <sys/stmf_ioctl.h>
39#include <sys/portif.h>
40#include <sys/idm/idm.h>
41#include <sys/idm/idm_text.h>
42
43#include "iscsit.h"
44#include "iscsit_auth.h"
45
46static kv_status_t
47iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp,
48    const idm_kv_xlate_t *ikvx);
49
50static kv_status_t
51auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp,
52    const idm_kv_xlate_t *ikvx);
53
54static kv_status_t
55auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp,
56    const idm_kv_xlate_t *ikvx);
57
58static kv_status_t
59auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp,
60    const idm_kv_xlate_t *ikvx);
61
62static kv_status_t
63auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp,
64    const idm_kv_xlate_t *ikvx);
65
66static kv_status_t
67auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp,
68    const idm_kv_xlate_t *ikvx);
69
70static kv_status_t
71auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp,
72    const idm_kv_xlate_t *ikvx);
73
74static kv_status_t
75iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp,
76    const idm_kv_xlate_t *ikvx);
77
78static kv_status_t
79iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp,
80    const idm_kv_xlate_t *ikvx);
81
82static kv_status_t
83auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp,
84    const idm_kv_xlate_t *ikvx);
85
86static kv_status_t
87auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp,
88    const idm_kv_xlate_t *ikvx);
89
90static kv_status_t
91iscsit_auth_gen_challenge(iscsit_conn_t *ict);
92
93static kv_status_t
94iscsit_auth_gen_response(iscsit_conn_t *ict);
95
96typedef struct {
97	iscsit_auth_phase_t	phase;
98	iscsikey_id_t		kv_id;
99	iscsit_auth_handler_t	handler;
100} auth_phase_entry_t;
101
102/*
103 * This table defines all authentication phases which have valid
104 * handler. The entries which have a non-zero key index are for
105 * a key/value pair handling when a key/value is being received,
106 * the rest of entries are for target checking the authentication
107 * phase after all key/value pair(s) are handled.
108 */
109static const auth_phase_entry_t	apet[] = {
110	/* by key */
111	{ AP_AM_UNDECIDED,	KI_AUTH_METHOD,	iscsit_select_auth },
112	{ AP_AM_PROPOSED,	KI_CHAP_A,	auth_propose_chap  },
113
114	{ AP_CHAP_A_WAITING,	KI_CHAP_A,	auth_chap_select_alg },
115	{ AP_CHAP_R_WAITING,	KI_CHAP_N,	auth_chap_recv_n },
116	{ AP_CHAP_R_WAITING,	KI_CHAP_R,	auth_chap_recv_r },
117	{ AP_CHAP_R_WAITING,	KI_CHAP_I,	auth_chap_recv_i },
118	{ AP_CHAP_R_WAITING,	KI_CHAP_C,	auth_chap_recv_c },
119	{ AP_CHAP_R_RCVD,	KI_CHAP_N,	auth_chap_recv_n },
120	{ AP_CHAP_R_RCVD,	KI_CHAP_R,	auth_chap_recv_r },
121	{ AP_CHAP_R_RCVD,	KI_CHAP_I,	auth_chap_recv_i },
122	{ AP_CHAP_R_RCVD,	KI_CHAP_C,	auth_chap_recv_c },
123
124	/* by target */
125	{ AP_AM_UNDECIDED,	0,		iscsit_auth_propose },
126	{ AP_AM_DECIDED,	0,		iscsit_auth_expect_key },
127
128	{ AP_CHAP_A_RCVD,	0,		auth_chap_expect_r },
129	{ AP_CHAP_R_RCVD,	0,		auth_chap_done }
130};
131
132typedef struct {
133	iscsit_auth_method_t	am_id;
134	char			*am_name;
135} auth_id_name_t;
136
137/*
138 * a table of mapping from the authentication index to name.
139 */
140static const auth_id_name_t aint[] = {
141	{ AM_CHAP,	"CHAP" },
142	{ AM_NONE,	"None" },
143	/* { AM_KRB5,	"KRB5" }, */	/* Not supported */
144	/* { AM_SPKM1,	"SPKM1" }, */	/* Not supported */
145	/* { AM_SPKM2,	"SPKM2" }, */	/* Not supported */
146	/* { AM_SRP,	"SRP" },  */	/* Not supported */
147};
148
149#define	ARRAY_LENGTH(ARRAY)	(sizeof (ARRAY) / sizeof (ARRAY[0]))
150
151/*
152 * get the authentication method name for the method id.
153 */
154static const char *
155am_id_to_name(int id)
156{
157	int			i;
158	const auth_id_name_t	*p;
159	i = 0;
160	while (i < ARRAY_LENGTH(aint)) {
161		p = &(aint[i]);
162		if (id == p->am_id) {
163			return (p->am_name);
164		}
165		i ++;
166	}
167
168	return (NULL);
169}
170
171/*
172 * Look for an apporiate function handler which is defined for
173 * current authentication phase and matches the key which is
174 * being handled. The key index is passed in as zero when it
175 * is looking for an handler for checking the authentication phase
176 * after all security keys are handled.
177 */
178iscsit_auth_handler_t
179iscsit_auth_get_handler(iscsit_auth_client_t *client, iscsikey_id_t kv_id)
180{
181	iscsit_auth_phase_t		phase = client->phase;
182	int				i;
183	const auth_phase_entry_t	*p;
184
185	i = 0;
186	p = NULL;
187	while (i < ARRAY_LENGTH(apet)) {
188		p = &(apet[i]);
189		if (phase == p->phase &&
190		    kv_id == p->kv_id) {
191			return (p->handler);
192		}
193		i ++;
194	}
195
196	/* No handler can be found, it must be an invalid requst. */
197	return (NULL);
198}
199
200/*
201 * Select an authentication method from a list of values proposed
202 * by initiator. After a valid method is selected, shift the
203 * authentication phase to AP_AM_DECIDED.
204 */
205static kv_status_t
206iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp,
207    const idm_kv_xlate_t *ikvx)
208{
209	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
210	conn_auth_t		*auth = &lsm->icl_auth;
211	iscsit_auth_method_t	*am_list = &auth->ca_method_valid_list[0];
212	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
213	int			nvrc;
214	kv_status_t		kvrc;
215	nvpair_t		*am_choice;
216	char			*am;
217	const char		*am_name;
218	const char		*text;
219	iscsit_auth_method_t	am_id;
220	int			i;
221
222	client->phase = AP_AM_DECIDED;
223
224	/* select a valid authentication method */
225	am_choice = idm_get_next_listvalue(nvp, NULL);
226	while (am_choice != NULL) {
227		nvrc = nvpair_value_string(am_choice, &am);
228		ASSERT(nvrc == 0);
229
230		i = 0;
231		am_id = am_list[i];
232		while (am_id != 0) {
233			am_name = am_id_to_name(am_id);
234			if (strcasecmp(am, am_name) == 0) {
235				text = am;
236				goto am_decided;
237			}
238			i++;
239			am_id = am_list[i];
240		}
241		am_choice = idm_get_next_listvalue(nvp, am_choice);
242	}
243
244	/* none of authentication method is valid */
245	am_id = 0;
246	text = ISCSI_TEXT_REJECT;
247
248am_decided:
249	client->negotiatedMethod = am_id;
250	/* add the selected method to the response nvlist */
251	nvrc = nvlist_add_string(lsm->icl_response_nvlist,
252	    ikvx->ik_key_name, text);
253	kvrc = idm_nvstat_to_kvstat(nvrc);
254
255	return (kvrc);
256}
257
258/*
259 * Initiator chooses to use CHAP after target proposed a list of
260 * authentication method. Set the authentication method to CHAP and
261 * continue on chap authentication phase.
262 */
263static kv_status_t
264auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp,
265    const idm_kv_xlate_t *ikvx)
266{
267	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
268	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
269
270	client->negotiatedMethod = AM_CHAP;
271	client->phase = AP_AM_DECIDED;
272
273	return (auth_chap_select_alg(ict, nvp, ikvx));
274}
275
276/*
277 * Select a CHAP algorithm from a list of values proposed by
278 * initiator and shift the authentication phase to AP_CHAP_A_RCVD.
279 */
280static kv_status_t
281auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp,
282    const idm_kv_xlate_t *ikvx)
283{
284	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
285	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
286	int			nvrc, rc;
287	kv_status_t		kvrc;
288	nvpair_t		*alg_choice;
289	char			*alg_string;
290	uint64_t		alg;
291	const char		*text;
292
293	client->phase = AP_CHAP_A_RCVD;
294
295	alg_choice = idm_get_next_listvalue(nvp, NULL);
296	while (alg_choice != NULL) {
297		nvrc = nvpair_value_string(alg_choice, &alg_string);
298		ASSERT(nvrc == 0);
299		rc = ddi_strtoull(alg_string, NULL, 0, (u_longlong_t *)&alg);
300		if (rc == 0 && alg == 5) {
301			/* only MD5 is supported */
302			text = alg_string;
303			goto alg_selected;
304		}
305
306		alg_choice = idm_get_next_listvalue(nvp, alg_choice);
307	}
308
309	/* none of algorithm is selected */
310	alg = 0;
311	text = ISCSI_TEXT_REJECT;
312
313alg_selected:
314	/* save the selected algorithm or zero for none is selected */
315	client_set_numeric_data(
316	    &client->recvKeyBlock,
317	    AKT_CHAP_A,
318	    (uint32_t)alg);
319
320	/* add the selected algorithm to the response nvlist */
321	nvrc = nvlist_add_string(lsm->icl_response_nvlist,
322	    ikvx->ik_key_name, text);
323	if (alg == 0) {
324		kvrc = KV_AUTH_FAILED; /* No algorithm selected */
325	} else {
326		kvrc = idm_nvstat_to_kvstat(nvrc);
327		if (kvrc == 0) {
328			kvrc = iscsit_auth_gen_challenge(ict);
329		}
330	}
331
332	return (kvrc);
333}
334
335/*
336 * Validate and save the the chap name which is sent by initiator
337 * and shift the authentication phase to AP_CHAP_R_RCVD.
338 *
339 * Note: the CHAP_N, CHAP_R, optionally CHAP_I and CHAP_C key/value
340 * pairs need to be received in one packet, we handle each of them
341 * separately, in order to track the authentication phase, we set
342 * the authentication phase to AP_CHAP_R_RCVD once one of them is
343 * handled. So both of AP_CHAP_R_WAITING and AP_CHAP_R_RCVD phases
344 * are valid for these keys. The function auth_chap_done is going
345 * to detect if any of these keys is missing.
346 */
347
348/*ARGSUSED*/
349static kv_status_t
350auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp,
351    const idm_kv_xlate_t *ikvx)
352{
353	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
354	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
355	int			nvrc;
356	char			*chap_name;
357
358	nvrc = nvpair_value_string(nvp, &chap_name);
359	ASSERT(nvrc == 0);
360
361	client_set_string_data(&client->recvKeyBlock,
362	    AKT_CHAP_N,
363	    chap_name);
364
365	client->phase = AP_CHAP_R_RCVD;
366
367	return (KV_HANDLED);
368}
369
370/*
371 * Validate and save the the chap response which is sent by initiator
372 * and shift the authentication phase to AP_CHAP_R_RCVD.
373 *
374 * Note: see function auth_chap_recv_n.
375 */
376
377/*ARGSUSED*/
378static kv_status_t
379auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp,
380    const idm_kv_xlate_t *ikvx)
381{
382	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
383	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
384	int			nvrc;
385	unsigned char		*chap_resp;
386	uint_t			len;
387
388	nvrc = nvpair_value_byte_array(nvp, &chap_resp, &len);
389	ASSERT(nvrc == 0);
390
391	client_set_binary_data(&client->recvKeyBlock,
392	    AKT_CHAP_R,
393	    chap_resp, len);
394
395	client->phase = AP_CHAP_R_RCVD;
396
397	return (KV_HANDLED);
398}
399
400/*
401 * Validate and save the the chap identifier which is sent by initiator
402 * and shift the authentication phase to AP_CHAP_R_RCVD.
403 *
404 * Note: see function auth_chap_recv_n.
405 */
406
407/*ARGSUSED*/
408static kv_status_t
409auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp,
410    const idm_kv_xlate_t *ikvx)
411{
412	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
413	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
414	int			nvrc;
415	uint64_t		chap_id;
416
417	nvrc = nvpair_value_uint64(nvp, &chap_id);
418	ASSERT(nvrc == 0);
419
420	client_set_numeric_data(&client->recvKeyBlock,
421	    AKT_CHAP_I,
422	    chap_id);
423
424	client->phase = AP_CHAP_R_RCVD;
425
426	return (KV_HANDLED);
427}
428
429/*
430 * Validate and save the the chap challenge which is sent by initiator
431 * and shift the authentication phase to AP_CHAP_R_RCVD.
432 *
433 * Note: see function auth_chap_recv_n.
434 */
435
436/*ARGSUSED*/
437static kv_status_t
438auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp,
439    const idm_kv_xlate_t *ikvx)
440{
441	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
442	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
443	int			nvrc;
444	unsigned char		*chap_challenge;
445	uint_t			len;
446
447	nvrc = nvpair_value_byte_array(nvp, &chap_challenge, &len);
448	ASSERT(nvrc == 0);
449
450	client_set_binary_data(
451	    &client->recvKeyBlock,
452	    AKT_CHAP_C,
453	    chap_challenge, len);
454
455	client->phase = AP_CHAP_R_RCVD;
456
457	return (KV_HANDLED);
458}
459
460/*
461 * Shift the authentication phase to AP_CHAP_R_WAITING after target
462 * has successfully selected a chap algorithm.
463 */
464
465/*ARGSUSED*/
466static kv_status_t
467auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp,
468    const idm_kv_xlate_t *ikvx)
469{
470	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
471	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
472
473	uint32_t		alg;
474
475	client_get_numeric_data(&client->recvKeyBlock,
476	    AKT_CHAP_A,
477	    &alg);
478
479	if (alg != 0) {
480		client->phase = AP_CHAP_R_WAITING;
481	} else {
482		/* none of proposed algorithm is supported or understood. */
483		client->phase = AP_CHAP_A_WAITING;
484	}
485
486	return (KV_HANDLED);
487}
488
489/*
490 * Initiator does not propose security negotiation, target needs to
491 * verify if we can bypass the security negotiation phase or propose
492 * a security negotiation for the initiator.
493 */
494
495/*ARGSUSED*/
496static kv_status_t
497iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp,
498    const idm_kv_xlate_t *ikvx)
499{
500	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
501	conn_auth_t		*auth = &lsm->icl_auth;
502	iscsit_auth_method_t	*am_list = &auth->ca_method_valid_list[0];
503	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
504
505	int			nvrc;
506	kv_status_t		kvrc;
507	const char		*am_name;
508
509	if (am_list[0] == AM_NONE || am_list[0] == 0) {
510		lsm->icl_auth_pass = 1;
511	}
512
513	if (lsm->icl_auth_pass == 0) {
514		/*
515		 * It should be noted that the negotiation might also
516		 * be directed by the target if the initiator does
517		 * support security, but is not ready to direct the
518		 * negotiation (propose options).
519		 * - RFC3720 section 5.3.2.
520		 */
521		am_name = am_id_to_name(am_list[0]);
522		nvrc = nvlist_add_string(
523		    lsm->icl_response_nvlist,
524		    "AuthMethod", am_name);
525		kvrc = idm_nvstat_to_kvstat(nvrc);
526
527		client->phase = AP_AM_PROPOSED;
528	} else {
529		kvrc = KV_HANDLED;
530
531		client->phase = AP_DONE;
532	}
533
534	return (kvrc);
535}
536
537/*
538 * Shift the authentication phase according to the authentication
539 * method once it is selected.
540 */
541
542/*ARGSUSED*/
543static kv_status_t
544iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp,
545    const idm_kv_xlate_t *ikvx)
546{
547	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
548	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
549
550	if (client->negotiatedMethod != 0) {
551		/* Shift security negotiation phase. */
552		switch (client->negotiatedMethod) {
553		case AM_CHAP:
554			client->phase = AP_CHAP_A_WAITING;
555			break;
556		case AM_NONE:
557			client->phase = AP_DONE;
558			lsm->icl_auth_pass = 1;
559			break;
560		default:
561			ASSERT(0);
562			break;
563		}
564	} else {
565		/* None of proposed method is supported or understood. */
566		client->phase = AP_AM_UNDECIDED;
567	}
568
569	return (KV_HANDLED);
570}
571
572/*
573 * The last step of the chap authentication. We will validate the
574 * chap parameters we received and authenticate the client here.
575 */
576
577/*ARGSUSED*/
578static kv_status_t
579auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp,
580    const idm_kv_xlate_t *ikvx)
581{
582	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
583	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
584	kv_status_t		kvrc = KV_HANDLED;
585
586	conn_auth_t		*auth = &lsm->icl_auth;
587	char			*username_in;
588
589	uint32_t		chap_id;
590	unsigned char		*chap_challenge;
591	unsigned int		challenge_len;
592	char			*chap_name;
593	unsigned char		*chap_resp;
594	unsigned int		resp_len;
595
596	int			bi_auth;
597
598	username_in = auth->ca_ini_chapuser;
599	if (username_in[0] == '\0')
600		return (KV_AUTH_FAILED);
601
602	/*
603	 * Check if we have received a valid list of response keys.
604	 */
605	if (!client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_N) ||
606	    !client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_R) ||
607	    ((bi_auth =
608	    client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_I)) ^
609	    client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_C))) {
610		return (KV_MISSING_FIELDS);
611	}
612
613	client->phase = AP_DONE;
614
615	client_get_string_data(&client->recvKeyBlock,
616	    AKT_CHAP_N,
617	    &chap_name);
618
619	/* check username */
620	if (strcmp(username_in, chap_name) != 0) {
621		return (KV_AUTH_FAILED);
622	}
623
624	client_get_numeric_data(&client->sendKeyBlock,
625	    AKT_CHAP_I,
626	    &chap_id);
627
628	client_get_binary_data(&client->sendKeyBlock,
629	    AKT_CHAP_C,
630	    &chap_challenge, &challenge_len);
631
632	client_get_binary_data(&client->recvKeyBlock,
633	    AKT_CHAP_R,
634	    &chap_resp, &resp_len);
635
636	if (iscsit_verify_chap_resp(lsm,
637	    chap_id, chap_challenge, challenge_len,
638	    chap_resp, resp_len) != ISCSI_AUTH_PASSED) {
639		return (KV_AUTH_FAILED);
640	}
641
642	/* bi-direction authentication is required */
643	if (bi_auth != 0) {
644		kvrc = iscsit_auth_gen_response(ict);
645	}
646
647	lsm->icl_auth_pass = 1;
648
649	return (kvrc);
650}
651
652static kv_status_t
653iscsit_auth_gen_challenge(iscsit_conn_t *ict)
654{
655	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
656	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
657	int			nvrc;
658	kv_status_t		kvrc;
659
660	unsigned char		idData[1];
661	unsigned char		*bin;
662	int			len;
663
664	auth_random_set_data(idData, 1);
665	client_set_numeric_data(&client->sendKeyBlock,
666	    AKT_CHAP_I,
667	    idData[0]);
668
669	/* send chap identifier */
670	nvrc = nvlist_add_uint64(
671	    lsm->icl_response_nvlist,
672	    "CHAP_I", idData[0]);
673	kvrc = idm_nvstat_to_kvstat(nvrc);
674	if (kvrc != 0) {
675		return (kvrc);
676	}
677
678	bin = &(client->auth_send_binary_block.largeBinary[0]);
679	len = iscsitAuthChapResponseLength;
680	auth_random_set_data(bin, len);
681	client_set_binary_data(&client->sendKeyBlock,
682	    AKT_CHAP_C,
683	    bin, len);
684
685	/* send chap challenge */
686	nvrc = nvlist_add_byte_array(
687	    lsm->icl_response_nvlist,
688	    "CHAP_C", bin, len);
689	kvrc = idm_nvstat_to_kvstat(nvrc);
690
691	return (kvrc);
692}
693
694static kv_status_t
695iscsit_auth_gen_response(iscsit_conn_t *ict)
696{
697	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
698	iscsit_auth_client_t	*client = &lsm->icl_auth_client;
699	int			nvrc;
700	kv_status_t		kvrc;
701
702	conn_auth_t		*auth = &lsm->icl_auth;
703	char			*tgt_username;
704	uint8_t			*tgt_password;
705	int			tgt_password_length;
706
707	uint32_t		chap_id;
708	unsigned char		*chap_challenge;
709	unsigned int		challenge_len;
710	uchar_t			resp[iscsitAuthChapResponseLength];
711
712	tgt_username = auth->ca_tgt_chapuser;
713	tgt_password = auth->ca_tgt_chapsecret;
714	tgt_password_length = auth->ca_tgt_chapsecretlen;
715
716	/*
717	 * We can't know in advance whether the initiator will attempt
718	 * mutual authentication, so now we need to check whether we
719	 * have a target CHAP secret configured.
720	 */
721	if (tgt_password_length == 0) {
722		return (KV_AUTH_FAILED);
723	}
724
725	client_get_numeric_data(&client->recvKeyBlock,
726	    AKT_CHAP_I,
727	    &chap_id);
728
729	client_get_binary_data(&client->recvKeyBlock,
730	    AKT_CHAP_C,
731	    &chap_challenge, &challenge_len);
732
733	client_compute_chap_resp(
734	    &resp[0],
735	    chap_id,
736	    tgt_password, tgt_password_length,
737	    chap_challenge, challenge_len);
738
739	nvrc = nvlist_add_string(
740	    lsm->icl_response_nvlist,
741	    "CHAP_N", tgt_username);
742
743	if (nvrc == 0) {
744		nvrc = nvlist_add_byte_array(
745		    lsm->icl_response_nvlist,
746		    "CHAP_R", resp, sizeof (resp));
747	}
748	kvrc = idm_nvstat_to_kvstat(nvrc);
749
750	return (kvrc);
751}
752