dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / kernel / comstar / port / iscsit / iscsit_auth.c
blob5ab5647ad125e51e1f293f8d2fb63d13065c0fc3
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
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>
33 #include <sys/socket.h>
34 #include <sys/strsubr.h>
35 #include <sys/sysmacros.h>
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>
43 #include "iscsit.h"
44 #include "iscsit_auth.h"
46 static kv_status_t
47 iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp,
48 const idm_kv_xlate_t *ikvx);
50 static kv_status_t
51 auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp,
52 const idm_kv_xlate_t *ikvx);
54 static kv_status_t
55 auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp,
56 const idm_kv_xlate_t *ikvx);
58 static kv_status_t
59 auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp,
60 const idm_kv_xlate_t *ikvx);
62 static kv_status_t
63 auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp,
64 const idm_kv_xlate_t *ikvx);
66 static kv_status_t
67 auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp,
68 const idm_kv_xlate_t *ikvx);
70 static kv_status_t
71 auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp,
72 const idm_kv_xlate_t *ikvx);
74 static kv_status_t
75 iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp,
76 const idm_kv_xlate_t *ikvx);
78 static kv_status_t
79 iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp,
80 const idm_kv_xlate_t *ikvx);
82 static kv_status_t
83 auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp,
84 const idm_kv_xlate_t *ikvx);
86 static kv_status_t
87 auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp,
88 const idm_kv_xlate_t *ikvx);
90 static kv_status_t
91 iscsit_auth_gen_challenge(iscsit_conn_t *ict);
93 static kv_status_t
94 iscsit_auth_gen_response(iscsit_conn_t *ict);
96 typedef struct {
97 iscsit_auth_phase_t phase;
98 iscsikey_id_t kv_id;
99 iscsit_auth_handler_t handler;
100 } auth_phase_entry_t;
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.
109 static 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 },
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 },
124 /* by target */
125 { AP_AM_UNDECIDED, 0, iscsit_auth_propose },
126 { AP_AM_DECIDED, 0, iscsit_auth_expect_key },
128 { AP_CHAP_A_RCVD, 0, auth_chap_expect_r },
129 { AP_CHAP_R_RCVD, 0, auth_chap_done }
132 typedef struct {
133 iscsit_auth_method_t am_id;
134 char *am_name;
135 } auth_id_name_t;
138 * a table of mapping from the authentication index to name.
140 static 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 */
149 #define ARRAY_LENGTH(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
152 * get the authentication method name for the method id.
154 static const char *
155 am_id_to_name(int id)
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);
165 i ++;
168 return (NULL);
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.
178 iscsit_auth_handler_t
179 iscsit_auth_get_handler(iscsit_auth_client_t *client, iscsikey_id_t kv_id)
181 iscsit_auth_phase_t phase = client->phase;
182 int i;
183 const auth_phase_entry_t *p;
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);
193 i ++;
196 /* No handler can be found, it must be an invalid requst. */
197 return (NULL);
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.
205 static kv_status_t
206 iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp,
207 const idm_kv_xlate_t *ikvx)
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;
222 client->phase = AP_AM_DECIDED;
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);
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;
238 i++;
239 am_id = am_list[i];
241 am_choice = idm_get_next_listvalue(nvp, am_choice);
244 /* none of authentication method is valid */
245 am_id = 0;
246 text = ISCSI_TEXT_REJECT;
248 am_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);
255 return (kvrc);
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.
263 static kv_status_t
264 auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp,
265 const idm_kv_xlate_t *ikvx)
267 iscsit_conn_login_t *lsm = &ict->ict_login_sm;
268 iscsit_auth_client_t *client = &lsm->icl_auth_client;
270 client->negotiatedMethod = AM_CHAP;
271 client->phase = AP_AM_DECIDED;
273 return (auth_chap_select_alg(ict, nvp, ikvx));
277 * Select a CHAP algorithm from a list of values proposed by
278 * initiator and shift the authentication phase to AP_CHAP_A_RCVD.
280 static kv_status_t
281 auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp,
282 const idm_kv_xlate_t *ikvx)
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;
293 client->phase = AP_CHAP_A_RCVD;
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;
306 alg_choice = idm_get_next_listvalue(nvp, alg_choice);
309 /* none of algorithm is selected */
310 alg = 0;
311 text = ISCSI_TEXT_REJECT;
313 alg_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);
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);
332 return (kvrc);
336 * Validate and save the the chap name which is sent by initiator
337 * and shift the authentication phase to AP_CHAP_R_RCVD.
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.
348 /*ARGSUSED*/
349 static kv_status_t
350 auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp,
351 const idm_kv_xlate_t *ikvx)
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;
358 nvrc = nvpair_value_string(nvp, &chap_name);
359 ASSERT(nvrc == 0);
361 client_set_string_data(&client->recvKeyBlock,
362 AKT_CHAP_N,
363 chap_name);
365 client->phase = AP_CHAP_R_RCVD;
367 return (KV_HANDLED);
371 * Validate and save the the chap response which is sent by initiator
372 * and shift the authentication phase to AP_CHAP_R_RCVD.
374 * Note: see function auth_chap_recv_n.
377 /*ARGSUSED*/
378 static kv_status_t
379 auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp,
380 const idm_kv_xlate_t *ikvx)
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;
388 nvrc = nvpair_value_byte_array(nvp, &chap_resp, &len);
389 ASSERT(nvrc == 0);
391 client_set_binary_data(&client->recvKeyBlock,
392 AKT_CHAP_R,
393 chap_resp, len);
395 client->phase = AP_CHAP_R_RCVD;
397 return (KV_HANDLED);
401 * Validate and save the the chap identifier which is sent by initiator
402 * and shift the authentication phase to AP_CHAP_R_RCVD.
404 * Note: see function auth_chap_recv_n.
407 /*ARGSUSED*/
408 static kv_status_t
409 auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp,
410 const idm_kv_xlate_t *ikvx)
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;
417 nvrc = nvpair_value_uint64(nvp, &chap_id);
418 ASSERT(nvrc == 0);
420 client_set_numeric_data(&client->recvKeyBlock,
421 AKT_CHAP_I,
422 chap_id);
424 client->phase = AP_CHAP_R_RCVD;
426 return (KV_HANDLED);
430 * Validate and save the the chap challenge which is sent by initiator
431 * and shift the authentication phase to AP_CHAP_R_RCVD.
433 * Note: see function auth_chap_recv_n.
436 /*ARGSUSED*/
437 static kv_status_t
438 auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp,
439 const idm_kv_xlate_t *ikvx)
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;
447 nvrc = nvpair_value_byte_array(nvp, &chap_challenge, &len);
448 ASSERT(nvrc == 0);
450 client_set_binary_data(
451 &client->recvKeyBlock,
452 AKT_CHAP_C,
453 chap_challenge, len);
455 client->phase = AP_CHAP_R_RCVD;
457 return (KV_HANDLED);
461 * Shift the authentication phase to AP_CHAP_R_WAITING after target
462 * has successfully selected a chap algorithm.
465 /*ARGSUSED*/
466 static kv_status_t
467 auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp,
468 const idm_kv_xlate_t *ikvx)
470 iscsit_conn_login_t *lsm = &ict->ict_login_sm;
471 iscsit_auth_client_t *client = &lsm->icl_auth_client;
473 uint32_t alg;
475 client_get_numeric_data(&client->recvKeyBlock,
476 AKT_CHAP_A,
477 &alg);
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;
486 return (KV_HANDLED);
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.
495 /*ARGSUSED*/
496 static kv_status_t
497 iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp,
498 const idm_kv_xlate_t *ikvx)
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;
505 int nvrc;
506 kv_status_t kvrc;
507 const char *am_name;
509 if (am_list[0] == AM_NONE || am_list[0] == 0) {
510 lsm->icl_auth_pass = 1;
513 if (lsm->icl_auth_pass == 0) {
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.
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);
527 client->phase = AP_AM_PROPOSED;
528 } else {
529 kvrc = KV_HANDLED;
531 client->phase = AP_DONE;
534 return (kvrc);
538 * Shift the authentication phase according to the authentication
539 * method once it is selected.
542 /*ARGSUSED*/
543 static kv_status_t
544 iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp,
545 const idm_kv_xlate_t *ikvx)
547 iscsit_conn_login_t *lsm = &ict->ict_login_sm;
548 iscsit_auth_client_t *client = &lsm->icl_auth_client;
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;
564 } else {
565 /* None of proposed method is supported or understood. */
566 client->phase = AP_AM_UNDECIDED;
569 return (KV_HANDLED);
573 * The last step of the chap authentication. We will validate the
574 * chap parameters we received and authenticate the client here.
577 /*ARGSUSED*/
578 static kv_status_t
579 auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp,
580 const idm_kv_xlate_t *ikvx)
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;
586 conn_auth_t *auth = &lsm->icl_auth;
587 char *username_in;
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;
596 int bi_auth;
598 username_in = auth->ca_ini_chapuser;
599 if (username_in[0] == '\0')
600 return (KV_AUTH_FAILED);
603 * Check if we have received a valid list of response keys.
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);
613 client->phase = AP_DONE;
615 client_get_string_data(&client->recvKeyBlock,
616 AKT_CHAP_N,
617 &chap_name);
619 /* check username */
620 if (strcmp(username_in, chap_name) != 0) {
621 return (KV_AUTH_FAILED);
624 client_get_numeric_data(&client->sendKeyBlock,
625 AKT_CHAP_I,
626 &chap_id);
628 client_get_binary_data(&client->sendKeyBlock,
629 AKT_CHAP_C,
630 &chap_challenge, &challenge_len);
632 client_get_binary_data(&client->recvKeyBlock,
633 AKT_CHAP_R,
634 &chap_resp, &resp_len);
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);
642 /* bi-direction authentication is required */
643 if (bi_auth != 0) {
644 kvrc = iscsit_auth_gen_response(ict);
647 lsm->icl_auth_pass = 1;
649 return (kvrc);
652 static kv_status_t
653 iscsit_auth_gen_challenge(iscsit_conn_t *ict)
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;
660 unsigned char idData[1];
661 unsigned char *bin;
662 int len;
664 auth_random_set_data(idData, 1);
665 client_set_numeric_data(&client->sendKeyBlock,
666 AKT_CHAP_I,
667 idData[0]);
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);
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);
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);
691 return (kvrc);
694 static kv_status_t
695 iscsit_auth_gen_response(iscsit_conn_t *ict)
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;
702 conn_auth_t *auth = &lsm->icl_auth;
703 char *tgt_username;
704 uint8_t *tgt_password;
705 int tgt_password_length;
707 uint32_t chap_id;
708 unsigned char *chap_challenge;
709 unsigned int challenge_len;
710 uchar_t resp[iscsitAuthChapResponseLength];
712 tgt_username = auth->ca_tgt_chapuser;
713 tgt_password = auth->ca_tgt_chapsecret;
714 tgt_password_length = auth->ca_tgt_chapsecretlen;
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.
721 if (tgt_password_length == 0) {
722 return (KV_AUTH_FAILED);
725 client_get_numeric_data(&client->recvKeyBlock,
726 AKT_CHAP_I,
727 &chap_id);
729 client_get_binary_data(&client->recvKeyBlock,
730 AKT_CHAP_C,
731 &chap_challenge, &challenge_len);
733 client_compute_chap_resp(
734 &resp[0],
735 chap_id,
736 tgt_password, tgt_password_length,
737 chap_challenge, challenge_len);
739 nvrc = nvlist_add_string(
740 lsm->icl_response_nvlist,
741 "CHAP_N", tgt_username);
743 if (nvrc == 0) {
744 nvrc = nvlist_add_byte_array(
745 lsm->icl_response_nvlist,
746 "CHAP_R", resp, sizeof (resp));
748 kvrc = idm_nvstat_to_kvstat(nvrc);
750 return (kvrc);