xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/iscsi/iscsiAuthClient.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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 2000 by Cisco Systems, Inc.  All rights reserved.
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * This file implements the iSCSI CHAP authentication method based.
27  * The code in this file is meant to be platform independent, and
28  * makes use of only limited library functions, presently only string.h.
29  * Platform dependent routines are  defined in iscsiAuthClient.h, but
30  * implemented in another file.
31  *
32  * This code in this files assumes a single thread of execution
33  * for each IscsiAuthClient structure, and does no locking.
34  */
35 
36 #include "iscsi.h"
37 #include "iscsiAuthClient.h"
38 
39 
40 struct iscsiAuthKeyInfo_t {
41 	const char *name;
42 };
43 typedef struct iscsiAuthKeyInfo_t IscsiAuthKeyInfo;
44 
45 
46 IscsiAuthClientGlobalStats iscsiAuthClientGlobalStats;
47 
48 /*
49  * Note: The ordering of this table must match the order
50  *       defined by IscsiAuthKeyType in iscsiAuthClient.h.
51  */
52 static IscsiAuthKeyInfo iscsiAuthClientKeyInfo[iscsiAuthKeyTypeMaxCount] = {
53 	{"AuthMethod"},
54 	{"CHAP_A"},
55 	{"CHAP_N"},
56 	{"CHAP_R"},
57 	{"CHAP_I"},
58 	{"CHAP_C"}
59 };
60 
61 static const char iscsiAuthClientHexString[] = "0123456789abcdefABCDEF";
62 static const char iscsiAuthClientBase64String[] =
63 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64 static const char iscsiAuthClientAuthMethodChapOptionName[] = "CHAP";
65 
66 
67 static int
68 iscsiAuthClientCheckString(const char *s,
69     unsigned int maxLength, unsigned int *pOutLength)
70 {
71 	unsigned int length;
72 
73 	if (!s) {
74 		return (TRUE);
75 	}
76 
77 	for (length = 0; length < maxLength; length++) {
78 		if (*s++ == '\0') {
79 			if (pOutLength) {
80 				*pOutLength = length;
81 			}
82 			return (FALSE);
83 		}
84 	}
85 
86 	return (TRUE);
87 }
88 
89 
90 static int
91 iscsiAuthClientStringCopy(char *stringOut, const char *stringIn,
92     unsigned int length)
93 {
94 	if (!stringOut || !stringIn || length == 0) {
95 		return (TRUE);
96 	}
97 
98 	while ((*stringOut++ = *stringIn++) != '\0') {
99 		if (--length == 0) {
100 			stringOut--;
101 			*stringOut = '\0';
102 			return (TRUE);
103 		}
104 	}
105 
106 	return (FALSE);
107 }
108 
109 
110 static int
111 iscsiAuthClientStringAppend(char *stringOut, const char *stringIn,
112     unsigned int length)
113 {
114 	if (!stringOut || !stringIn || length == 0) {
115 		return (TRUE);
116 	}
117 
118 	while (*stringOut++ != '\0') {
119 		if (--length == 0) {
120 			stringOut--;
121 			*stringOut = '\0';
122 			return (TRUE);
123 		}
124 	}
125 
126 	stringOut--;
127 
128 	while ((*stringOut++ = *stringIn++) != '\0') {
129 		if (--length == 0) {
130 			stringOut--;
131 			*stringOut = '\0';
132 			return (TRUE);
133 		}
134 	}
135 
136 	return (FALSE);
137 }
138 
139 
140 static int
141 iscsiAuthClientStringIndex(const char *s, int c)
142 {
143 	int n = 0;
144 
145 	while (*s != '\0') {
146 		if (*s++ == c) {
147 			return (n);
148 		}
149 		n++;
150 	}
151 
152 	return (-1);
153 }
154 
155 
156 static int
157 iscsiAuthClientCheckNodeType(int nodeType)
158 {
159 	if (nodeType == iscsiAuthNodeTypeInitiator ||
160 	    nodeType == iscsiAuthNodeTypeTarget) {
161 		return (FALSE);
162 	}
163 
164 	return (TRUE);
165 }
166 
167 
168 static int
169 iscsiAuthClientCheckVersion(int value)
170 {
171 	if (value == iscsiAuthVersionDraft8 || value == iscsiAuthVersionRfc) {
172 
173 		return (FALSE);
174 	}
175 
176 	return (TRUE);
177 }
178 
179 
180 static int
181 iscsiAuthClientCheckNegRole(int value)
182 {
183 	if (value == iscsiAuthNegRoleOriginator ||
184 	    value == iscsiAuthNegRoleResponder) {
185 		return (FALSE);
186 	}
187 
188 	return (TRUE);
189 }
190 
191 
192 static int
193 iscsiAuthClientCheckAuthMethodOption(int value)
194 {
195 	if (value == iscsiAuthOptionNone || value == iscsiAuthMethodChap) {
196 
197 		return (FALSE);
198 	}
199 
200 	return (TRUE);
201 }
202 
203 
204 static const char *
205 iscsiAuthClientAuthMethodOptionToText(IscsiAuthClient * client, int value)
206 {
207 	const char *s;
208 
209 	switch (value) {
210 	case iscsiAuthOptionReject:
211 		s = client->rejectOptionName;
212 		break;
213 
214 	case iscsiAuthOptionNone:
215 		s = client->noneOptionName;
216 		break;
217 
218 	case iscsiAuthMethodChap:
219 		s = iscsiAuthClientAuthMethodChapOptionName;
220 		break;
221 
222 	default:
223 		s = 0;
224 	}
225 
226 	return (s);
227 }
228 
229 
230 static int
231 iscsiAuthClientCheckChapAlgorithmOption(int chapAlgorithm)
232 {
233 	if (chapAlgorithm == iscsiAuthOptionNone ||
234 	    chapAlgorithm == iscsiAuthChapAlgorithmMd5) {
235 		return (FALSE);
236 	}
237 
238 	return (TRUE);
239 }
240 
241 
242 static int
243 iscsiAuthClientDataToHex(unsigned char *data, unsigned int dataLength,
244     char *text, unsigned int textLength)
245 {
246 	unsigned long n;
247 
248 	if (!text || textLength == 0) {
249 		return (TRUE);
250 	}
251 
252 	if (!data || dataLength == 0) {
253 		*text = '\0';
254 		return (TRUE);
255 	}
256 
257 	if (textLength < 3) {
258 		*text = '\0';
259 		return (TRUE);
260 	}
261 
262 	*text++ = '0';
263 	*text++ = 'x';
264 
265 	textLength -= 2;
266 
267 	while (dataLength > 0) {
268 
269 		if (textLength < 3) {
270 			*text = '\0';
271 			return (TRUE);
272 		}
273 
274 		n = *data++;
275 		dataLength--;
276 
277 		*text++ = iscsiAuthClientHexString[(n >> 4) & 0xf];
278 		*text++ = iscsiAuthClientHexString[n & 0xf];
279 
280 		textLength -= 2;
281 	}
282 
283 	*text = '\0';
284 
285 	return (FALSE);
286 }
287 
288 
289 static int
290 iscsiAuthClientDataToBase64(unsigned char *data, unsigned int dataLength,
291     char *text, unsigned int textLength)
292 {
293 	unsigned long n;
294 
295 	if (!text || textLength == 0) {
296 		return (TRUE);
297 	}
298 
299 	if (!data || dataLength == 0) {
300 		*text = '\0';
301 		return (TRUE);
302 	}
303 
304 	if (textLength < 3) {
305 		*text = '\0';
306 		return (TRUE);
307 	}
308 
309 	*text++ = '0';
310 	*text++ = 'b';
311 
312 	textLength -= 2;
313 
314 	while (dataLength >= 3) {
315 
316 		if (textLength < 5) {
317 			*text = '\0';
318 			return (TRUE);
319 		}
320 
321 		n = *data++;
322 		n = (n << 8) | *data++;
323 		n = (n << 8) | *data++;
324 		dataLength -= 3;
325 
326 		*text++ = iscsiAuthClientBase64String[(n >> 18) & 0x3f];
327 		*text++ = iscsiAuthClientBase64String[(n >> 12) & 0x3f];
328 		*text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f];
329 		*text++ = iscsiAuthClientBase64String[n & 0x3f];
330 
331 		textLength -= 4;
332 	}
333 
334 	if (dataLength == 1) {
335 
336 		if (textLength < 5) {
337 			*text = '\0';
338 			return (TRUE);
339 		}
340 
341 		n = *data++;
342 		n = n << 4;
343 
344 		*text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f];
345 		*text++ = iscsiAuthClientBase64String[n & 0x3f];
346 		*text++ = '=';
347 		*text++ = '=';
348 
349 	} else if (dataLength == 2) {
350 
351 		if (textLength < 5) {
352 			return (TRUE);
353 		}
354 
355 		n = *data++;
356 		n = (n << 8) | *data++;
357 		n = n << 2;
358 
359 		*text++ = iscsiAuthClientBase64String[(n >> 12) & 0x3f];
360 		*text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f];
361 		*text++ = iscsiAuthClientBase64String[n & 0x3f];
362 		*text++ = '=';
363 	}
364 
365 	*text = '\0';
366 
367 	return (FALSE);
368 }
369 
370 
371 static int
372 iscsiAuthClientDataToText(int base64, unsigned char *data,
373     unsigned int dataLength, char *text, unsigned int textLength)
374 {
375 	int status;
376 
377 	if (base64) {
378 		status = iscsiAuthClientDataToBase64(
379 		    data, dataLength, text, textLength);
380 	} else {
381 		status = iscsiAuthClientDataToHex(
382 		    data, dataLength, text, textLength);
383 	}
384 
385 	return (status);
386 }
387 
388 
389 static int
390 iscsiAuthClientHexToData(const char *text, unsigned int textLength,
391     unsigned char *data, unsigned int *pDataLength)
392 {
393 	int i;
394 	unsigned int n1;
395 	unsigned int n2;
396 	unsigned int dataLength = *pDataLength;
397 
398 	if ((textLength % 2) == 1) {
399 		i = iscsiAuthClientStringIndex(iscsiAuthClientHexString,
400 		    *text++);
401 		if (i < 0) {
402 			return (TRUE);	/* error, bad character */
403 		}
404 
405 		if (i > 15)
406 			i -= 6;
407 		n2 = i;
408 
409 		if (dataLength < 1) {
410 			return (TRUE);	/* error, too much data */
411 		}
412 
413 		*data++ = n2;
414 		dataLength--;
415 	}
416 
417 	while (*text != '\0') {
418 
419 		i = iscsiAuthClientStringIndex(
420 		    iscsiAuthClientHexString, *text++);
421 		if (i < 0) {
422 			return (TRUE);	/* error, bad character */
423 		}
424 
425 		if (i > 15)
426 			i -= 6;
427 		n1 = i;
428 
429 		if (*text == '\0') {
430 			return (TRUE);	/* error, odd string length */
431 		}
432 
433 		i = iscsiAuthClientStringIndex(
434 		    iscsiAuthClientHexString, *text++);
435 		if (i < 0) {
436 			return (TRUE);	/* error, bad character */
437 		}
438 
439 		if (i > 15)
440 			i -= 6;
441 		n2 = i;
442 
443 		if (dataLength < 1) {
444 			return (TRUE);	/* error, too much data */
445 		}
446 
447 		*data++ = (n1 << 4) | n2;
448 		dataLength--;
449 	}
450 
451 	if (dataLength >= *pDataLength) {
452 		return (TRUE);	/* error, no data */
453 	}
454 
455 	*pDataLength = *pDataLength - dataLength;
456 
457 	return (FALSE);		/* no error */
458 }
459 
460 
461 static int
462 iscsiAuthClientBase64ToData(const char *text, unsigned int textLength,
463     unsigned char *data, unsigned int *pDataLength)
464 {
465 	int i;
466 	unsigned int n;
467 	unsigned int count;
468 	unsigned int dataLength = *pDataLength;
469 
470 	textLength = textLength;	/* not used */
471 
472 	n = 0;
473 	count = 0;
474 
475 	while (*text != '\0' && *text != '=') {
476 
477 		i = iscsiAuthClientStringIndex(
478 		    iscsiAuthClientBase64String, *text++);
479 		if (i < 0) {
480 			return (TRUE);	/* error, bad character */
481 		}
482 
483 		n = (n << 6 | (unsigned int)i);
484 		count++;
485 
486 		if (count >= 4) {
487 			if (dataLength < 3) {
488 				return (TRUE);	/* error, too much data */
489 			}
490 			*data++ = n >> 16;
491 			*data++ = n >> 8;
492 			*data++ = n;
493 			dataLength -= 3;
494 			n = 0;
495 			count = 0;
496 		}
497 	}
498 
499 	while (*text != '\0') {
500 		if (*text++ != '=') {
501 			return (TRUE);	/* error, bad pad */
502 		}
503 	}
504 
505 	if (count == 0) {
506 		/*
507 		 * do nothing
508 		 */
509 		/* EMPTY */
510 	} else if (count == 2) {
511 		if (dataLength < 1) {
512 			return (TRUE);	/* error, too much data */
513 		}
514 		n = n >> 4;
515 		*data++ = n;
516 		dataLength--;
517 	} else if (count == 3) {
518 		if (dataLength < 2) {
519 			return (TRUE);	/* error, too much data */
520 		}
521 		n = n >> 2;
522 		*data++ = n >> 8;
523 		*data++ = n;
524 		dataLength -= 2;
525 	} else {
526 		return (TRUE);	/* bad encoding */
527 	}
528 
529 	if (dataLength >= *pDataLength) {
530 		return (TRUE);	/* error, no data */
531 	}
532 
533 	*pDataLength = *pDataLength - dataLength;
534 
535 	return (FALSE);		/* no error */
536 }
537 
538 
539 static int
540 iscsiAuthClientTextToData(const char *text, unsigned char *data,
541     unsigned int *dataLength)
542 {
543 	int status;
544 	unsigned int textLength;
545 
546 	status = iscsiAuthClientCheckString(text,
547 	    2 + 2 * iscsiAuthLargeBinaryMaxLength + 1, &textLength);
548 
549 	if (status) {
550 		return (status);
551 	}
552 
553 	if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
554 		/*
555 		 * skip prefix
556 		 */
557 		text += 2;
558 		textLength -= 2;
559 		status = iscsiAuthClientHexToData(text,
560 		    textLength, data, dataLength);
561 	} else if (text[0] == '0' && (text[1] == 'b' || text[1] == 'B')) {
562 		/*
563 		 * skip prefix
564 		 */
565 		text += 2;
566 		textLength -= 2;
567 		status = iscsiAuthClientBase64ToData(text,
568 		    textLength, data, dataLength);
569 	} else {
570 		status = TRUE;	/* prefix not recognized. */
571 	}
572 
573 	return (status);
574 }
575 
576 
577 static IscsiAuthDebugStatus
578 iscsiAuthClientChapComputeResponse(IscsiAuthClient * client,
579     int remoteAuthentication, unsigned int id,
580     unsigned char *challengeData, unsigned int challengeLength,
581     unsigned char *responseData)
582 {
583 	unsigned char idData[1];
584 	IscsiAuthMd5Context context;
585 	unsigned char outData[iscsiAuthStringMaxLength];
586 	unsigned int outLength = iscsiAuthStringMaxLength;
587 
588 	if (!client->passwordPresent) {
589 		return (iscsiAuthDebugStatusLocalPasswordNotSet);
590 	}
591 
592 	iscsiAuthMd5Init(&context);
593 
594 	/*
595 	 * id byte
596 	 */
597 	idData[0] = id;
598 	iscsiAuthMd5Update(&context, idData, 1);
599 
600 	/*
601 	 * decrypt password
602 	 */
603 	if (iscsiAuthClientData(outData, &outLength,
604 	    client->passwordData, client->passwordLength)) {
605 
606 		return (iscsiAuthDebugStatusPasswordDecryptFailed);
607 	}
608 
609 	if (!remoteAuthentication && !client->ipSec && outLength < 12) {
610 		return (iscsiAuthDebugStatusPasswordTooShortWithNoIpSec);
611 	}
612 
613 	/*
614 	 * shared secret
615 	 */
616 	iscsiAuthMd5Update(&context, outData, outLength);
617 
618 	/*
619 	 * clear decrypted password
620 	 */
621 	bzero(outData, iscsiAuthStringMaxLength);
622 
623 	/*
624 	 * challenge value
625 	 */
626 	iscsiAuthMd5Update(&context, challengeData, challengeLength);
627 
628 	iscsiAuthMd5Final(responseData, &context);
629 
630 	return (iscsiAuthDebugStatusNotSet);	/* no error */
631 }
632 
633 
634 static void
635 iscsiAuthClientInitKeyBlock(IscsiAuthKeyBlock * keyBlock)
636 {
637 	char *stringBlock = keyBlock->stringBlock;
638 
639 	bzero(keyBlock, sizeof (*keyBlock));
640 	keyBlock->stringBlock = stringBlock;
641 }
642 
643 
644 static void
645 iscsiAuthClientSetKeyValue(IscsiAuthKeyBlock * keyBlock,
646     int keyType, const char *keyValue)
647 {
648 	unsigned int length;
649 	char *string;
650 
651 	if (keyBlock->key[keyType].valueSet) {
652 		keyBlock->duplicateSet = TRUE;
653 		return;
654 	}
655 
656 	keyBlock->key[keyType].valueSet = TRUE;
657 
658 	if (!keyValue) {
659 		return;
660 	}
661 
662 	if (iscsiAuthClientCheckString(keyValue,
663 	    iscsiAuthStringMaxLength, &length)) {
664 		keyBlock->stringTooLong = TRUE;
665 		return;
666 	}
667 
668 	length += 1;
669 
670 	if ((keyBlock->blockLength + length) > iscsiAuthStringBlockMaxLength) {
671 		keyBlock->tooMuchData = TRUE;
672 		return;
673 	}
674 
675 	string = &keyBlock->stringBlock[keyBlock->blockLength];
676 
677 	if (iscsiAuthClientStringCopy(string, keyValue, length)) {
678 		keyBlock->tooMuchData = TRUE;
679 		return;
680 	}
681 	keyBlock->blockLength += length;
682 
683 	keyBlock->key[keyType].string = string;
684 	keyBlock->key[keyType].present = TRUE;
685 }
686 
687 
688 static const char *
689 iscsiAuthClientGetKeyValue(IscsiAuthKeyBlock * keyBlock, int keyType)
690 {
691 	keyBlock->key[keyType].processed = TRUE;
692 
693 	if (!keyBlock->key[keyType].present) {
694 		return (0);
695 	}
696 
697 	return (keyBlock->key[keyType].string);
698 }
699 
700 
701 static void
702 iscsiAuthClientCheckKey(IscsiAuthClient * client,
703     int keyType,
704     int *negotiatedOption,
705     unsigned int optionCount,
706     int *optionList, const char *(*valueToText) (IscsiAuthClient *, int))
707 {
708 	const char *keyValue;
709 	int length;
710 	unsigned int i;
711 
712 	keyValue = iscsiAuthClientGetKeyValue(&client->recvKeyBlock, keyType);
713 	if (!keyValue) {
714 		*negotiatedOption = iscsiAuthOptionNotPresent;
715 		return;
716 	}
717 
718 	while (*keyValue != '\0') {
719 
720 		length = 0;
721 
722 		while (*keyValue != '\0' && *keyValue != ',') {
723 			client->scratchKeyValue[length++] = *keyValue++;
724 		}
725 
726 		if (*keyValue == ',')
727 			keyValue++;
728 		client->scratchKeyValue[length++] = '\0';
729 
730 		for (i = 0; i < optionCount; i++) {
731 			const char *s = (*valueToText) (client, optionList[i]);
732 
733 			if (!s)
734 				continue;
735 
736 			if (strcmp(client->scratchKeyValue, s) == 0) {
737 				*negotiatedOption = optionList[i];
738 				return;
739 			}
740 		}
741 	}
742 
743 	*negotiatedOption = iscsiAuthOptionReject;
744 }
745 
746 
747 static void
748 iscsiAuthClientSetKey(IscsiAuthClient * client,
749     int keyType,
750     unsigned int optionCount,
751     int *optionList, const char *(*valueToText) (IscsiAuthClient *, int))
752 {
753 	unsigned int i;
754 
755 	if (optionCount == 0) {
756 		/*
757 		 * No valid options to send, but we always want to
758 		 * send something.
759 		 */
760 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock, keyType,
761 		    client->noneOptionName);
762 		return;
763 	}
764 
765 	if (optionCount == 1 && optionList[0] == iscsiAuthOptionNotPresent) {
766 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock, keyType, 0);
767 		return;
768 	}
769 
770 	for (i = 0; i < optionCount; i++) {
771 		const char *s = (*valueToText) (client, optionList[i]);
772 
773 		if (!s)
774 			continue;
775 
776 		if (i == 0) {
777 			(void) iscsiAuthClientStringCopy(
778 			    client->scratchKeyValue,
779 			    s, iscsiAuthStringMaxLength);
780 		} else {
781 			(void) iscsiAuthClientStringAppend(
782 			    client->scratchKeyValue,
783 			    ",", iscsiAuthStringMaxLength);
784 			(void) iscsiAuthClientStringAppend(
785 			    client->scratchKeyValue,
786 			    s, iscsiAuthStringMaxLength);
787 		}
788 	}
789 
790 	iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
791 	    keyType, client->scratchKeyValue);
792 }
793 
794 
795 static void
796 iscsiAuthClientCheckAuthMethodKey(IscsiAuthClient * client)
797 {
798 	iscsiAuthClientCheckKey(client,
799 	    iscsiAuthKeyTypeAuthMethod,
800 	    &client->negotiatedAuthMethod,
801 	    client->authMethodValidCount,
802 	    client->authMethodValidList, iscsiAuthClientAuthMethodOptionToText);
803 }
804 
805 
806 static void
807 iscsiAuthClientSetAuthMethodKey(IscsiAuthClient * client,
808     unsigned int authMethodCount, int *authMethodList)
809 {
810 	iscsiAuthClientSetKey(client, iscsiAuthKeyTypeAuthMethod,
811 	    authMethodCount, authMethodList,
812 	    iscsiAuthClientAuthMethodOptionToText);
813 }
814 
815 
816 static void
817 iscsiAuthClientCheckChapAlgorithmKey(IscsiAuthClient * client)
818 {
819 	const char *keyValue;
820 	int length;
821 	unsigned long number;
822 	unsigned int i;
823 
824 	keyValue = iscsiAuthClientGetKeyValue(&client->recvKeyBlock,
825 	    iscsiAuthKeyTypeChapAlgorithm);
826 	if (!keyValue) {
827 		client->negotiatedChapAlgorithm = iscsiAuthOptionNotPresent;
828 		return;
829 	}
830 
831 	while (*keyValue != '\0') {
832 		length = 0;
833 
834 		while (*keyValue != '\0' && *keyValue != ',') {
835 			client->scratchKeyValue[length++] = *keyValue++;
836 		}
837 
838 		if (*keyValue == ',')
839 			keyValue++;
840 		client->scratchKeyValue[length++] = '\0';
841 
842 		if (iscsiAuthClientTextToNumber(client->scratchKeyValue,
843 		    &number)) {
844 			continue;
845 		}
846 
847 		for (i = 0; i < client->chapAlgorithmCount; i++) {
848 
849 			if (number == (unsigned long)client->
850 			    chapAlgorithmList[i]) {
851 				client->negotiatedChapAlgorithm = number;
852 				return;
853 			}
854 		}
855 	}
856 
857 	client->negotiatedChapAlgorithm = iscsiAuthOptionReject;
858 }
859 
860 
861 static void
862 iscsiAuthClientSetChapAlgorithmKey(IscsiAuthClient * client,
863     unsigned int chapAlgorithmCount, int *chapAlgorithmList)
864 {
865 	unsigned int i;
866 
867 	if (chapAlgorithmCount == 0) {
868 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
869 		    iscsiAuthKeyTypeChapAlgorithm, 0);
870 		return;
871 	}
872 
873 	if (chapAlgorithmCount == 1 &&
874 	    chapAlgorithmList[0] == iscsiAuthOptionNotPresent) {
875 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
876 		    iscsiAuthKeyTypeChapAlgorithm, 0);
877 		return;
878 	}
879 
880 	if (chapAlgorithmCount == 1 &&
881 	    chapAlgorithmList[0] == iscsiAuthOptionReject) {
882 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
883 		    iscsiAuthKeyTypeChapAlgorithm, client->rejectOptionName);
884 		return;
885 	}
886 
887 	for (i = 0; i < chapAlgorithmCount; i++) {
888 		char s[20];
889 
890 		iscsiAuthClientNumberToText(chapAlgorithmList[i],
891 		    s, sizeof (s));
892 
893 		if (i == 0) {
894 			(void) iscsiAuthClientStringCopy(
895 			    client->scratchKeyValue, s,
896 			    iscsiAuthStringMaxLength);
897 		} else {
898 			(void) iscsiAuthClientStringAppend(
899 			    client->scratchKeyValue,
900 			    ",", iscsiAuthStringMaxLength);
901 			(void) iscsiAuthClientStringAppend(
902 			    client->scratchKeyValue,
903 			    s, iscsiAuthStringMaxLength);
904 		}
905 	}
906 
907 	iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
908 	    iscsiAuthKeyTypeChapAlgorithm, client->scratchKeyValue);
909 }
910 
911 
912 static void
913 iscsiAuthClientNextPhase(IscsiAuthClient * client)
914 {
915 	switch (client->phase) {
916 	case iscsiAuthPhaseConfigure:
917 		client->phase = iscsiAuthPhaseNegotiate;
918 		break;
919 
920 	case iscsiAuthPhaseNegotiate:
921 		client->phase = iscsiAuthPhaseAuthenticate;
922 
923 		if (client->negotiatedAuthMethod ==
924 		    iscsiAuthOptionReject ||
925 		    client->negotiatedAuthMethod ==
926 		    iscsiAuthOptionNotPresent ||
927 		    client->negotiatedAuthMethod == iscsiAuthOptionNone) {
928 
929 			client->localState = iscsiAuthLocalStateDone;
930 			client->remoteState = iscsiAuthRemoteStateDone;
931 
932 			if (client->authRemote) {
933 				client->remoteAuthStatus = iscsiAuthStatusFail;
934 				client->phase = iscsiAuthPhaseDone;
935 			} else {
936 				client->remoteAuthStatus = iscsiAuthStatusPass;
937 			}
938 
939 			switch (client->negotiatedAuthMethod) {
940 			case iscsiAuthOptionReject:
941 				client->debugStatus =
942 				    iscsiAuthDebugStatusAuthMethodReject;
943 				break;
944 
945 			case iscsiAuthOptionNotPresent:
946 				client->debugStatus =
947 				    iscsiAuthDebugStatusAuthMethodNotPresent;
948 				break;
949 
950 			case iscsiAuthOptionNone:
951 				client->debugStatus =
952 				    iscsiAuthDebugStatusAuthMethodNone;
953 			}
954 
955 		} else if (client->negotiatedAuthMethod ==
956 		    iscsiAuthMethodChap) {
957 			client->localState = iscsiAuthLocalStateSendAlgorithm;
958 			client->remoteState = iscsiAuthRemoteStateSendAlgorithm;
959 		} else {
960 			client->localState = iscsiAuthLocalStateDone;
961 			client->remoteState = iscsiAuthRemoteStateDone;
962 			client->remoteAuthStatus = iscsiAuthStatusFail;
963 			client->debugStatus = iscsiAuthDebugStatusAuthMethodBad;
964 		}
965 
966 		break;
967 
968 	case iscsiAuthPhaseAuthenticate:
969 		client->phase = iscsiAuthPhaseDone;
970 		break;
971 
972 	case iscsiAuthPhaseDone:
973 	case iscsiAuthPhaseError:
974 	default:
975 		client->phase = iscsiAuthPhaseError;
976 	}
977 }
978 
979 
980 static void
981 iscsiAuthClientLocalAuthentication(IscsiAuthClient * client)
982 {
983 	unsigned int chapIdentifier;
984 	unsigned char responseData[iscsiAuthChapResponseLength];
985 	unsigned long number;
986 	int status;
987 	IscsiAuthDebugStatus debugStatus;
988 	const char *chapIdentifierKeyValue;
989 	const char *chapChallengeKeyValue;
990 
991 	switch (client->localState) {
992 	case iscsiAuthLocalStateSendAlgorithm:
993 		if (client->nodeType == iscsiAuthNodeTypeInitiator) {
994 			iscsiAuthClientSetChapAlgorithmKey(
995 			    client, client->chapAlgorithmCount,
996 			    client->chapAlgorithmList);
997 			client->localState = iscsiAuthLocalStateRecvAlgorithm;
998 			break;
999 		}
1000 
1001 		/* FALLTHRU */
1002 
1003 	case iscsiAuthLocalStateRecvAlgorithm:
1004 		iscsiAuthClientCheckChapAlgorithmKey(client);
1005 
1006 		if (client->nodeType == iscsiAuthNodeTypeTarget) {
1007 
1008 			iscsiAuthClientSetChapAlgorithmKey(client, 1,
1009 			    &client->negotiatedChapAlgorithm);
1010 		}
1011 
1012 		/*
1013 		 * Make sure only supported CHAP algorithm is used.
1014 		 */
1015 		if (client->negotiatedChapAlgorithm ==
1016 		    iscsiAuthOptionNotPresent) {
1017 			client->localState = iscsiAuthLocalStateError;
1018 			client->debugStatus =
1019 			    iscsiAuthDebugStatusChapAlgorithmExpected;
1020 			break;
1021 
1022 		} else if (client->negotiatedChapAlgorithm ==
1023 		    iscsiAuthOptionReject) {
1024 			client->localState = iscsiAuthLocalStateError;
1025 			client->debugStatus =
1026 			    iscsiAuthDebugStatusChapAlgorithmReject;
1027 			break;
1028 
1029 		} else if (client->negotiatedChapAlgorithm !=
1030 		    iscsiAuthChapAlgorithmMd5) {
1031 			client->localState = iscsiAuthLocalStateError;
1032 			client->debugStatus =
1033 			    iscsiAuthDebugStatusChapAlgorithmBad;
1034 			break;
1035 		}
1036 
1037 		if (client->nodeType == iscsiAuthNodeTypeTarget) {
1038 
1039 			client->localState = iscsiAuthLocalStateRecvChallenge;
1040 			break;
1041 		}
1042 
1043 		/* FALLTHRU */
1044 
1045 	case iscsiAuthLocalStateRecvChallenge:
1046 		chapIdentifierKeyValue = iscsiAuthClientGetKeyValue(
1047 		    &client->recvKeyBlock, iscsiAuthKeyTypeChapIdentifier);
1048 		chapChallengeKeyValue = iscsiAuthClientGetKeyValue(
1049 		    &client->recvKeyBlock, iscsiAuthKeyTypeChapChallenge);
1050 
1051 		if (client->nodeType == iscsiAuthNodeTypeTarget) {
1052 			if (!chapIdentifierKeyValue && !chapChallengeKeyValue) {
1053 				client->localState = iscsiAuthLocalStateDone;
1054 				break;
1055 			}
1056 		}
1057 
1058 		if (!chapIdentifierKeyValue) {
1059 			client->localState = iscsiAuthLocalStateError;
1060 			client->debugStatus =
1061 			    iscsiAuthDebugStatusChapIdentifierExpected;
1062 			break;
1063 		}
1064 
1065 		if (!chapChallengeKeyValue) {
1066 			client->localState = iscsiAuthLocalStateError;
1067 			client->debugStatus =
1068 			    iscsiAuthDebugStatusChapChallengeExpected;
1069 			break;
1070 		}
1071 
1072 		status = iscsiAuthClientTextToNumber(
1073 		    chapIdentifierKeyValue, &number);
1074 
1075 		if (status || (255 < number)) {
1076 			client->localState = iscsiAuthLocalStateError;
1077 			client->debugStatus =
1078 			    iscsiAuthDebugStatusChapIdentifierBad;
1079 			break;
1080 		}
1081 		chapIdentifier = number;
1082 
1083 		if (client->recvChapChallengeStatus) {
1084 			client->localState = iscsiAuthLocalStateError;
1085 			client->debugStatus =
1086 			    iscsiAuthDebugStatusChapChallengeBad;
1087 			break;
1088 		}
1089 
1090 		if (client->nodeType == iscsiAuthNodeTypeTarget &&
1091 		    client->recvChapChallenge.length ==
1092 		    client->sendChapChallenge.length &&
1093 		    bcmp(client->recvChapChallenge.largeBinary,
1094 		    client->sendChapChallenge.largeBinary,
1095 		    client->sendChapChallenge.length) == 0) {
1096 
1097 			client->localState = iscsiAuthLocalStateError;
1098 			client->debugStatus =
1099 			    iscsiAuthDebugStatusChapChallengeReflected;
1100 			break;
1101 		}
1102 
1103 		debugStatus = iscsiAuthClientChapComputeResponse(client,
1104 		    FALSE,
1105 		    chapIdentifier,
1106 		    client->recvChapChallenge.largeBinary,
1107 		    client->recvChapChallenge.length, responseData);
1108 
1109 		if (debugStatus != iscsiAuthDebugStatusNotSet) {
1110 			client->localState = iscsiAuthLocalStateError;
1111 			client->debugStatus = debugStatus;
1112 			break;
1113 		}
1114 
1115 		(void) iscsiAuthClientDataToText(client->base64,
1116 		    responseData, iscsiAuthChapResponseLength,
1117 		    client->scratchKeyValue, iscsiAuthStringMaxLength);
1118 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
1119 		    iscsiAuthKeyTypeChapResponse, client->scratchKeyValue);
1120 
1121 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
1122 		    iscsiAuthKeyTypeChapUsername, client->username);
1123 
1124 		client->localState = iscsiAuthLocalStateDone;
1125 		break;
1126 
1127 	case iscsiAuthLocalStateDone:
1128 		break;
1129 
1130 	case iscsiAuthLocalStateError:
1131 	default:
1132 		client->phase = iscsiAuthPhaseError;
1133 	}
1134 }
1135 
1136 
1137 static void
1138 iscsiAuthClientRemoteAuthentication(IscsiAuthClient * client)
1139 {
1140 	unsigned char idData[1];
1141 	unsigned char responseData[iscsiAuthStringMaxLength];
1142 	unsigned int responseLength = iscsiAuthStringMaxLength;
1143 	unsigned char myResponseData[iscsiAuthChapResponseLength];
1144 	int status;
1145 	IscsiAuthDebugStatus debugStatus;
1146 	const char *chapResponseKeyValue;
1147 	const char *chapUsernameKeyValue;
1148 
1149 	switch (client->remoteState) {
1150 	case iscsiAuthRemoteStateSendAlgorithm:
1151 		if (client->nodeType == iscsiAuthNodeTypeInitiator) {
1152 			client->remoteState = iscsiAuthRemoteStateSendChallenge;
1153 			break;
1154 		}
1155 
1156 		/* FALLTHRU */
1157 
1158 	case iscsiAuthRemoteStateSendChallenge:
1159 		if (!client->authRemote) {
1160 			client->remoteAuthStatus = iscsiAuthStatusPass;
1161 			client->debugStatus =
1162 			    iscsiAuthDebugStatusAuthRemoteFalse;
1163 			client->remoteState = iscsiAuthRemoteStateDone;
1164 			break;
1165 		}
1166 
1167 		iscsiAuthRandomSetData(idData, 1);
1168 		client->sendChapIdentifier = idData[0];
1169 
1170 		iscsiAuthClientNumberToText(client->sendChapIdentifier,
1171 		    client->scratchKeyValue, iscsiAuthStringMaxLength);
1172 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
1173 		    iscsiAuthKeyTypeChapIdentifier, client->scratchKeyValue);
1174 
1175 		client->sendChapChallenge.length = client->chapChallengeLength;
1176 		iscsiAuthRandomSetData(client->sendChapChallenge.largeBinary,
1177 		    client->sendChapChallenge.length);
1178 
1179 		iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
1180 		    iscsiAuthKeyTypeChapChallenge, "");
1181 
1182 		client->remoteState = iscsiAuthRemoteStateRecvResponse;
1183 		break;
1184 
1185 	case iscsiAuthRemoteStateRecvResponse:
1186 		chapResponseKeyValue = iscsiAuthClientGetKeyValue(
1187 		    &client->recvKeyBlock, iscsiAuthKeyTypeChapResponse);
1188 
1189 		chapUsernameKeyValue = iscsiAuthClientGetKeyValue(
1190 		    &client->recvKeyBlock, iscsiAuthKeyTypeChapUsername);
1191 
1192 		if (!chapResponseKeyValue) {
1193 			client->remoteState = iscsiAuthRemoteStateError;
1194 			client->debugStatus =
1195 			    iscsiAuthDebugStatusChapResponseExpected;
1196 			break;
1197 		}
1198 
1199 		if (!chapUsernameKeyValue) {
1200 			client->remoteState = iscsiAuthRemoteStateError;
1201 			client->debugStatus =
1202 			    iscsiAuthDebugStatusChapUsernameExpected;
1203 			break;
1204 		}
1205 
1206 		status = iscsiAuthClientTextToData(chapResponseKeyValue,
1207 		    responseData, &responseLength);
1208 
1209 		if (status) {
1210 			client->remoteState = iscsiAuthRemoteStateError;
1211 			client->debugStatus =
1212 			    iscsiAuthDebugStatusChapResponseBad;
1213 			break;
1214 		}
1215 
1216 		if (responseLength == iscsiAuthChapResponseLength) {
1217 			debugStatus = iscsiAuthClientChapComputeResponse(
1218 			    client, TRUE, client->sendChapIdentifier,
1219 			    client->sendChapChallenge.largeBinary,
1220 			    client->sendChapChallenge.length, myResponseData);
1221 
1222 			/*
1223 			 * Check if the same CHAP secret is being used for
1224 			 * authentication in both directions.
1225 			 */
1226 			if (debugStatus == iscsiAuthDebugStatusNotSet &&
1227 			    bcmp(myResponseData, responseData,
1228 			    iscsiAuthChapResponseLength) == 0) {
1229 
1230 				client->remoteState =
1231 				    iscsiAuthRemoteStateError;
1232 				client->debugStatus =
1233 				    iscsiAuthDebugStatusPasswordIdentical;
1234 				break;
1235 			}
1236 		}
1237 
1238 		(void) iscsiAuthClientStringCopy(client->chapUsername,
1239 		    chapUsernameKeyValue, iscsiAuthStringMaxLength);
1240 
1241 		/* To verify the target's response. */
1242 		status = iscsiAuthClientChapAuthRequest(
1243 		    client, client->chapUsername, client->sendChapIdentifier,
1244 		    client->sendChapChallenge.largeBinary,
1245 		    client->sendChapChallenge.length, responseData,
1246 		    responseLength);
1247 
1248 		if (status == iscsiAuthStatusInProgress) {
1249 			iscsiAuthClientGlobalStats.requestSent++;
1250 			client->remoteState = iscsiAuthRemoteStateAuthRequest;
1251 			break;
1252 		}
1253 
1254 		client->remoteAuthStatus = (IscsiAuthStatus) status;
1255 		client->authResponseFlag = TRUE;
1256 
1257 		/* FALLTHRU */
1258 
1259 	case iscsiAuthRemoteStateAuthRequest:
1260 		/*
1261 		 * client->remoteAuthStatus already set
1262 		 */
1263 		if (client->authServerErrorFlag) {
1264 			client->remoteAuthStatus = iscsiAuthStatusFail;
1265 			client->debugStatus =
1266 			    iscsiAuthDebugStatusAuthServerError;
1267 		} else if (client->remoteAuthStatus == iscsiAuthStatusPass) {
1268 			client->debugStatus = iscsiAuthDebugStatusAuthPass;
1269 		} else if (client->remoteAuthStatus == iscsiAuthStatusFail) {
1270 			client->debugStatus = iscsiAuthDebugStatusAuthFail;
1271 		} else {
1272 			client->remoteAuthStatus = iscsiAuthStatusFail;
1273 			client->debugStatus = iscsiAuthDebugStatusAuthStatusBad;
1274 		}
1275 		client->remoteState = iscsiAuthRemoteStateDone;
1276 
1277 		/* FALLTHRU */
1278 
1279 	case iscsiAuthRemoteStateDone:
1280 		break;
1281 
1282 	case iscsiAuthRemoteStateError:
1283 	default:
1284 		client->phase = iscsiAuthPhaseError;
1285 	}
1286 }
1287 
1288 
1289 static void
1290 iscsiAuthClientHandshake(IscsiAuthClient * client)
1291 {
1292 	if (client->phase == iscsiAuthPhaseDone) {
1293 		/*
1294 		 * Should only happen if authentication
1295 		 * protocol error occured.
1296 		 */
1297 		return;
1298 	}
1299 
1300 	if (client->remoteState == iscsiAuthRemoteStateAuthRequest) {
1301 		/*
1302 		 * Defer until authentication response received
1303 		 * from internal authentication service.
1304 		 */
1305 		return;
1306 	}
1307 
1308 	if (client->nodeType == iscsiAuthNodeTypeInitiator) {
1309 
1310 		/*
1311 		 * Target should only have set T bit on response if
1312 		 * initiator set it on previous message.
1313 		 */
1314 		if (client->recvKeyBlock.transitBit &&
1315 		    client->transitBitSentFlag == 0) {
1316 			client->remoteAuthStatus = iscsiAuthStatusFail;
1317 			client->phase = iscsiAuthPhaseDone;
1318 			client->debugStatus =
1319 			    iscsiAuthDebugStatusTbitSetIllegal;
1320 			return;
1321 		}
1322 	}
1323 
1324 	if (client->phase == iscsiAuthPhaseNegotiate) {
1325 		/*
1326 		 * Should only happen if waiting for peer
1327 		 * to send AuthMethod key or set Transit Bit.
1328 		 */
1329 		if (client->nodeType == iscsiAuthNodeTypeInitiator) {
1330 			client->sendKeyBlock.transitBit = TRUE;
1331 		}
1332 		return;
1333 	}
1334 
1335 	if (client->remoteState == iscsiAuthRemoteStateRecvResponse ||
1336 	    client->remoteState == iscsiAuthRemoteStateDone) {
1337 
1338 		if (client->nodeType == iscsiAuthNodeTypeInitiator) {
1339 			if (client->recvKeyBlock.transitBit) {
1340 				if (client->remoteState !=
1341 				    iscsiAuthRemoteStateDone) {
1342 					goto recvTransitBitError;
1343 				}
1344 				iscsiAuthClientNextPhase(client);
1345 			} else {
1346 				client->sendKeyBlock.transitBit = TRUE;
1347 			}
1348 		} else {
1349 			if (client->remoteState == iscsiAuthRemoteStateDone &&
1350 			    client->remoteAuthStatus != iscsiAuthStatusPass) {
1351 
1352 				/*
1353 				 * Authentication failed, don't
1354 				 * do T bit handshake.
1355 				 */
1356 				iscsiAuthClientNextPhase(client);
1357 			} else {
1358 
1359 				/*
1360 				 * Target can only set T bit on response if
1361 				 * initiator set it on current message.
1362 				 */
1363 				if (client->recvKeyBlock.transitBit) {
1364 					client->sendKeyBlock.transitBit = TRUE;
1365 					iscsiAuthClientNextPhase(client);
1366 				}
1367 			}
1368 		}
1369 	} else {
1370 		if (client->nodeType == iscsiAuthNodeTypeInitiator) {
1371 			if (client->recvKeyBlock.transitBit) {
1372 				goto recvTransitBitError;
1373 			}
1374 		}
1375 	}
1376 
1377 	return;
1378 
1379 recvTransitBitError:
1380 	/*
1381 	 * Target set T bit on response but
1382 	 * initiator was not done with authentication.
1383 	 */
1384 	client->remoteAuthStatus = iscsiAuthStatusFail;
1385 	client->phase = iscsiAuthPhaseDone;
1386 	client->debugStatus = iscsiAuthDebugStatusTbitSetPremature;
1387 }
1388 
1389 
1390 static int
1391 iscsiAuthClientRecvEndStatus(IscsiAuthClient * client)
1392 {
1393 	int authStatus;
1394 	int keyType;
1395 
1396 	if (client->phase == iscsiAuthPhaseError) {
1397 		return (iscsiAuthStatusError);
1398 	}
1399 
1400 	if (client->phase == iscsiAuthPhaseDone) {
1401 
1402 		/*
1403 		 * Perform sanity check against configured parameters.
1404 		 */
1405 
1406 		if (client->authRemote && !client->authResponseFlag &&
1407 		    client->remoteAuthStatus == iscsiAuthStatusPass) {
1408 
1409 			client->remoteAuthStatus = iscsiAuthStatusFail;
1410 			client->debugStatus =
1411 			    iscsiAuthDebugStatusAuthPassNotValid;
1412 		}
1413 
1414 		authStatus = client->remoteAuthStatus;
1415 	} else if (client->remoteState == iscsiAuthRemoteStateAuthRequest) {
1416 		authStatus = iscsiAuthStatusInProgress;
1417 	} else {
1418 		authStatus = iscsiAuthStatusContinue;
1419 	}
1420 
1421 	if (authStatus != iscsiAuthStatusInProgress) {
1422 		client->recvInProgressFlag = FALSE;
1423 	}
1424 
1425 	if (authStatus == iscsiAuthStatusContinue ||
1426 	    authStatus == iscsiAuthStatusPass) {
1427 		if (client->sendKeyBlock.duplicateSet) {
1428 			client->remoteAuthStatus = iscsiAuthStatusFail;
1429 			client->phase = iscsiAuthPhaseDone;
1430 			client->debugStatus =
1431 			    iscsiAuthDebugStatusSendDuplicateSetKeyValue;
1432 			authStatus = iscsiAuthStatusFail;
1433 		} else if (client->sendKeyBlock.stringTooLong) {
1434 			client->remoteAuthStatus = iscsiAuthStatusFail;
1435 			client->phase = iscsiAuthPhaseDone;
1436 			client->debugStatus =
1437 			    iscsiAuthDebugStatusSendStringTooLong;
1438 			authStatus = iscsiAuthStatusFail;
1439 		} else if (client->sendKeyBlock.tooMuchData) {
1440 			client->remoteAuthStatus = iscsiAuthStatusFail;
1441 			client->phase = iscsiAuthPhaseDone;
1442 			client->debugStatus =
1443 			    iscsiAuthDebugStatusSendTooMuchData;
1444 			authStatus = iscsiAuthStatusFail;
1445 		} else {
1446 			/*
1447 			 * Check that all incoming keys have been processed.
1448 			 */
1449 			for (keyType = iscsiAuthKeyTypeFirst;
1450 			    keyType < iscsiAuthKeyTypeMaxCount; keyType++) {
1451 				if (client->recvKeyBlock.key[keyType].present &&
1452 				    client->recvKeyBlock.key[keyType].
1453 				    processed == 0) {
1454 					break;
1455 				}
1456 			}
1457 
1458 			if (keyType < iscsiAuthKeyTypeMaxCount) {
1459 				client->remoteAuthStatus = iscsiAuthStatusFail;
1460 				client->phase = iscsiAuthPhaseDone;
1461 				client->debugStatus =
1462 				    iscsiAuthDebugStatusUnexpectedKeyPresent;
1463 				authStatus = iscsiAuthStatusFail;
1464 			}
1465 		}
1466 	}
1467 
1468 	if (authStatus != iscsiAuthStatusPass &&
1469 	    authStatus != iscsiAuthStatusContinue &&
1470 	    authStatus != iscsiAuthStatusInProgress) {
1471 		int authMethodKeyPresent = FALSE;
1472 		int chapAlgorithmKeyPresent = FALSE;
1473 
1474 		/*
1475 		 * Suppress send keys on error, except
1476 		 * for AuthMethod and CHAP_A.
1477 		 */
1478 		if (client->nodeType == iscsiAuthNodeTypeTarget) {
1479 			if (iscsiAuthClientGetKeyValue(&client->sendKeyBlock,
1480 			    iscsiAuthKeyTypeAuthMethod)) {
1481 				authMethodKeyPresent = TRUE;
1482 			} else if (iscsiAuthClientGetKeyValue(
1483 			    &client->sendKeyBlock,
1484 			    iscsiAuthKeyTypeChapAlgorithm)) {
1485 				chapAlgorithmKeyPresent = TRUE;
1486 			}
1487 		}
1488 
1489 		iscsiAuthClientInitKeyBlock(&client->sendKeyBlock);
1490 
1491 		if (client->nodeType == iscsiAuthNodeTypeTarget) {
1492 			if (authMethodKeyPresent &&
1493 			    client->negotiatedAuthMethod ==
1494 			    iscsiAuthOptionReject) {
1495 				iscsiAuthClientSetKeyValue(
1496 				    &client->sendKeyBlock,
1497 				    iscsiAuthKeyTypeAuthMethod,
1498 				    client->rejectOptionName);
1499 			} else if (chapAlgorithmKeyPresent &&
1500 			    client->negotiatedChapAlgorithm ==
1501 			    iscsiAuthOptionReject) {
1502 				iscsiAuthClientSetKeyValue(
1503 				    &client->sendKeyBlock,
1504 				    iscsiAuthKeyTypeChapAlgorithm,
1505 				    client->rejectOptionName);
1506 			}
1507 		}
1508 	}
1509 
1510 	return (authStatus);
1511 }
1512 
1513 
1514 int
1515 iscsiAuthClientRecvBegin(IscsiAuthClient * client)
1516 {
1517 	if (!client || client->signature != iscsiAuthClientSignature) {
1518 		return (iscsiAuthStatusError);
1519 	}
1520 
1521 	if (client->phase == iscsiAuthPhaseError) {
1522 		return (iscsiAuthStatusError);
1523 	}
1524 
1525 	if (client->phase == iscsiAuthPhaseDone) {
1526 		client->phase = iscsiAuthPhaseError;
1527 		return (iscsiAuthStatusError);
1528 	}
1529 
1530 	if (client->recvInProgressFlag) {
1531 		client->phase = iscsiAuthPhaseError;
1532 		return (iscsiAuthStatusError);
1533 	}
1534 
1535 	client->recvInProgressFlag = TRUE;
1536 
1537 	if (client->phase == iscsiAuthPhaseConfigure) {
1538 		iscsiAuthClientNextPhase(client);
1539 	}
1540 
1541 	client->transitBitSentFlag = client->sendKeyBlock.transitBit;
1542 
1543 	iscsiAuthClientInitKeyBlock(&client->recvKeyBlock);
1544 	iscsiAuthClientInitKeyBlock(&client->sendKeyBlock);
1545 
1546 	return (iscsiAuthStatusNoError);
1547 }
1548 
1549 
1550 int
1551 iscsiAuthClientRecvEnd(IscsiAuthClient * client,
1552     IscsiAuthClientCallback * callback, void *userHandle, void *messageHandle)
1553 {
1554 	int nextPhaseFlag = FALSE;
1555 
1556 	if (!client || client->signature != iscsiAuthClientSignature) {
1557 		return (iscsiAuthStatusError);
1558 	}
1559 
1560 	if (client->phase == iscsiAuthPhaseError) {
1561 		return (iscsiAuthStatusError);
1562 	}
1563 
1564 	if (!callback || !client->recvInProgressFlag) {
1565 		client->phase = iscsiAuthPhaseError;
1566 		return (iscsiAuthStatusError);
1567 	}
1568 
1569 	if (client->recvEndCount > iscsiAuthRecvEndMaxCount) {
1570 		client->remoteAuthStatus = iscsiAuthStatusFail;
1571 		client->phase = iscsiAuthPhaseDone;
1572 		client->debugStatus =
1573 		    iscsiAuthDebugStatusRecvMessageCountLimit;
1574 	} else if (client->recvKeyBlock.duplicateSet) {
1575 		client->remoteAuthStatus = iscsiAuthStatusFail;
1576 		client->phase = iscsiAuthPhaseDone;
1577 		client->debugStatus =
1578 		    iscsiAuthDebugStatusRecvDuplicateSetKeyValue;
1579 	} else if (client->recvKeyBlock.stringTooLong) {
1580 		client->remoteAuthStatus = iscsiAuthStatusFail;
1581 		client->phase = iscsiAuthPhaseDone;
1582 		client->debugStatus = iscsiAuthDebugStatusRecvStringTooLong;
1583 	} else if (client->recvKeyBlock.tooMuchData) {
1584 		client->remoteAuthStatus = iscsiAuthStatusFail;
1585 		client->phase = iscsiAuthPhaseDone;
1586 		client->debugStatus = iscsiAuthDebugStatusRecvTooMuchData;
1587 	}
1588 
1589 	client->recvEndCount++;
1590 
1591 	client->callback = callback;
1592 	client->userHandle = userHandle;
1593 	client->messageHandle = messageHandle;
1594 
1595 	switch (client->phase) {
1596 	case iscsiAuthPhaseNegotiate:
1597 		iscsiAuthClientCheckAuthMethodKey(client);
1598 
1599 		if (client->authMethodValidNegRole ==
1600 		    iscsiAuthNegRoleResponder) {
1601 			if (client->negotiatedAuthMethod ==
1602 			    iscsiAuthOptionNotPresent) {
1603 				if (client->authRemote ||
1604 				    client->recvKeyBlock.transitBit == 0) {
1605 					/*
1606 					 * No AuthMethod key from peer
1607 					 * on first message, try moving
1608 					 * the process along by sending
1609 					 * the AuthMethod key.
1610 					 */
1611 
1612 					client->authMethodValidNegRole =
1613 					    iscsiAuthNegRoleOriginator;
1614 
1615 					iscsiAuthClientSetAuthMethodKey(client,
1616 					    client->authMethodValidCount,
1617 					    client->authMethodValidList);
1618 					break;
1619 				}
1620 
1621 				/*
1622 				 * Special case if peer sent no
1623 				 * AuthMethod key, but did set Transit
1624 				 * Bit, allowing this side to do a
1625 				 * null authentication, and compelete
1626 				 * the iSCSI security phase without
1627 				 * either side sending the AuthMethod
1628 				 * key.
1629 				 */
1630 			} else {
1631 				/*
1632 				 * Send response to AuthMethod key.
1633 				 */
1634 
1635 				iscsiAuthClientSetAuthMethodKey(client, 1,
1636 				    &client->negotiatedAuthMethod);
1637 			}
1638 
1639 			if (client->nodeType == iscsiAuthNodeTypeInitiator) {
1640 				iscsiAuthClientNextPhase(client);
1641 			} else {
1642 				nextPhaseFlag = TRUE;
1643 			}
1644 
1645 		} else {
1646 			if (client->negotiatedAuthMethod ==
1647 			    iscsiAuthOptionNotPresent) {
1648 				client->remoteAuthStatus = iscsiAuthStatusFail;
1649 				client->phase = iscsiAuthPhaseDone;
1650 				client->debugStatus =
1651 				    iscsiAuthDebugStatusAuthMethodExpected;
1652 				break;
1653 			}
1654 
1655 			iscsiAuthClientNextPhase(client);
1656 		}
1657 		break;
1658 
1659 	case iscsiAuthPhaseAuthenticate:
1660 	case iscsiAuthPhaseDone:
1661 		break;
1662 
1663 	default:
1664 		client->phase = iscsiAuthPhaseError;
1665 		return (iscsiAuthStatusError);
1666 	}
1667 
1668 	switch (client->phase) {
1669 	case iscsiAuthPhaseNegotiate:
1670 		if (nextPhaseFlag) {
1671 			iscsiAuthClientNextPhase(client);
1672 		}
1673 		break;
1674 
1675 	case iscsiAuthPhaseAuthenticate:
1676 		/*
1677 		 * Must call iscsiAuthClientLocalAuthentication()
1678 		 * before iscsiAuthClientRemoteAuthentication()
1679 		 * to insure processing of the CHAP algorithm key,
1680 		 * and to avoid leaving an in progress request to the
1681 		 * authentication service.
1682 		 */
1683 		iscsiAuthClientLocalAuthentication(client);
1684 
1685 		if (client->localState != iscsiAuthLocalStateError) {
1686 			iscsiAuthClientRemoteAuthentication(client);
1687 		}
1688 
1689 		if (client->localState == iscsiAuthLocalStateError ||
1690 		    client->remoteState == iscsiAuthRemoteStateError) {
1691 
1692 			client->remoteAuthStatus = iscsiAuthStatusFail;
1693 			client->phase = iscsiAuthPhaseDone;
1694 			/*
1695 			 * client->debugStatus should already be set.
1696 			 */
1697 		}
1698 		break;
1699 
1700 	case iscsiAuthPhaseDone:
1701 		break;
1702 
1703 	default:
1704 		client->phase = iscsiAuthPhaseError;
1705 		return (iscsiAuthStatusError);
1706 	}
1707 
1708 	iscsiAuthClientHandshake(client);
1709 
1710 	return (iscsiAuthClientRecvEndStatus(client));
1711 }
1712 
1713 
1714 void
1715 iscsiAuthClientAuthResponse(IscsiAuthClient * client, int authStatus)
1716 {
1717 	iscsiAuthClientGlobalStats.responseReceived++;
1718 
1719 	if (!client || client->signature != iscsiAuthClientSignature) {
1720 		return;
1721 	}
1722 
1723 	if (!client->recvInProgressFlag ||
1724 	    client->phase != iscsiAuthPhaseAuthenticate ||
1725 	    client->remoteState != iscsiAuthRemoteStateAuthRequest) {
1726 
1727 		client->phase = iscsiAuthPhaseError;
1728 		return;
1729 	}
1730 
1731 	client->remoteAuthStatus = (IscsiAuthStatus) authStatus;
1732 	client->authResponseFlag = TRUE;
1733 
1734 	iscsiAuthClientRemoteAuthentication(client);
1735 
1736 	iscsiAuthClientHandshake(client);
1737 
1738 	authStatus = iscsiAuthClientRecvEndStatus(client);
1739 
1740 	client->callback(client->userHandle, client->messageHandle, authStatus);
1741 }
1742 
1743 
1744 const char *
1745 iscsiAuthClientGetKeyName(int keyType)
1746 {
1747 	if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) {
1748 		return (0);
1749 	}
1750 	return (iscsiAuthClientKeyInfo[keyType].name);
1751 }
1752 
1753 
1754 int
1755 iscsiAuthClientGetNextKeyType(int *pKeyType)
1756 {
1757 	int keyType = *pKeyType;
1758 
1759 	if (keyType >= iscsiAuthKeyTypeLast) {
1760 		return (iscsiAuthStatusError);
1761 	}
1762 
1763 	if (keyType < iscsiAuthKeyTypeFirst) {
1764 		keyType = iscsiAuthKeyTypeFirst;
1765 	} else {
1766 		keyType++;
1767 	}
1768 
1769 	*pKeyType = keyType;
1770 
1771 	return (iscsiAuthStatusNoError);
1772 }
1773 
1774 
1775 int
1776 iscsiAuthClientKeyNameToKeyType(const char *keyName)
1777 {
1778 	int keyType = iscsiAuthKeyTypeNone;
1779 
1780 	while (iscsiAuthClientGetNextKeyType(&keyType) ==
1781 	    iscsiAuthStatusNoError) {
1782 		const char *keyName2 = iscsiAuthClientGetKeyName(keyType);
1783 
1784 		if (!keyName2) {
1785 			return (iscsiAuthKeyTypeNone);
1786 		}
1787 
1788 		if (strcmp(keyName, keyName2) == 0) {
1789 			return (keyType);
1790 		}
1791 	}
1792 
1793 	return (iscsiAuthKeyTypeNone);
1794 }
1795 
1796 
1797 int
1798 iscsiAuthClientRecvKeyValue(IscsiAuthClient * client, int keyType,
1799     const char *userKeyValue)
1800 {
1801 	if (!client || client->signature != iscsiAuthClientSignature) {
1802 		return (iscsiAuthStatusError);
1803 	}
1804 
1805 	if (client->phase != iscsiAuthPhaseNegotiate &&
1806 	    client->phase != iscsiAuthPhaseAuthenticate) {
1807 
1808 		client->phase = iscsiAuthPhaseError;
1809 		return (iscsiAuthStatusError);
1810 	}
1811 
1812 	if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) {
1813 
1814 		client->phase = iscsiAuthPhaseError;
1815 		return (iscsiAuthStatusError);
1816 	}
1817 
1818 	if (keyType == iscsiAuthKeyTypeChapChallenge) {
1819 		client->recvChapChallenge.length =
1820 		    iscsiAuthLargeBinaryMaxLength;
1821 		client->recvChapChallengeStatus =
1822 		    iscsiAuthClientTextToData(userKeyValue,
1823 		    client->recvChapChallenge.largeBinary,
1824 		    &client->recvChapChallenge.length);
1825 		userKeyValue = "";
1826 	}
1827 
1828 	iscsiAuthClientSetKeyValue(&client->recvKeyBlock,
1829 	    keyType, userKeyValue);
1830 
1831 	return (iscsiAuthStatusNoError);
1832 }
1833 
1834 
1835 int
1836 iscsiAuthClientSendKeyValue(IscsiAuthClient * client, int keyType,
1837     int *keyPresent, char *userKeyValue, unsigned int maxLength)
1838 {
1839 	const char *keyValue;
1840 
1841 	if (!client || client->signature != iscsiAuthClientSignature) {
1842 		return (iscsiAuthStatusError);
1843 	}
1844 
1845 	if (client->phase != iscsiAuthPhaseConfigure &&
1846 	    client->phase != iscsiAuthPhaseNegotiate &&
1847 	    client->phase != iscsiAuthPhaseAuthenticate &&
1848 	    client->phase != iscsiAuthPhaseDone) {
1849 
1850 		client->phase = iscsiAuthPhaseError;
1851 		return (iscsiAuthStatusError);
1852 	}
1853 
1854 	if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) {
1855 
1856 		client->phase = iscsiAuthPhaseError;
1857 		return (iscsiAuthStatusError);
1858 	}
1859 
1860 	keyValue = iscsiAuthClientGetKeyValue(&client->sendKeyBlock, keyType);
1861 	if (keyValue) {
1862 		if (keyType == iscsiAuthKeyTypeChapChallenge) {
1863 			if (iscsiAuthClientDataToText(client->base64,
1864 			    client->sendChapChallenge.largeBinary,
1865 			    client->sendChapChallenge.length,
1866 			    userKeyValue, maxLength)) {
1867 				client->phase = iscsiAuthPhaseError;
1868 				return (iscsiAuthStatusError);
1869 			}
1870 		} else {
1871 			if (iscsiAuthClientStringCopy(userKeyValue,
1872 			    keyValue, maxLength)) {
1873 				client->phase = iscsiAuthPhaseError;
1874 				return (iscsiAuthStatusError);
1875 			}
1876 		}
1877 		*keyPresent = TRUE;
1878 	} else {
1879 		*keyPresent = FALSE;
1880 	}
1881 
1882 	return (iscsiAuthStatusNoError);
1883 }
1884 
1885 
1886 int
1887 iscsiAuthClientRecvTransitBit(IscsiAuthClient * client, int value)
1888 {
1889 	if (!client || client->signature != iscsiAuthClientSignature) {
1890 		return (iscsiAuthStatusError);
1891 	}
1892 
1893 	if (client->phase != iscsiAuthPhaseNegotiate &&
1894 	    client->phase != iscsiAuthPhaseAuthenticate) {
1895 
1896 		client->phase = iscsiAuthPhaseError;
1897 		return (iscsiAuthStatusError);
1898 	}
1899 
1900 	if (value) {
1901 		client->recvKeyBlock.transitBit = TRUE;
1902 	} else {
1903 		client->recvKeyBlock.transitBit = FALSE;
1904 	}
1905 
1906 	return (iscsiAuthStatusNoError);
1907 }
1908 
1909 
1910 int
1911 iscsiAuthClientSendTransitBit(IscsiAuthClient * client, int *value)
1912 {
1913 	if (!client || client->signature != iscsiAuthClientSignature) {
1914 		return (iscsiAuthStatusError);
1915 	}
1916 
1917 	if (client->phase != iscsiAuthPhaseConfigure &&
1918 	    client->phase != iscsiAuthPhaseNegotiate &&
1919 	    client->phase != iscsiAuthPhaseAuthenticate &&
1920 	    client->phase != iscsiAuthPhaseDone) {
1921 
1922 		client->phase = iscsiAuthPhaseError;
1923 		return (iscsiAuthStatusError);
1924 	}
1925 
1926 	*value = client->sendKeyBlock.transitBit;
1927 
1928 	return (iscsiAuthStatusNoError);
1929 }
1930 
1931 
1932 int
1933 iscsiAuthClientInit(int nodeType, int bufferDescCount,
1934     IscsiAuthBufferDesc * bufferDesc)
1935 {
1936 	IscsiAuthClient *client;
1937 	IscsiAuthStringBlock *recvStringBlock;
1938 	IscsiAuthStringBlock *sendStringBlock;
1939 	IscsiAuthLargeBinary *recvChapChallenge;
1940 	IscsiAuthLargeBinary *sendChapChallenge;
1941 	int valueList[2];
1942 
1943 	if (bufferDescCount != 5 ||
1944 	    bufferDesc == 0) {
1945 		return (iscsiAuthStatusError);
1946 	}
1947 
1948 	if (!bufferDesc[0].address ||
1949 	    bufferDesc[0].length != sizeof (*client)) {
1950 		return (iscsiAuthStatusError);
1951 	}
1952 	client = (IscsiAuthClient *) bufferDesc[0].address;
1953 
1954 	if (bufferDesc[1].address == 0 ||
1955 	    bufferDesc[1].length != sizeof (*recvStringBlock)) {
1956 		return (iscsiAuthStatusError);
1957 	}
1958 	recvStringBlock = (IscsiAuthStringBlock *) bufferDesc[1].address;
1959 
1960 	if (bufferDesc[2].address == 0 ||
1961 	    bufferDesc[2].length != sizeof (*sendStringBlock)) {
1962 		return (iscsiAuthStatusError);
1963 	}
1964 	sendStringBlock = (IscsiAuthStringBlock *) bufferDesc[2].address;
1965 
1966 	if (bufferDesc[3].address == 0 ||
1967 	    bufferDesc[3].length != sizeof (*recvChapChallenge)) {
1968 		return (iscsiAuthStatusError);
1969 	}
1970 	recvChapChallenge = (IscsiAuthLargeBinary *) bufferDesc[3].address;
1971 
1972 	if (bufferDesc[4].address == 0 ||
1973 	    bufferDesc[4].length != sizeof (*sendChapChallenge)) {
1974 		return (iscsiAuthStatusError);
1975 	}
1976 	sendChapChallenge = (IscsiAuthLargeBinary *) bufferDesc[4].address;
1977 
1978 	bzero(client, sizeof (*client));
1979 	bzero(recvStringBlock, sizeof (*recvStringBlock));
1980 	bzero(sendStringBlock, sizeof (*sendStringBlock));
1981 	bzero(recvChapChallenge, sizeof (*recvChapChallenge));
1982 	bzero(sendChapChallenge, sizeof (*sendChapChallenge));
1983 
1984 	client->recvKeyBlock.stringBlock = recvStringBlock->stringBlock;
1985 	client->sendKeyBlock.stringBlock = sendStringBlock->stringBlock;
1986 	client->recvChapChallenge.largeBinary = recvChapChallenge->largeBinary;
1987 	client->sendChapChallenge.largeBinary = sendChapChallenge->largeBinary;
1988 
1989 	if (iscsiAuthClientCheckNodeType(nodeType)) {
1990 		client->phase = iscsiAuthPhaseError;
1991 		return (iscsiAuthStatusError);
1992 	}
1993 
1994 	client->signature = iscsiAuthClientSignature;
1995 	client->nodeType = (IscsiAuthNodeType) nodeType;
1996 	/* Assume bi-directional authentication enabled. */
1997 	client->authRemote = TRUE;
1998 	client->passwordPresent = FALSE;
1999 	client->version = iscsiAuthVersionRfc;
2000 	client->chapChallengeLength = iscsiAuthChapResponseLength;
2001 	client->ipSec = TRUE;
2002 	client->base64 = FALSE;
2003 
2004 	client->phase = iscsiAuthPhaseConfigure;
2005 	client->negotiatedAuthMethod = iscsiAuthOptionNotPresent;
2006 	client->negotiatedChapAlgorithm = iscsiAuthOptionNotPresent;
2007 
2008 	if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2009 		client->authMethodNegRole = iscsiAuthNegRoleOriginator;
2010 	} else {
2011 		/*
2012 		 * Initial value ignored for Target.
2013 		 */
2014 		client->authMethodNegRole = iscsiAuthNegRoleResponder;
2015 	}
2016 
2017 	/* All supported authentication methods */
2018 	valueList[0] = iscsiAuthMethodChap;
2019 	valueList[1] = iscsiAuthOptionNone;
2020 
2021 	/*
2022 	 * Must call after setting authRemote, password,
2023 	 * version and authMethodNegRole
2024 	 */
2025 	if (iscsiAuthClientSetAuthMethodList(client, 2, valueList) !=
2026 	    iscsiAuthStatusNoError) {
2027 		client->phase = iscsiAuthPhaseError;
2028 		return (iscsiAuthStatusError);
2029 	}
2030 
2031 	valueList[0] = iscsiAuthChapAlgorithmMd5;
2032 
2033 	if (iscsiAuthClientSetChapAlgorithmList(client, 1, valueList) !=
2034 	    iscsiAuthStatusNoError) {
2035 		client->phase = iscsiAuthPhaseError;
2036 		return (iscsiAuthStatusError);
2037 	}
2038 
2039 	return (iscsiAuthStatusNoError);
2040 }
2041 
2042 
2043 int
2044 iscsiAuthClientFinish(IscsiAuthClient * client)
2045 {
2046 	if (!client || client->signature != iscsiAuthClientSignature) {
2047 		return (iscsiAuthStatusError);
2048 	}
2049 
2050 	iscsiAuthClientChapAuthCancel(client);
2051 
2052 	bzero(client, sizeof (*client));
2053 
2054 	return (iscsiAuthStatusNoError);
2055 }
2056 
2057 
2058 static int
2059 iscsiAuthClientSetOptionList(IscsiAuthClient * client,
2060     unsigned int optionCount,
2061     const int *optionList,
2062     unsigned int *clientOptionCount,
2063     int *clientOptionList,
2064     unsigned int optionMaxCount,
2065     int (*checkOption) (int),
2066     int (*checkList) (unsigned int optionCount, const int *optionList))
2067 {
2068 	unsigned int i;
2069 	unsigned int j;
2070 
2071 	if (!client || client->signature != iscsiAuthClientSignature) {
2072 		return (iscsiAuthStatusError);
2073 	}
2074 
2075 	if (client->phase != iscsiAuthPhaseConfigure ||
2076 	    optionCount > optionMaxCount) {
2077 		client->phase = iscsiAuthPhaseError;
2078 		return (iscsiAuthStatusError);
2079 	}
2080 
2081 	for (i = 0; i < optionCount; i++) {
2082 		if ((*checkOption) (optionList[i])) {
2083 			client->phase = iscsiAuthPhaseError;
2084 			return (iscsiAuthStatusError);
2085 		}
2086 	}
2087 
2088 	/*
2089 	 * Check for duplicate entries.
2090 	 */
2091 	for (i = 0; i < optionCount; i++) {
2092 		for (j = 0; j < optionCount; j++) {
2093 			if (j == i)
2094 				continue;
2095 			if (optionList[i] == optionList[j]) {
2096 				client->phase = iscsiAuthPhaseError;
2097 				return (iscsiAuthStatusError);
2098 			}
2099 		}
2100 	}
2101 
2102 	/*
2103 	 * Check for key specific constraints.
2104 	 */
2105 	if (checkList) {
2106 		if ((*checkList) (optionCount, optionList)) {
2107 			client->phase = iscsiAuthPhaseError;
2108 			return (iscsiAuthStatusError);
2109 		}
2110 	}
2111 
2112 	for (i = 0; i < optionCount; i++) {
2113 		clientOptionList[i] = optionList[i];
2114 	}
2115 
2116 	*clientOptionCount = optionCount;
2117 
2118 	return (iscsiAuthStatusNoError);
2119 }
2120 
2121 
2122 static void
2123 iscsiAuthClientSetAuthMethodValid(IscsiAuthClient * client)
2124 {
2125 	static const char rejectOptionNameDraft8[] = "reject";
2126 	static const char rejectOptionNameRfc[] = "Reject";
2127 	static const char noneOptionNameDraft8[] = "none";
2128 	static const char noneOptionNameRfc[] = "None";
2129 	unsigned int i;
2130 	unsigned int j = 0;
2131 	int option = 0;
2132 
2133 	if (client->version == iscsiAuthVersionDraft8) {
2134 		client->rejectOptionName = rejectOptionNameDraft8;
2135 		client->noneOptionName = noneOptionNameDraft8;
2136 	} else {
2137 		client->rejectOptionName = rejectOptionNameRfc;
2138 		client->noneOptionName = noneOptionNameRfc;
2139 	}
2140 
2141 	/*
2142 	 * Following checks may need to be revised if
2143 	 * authentication options other than CHAP and none
2144 	 * are supported.
2145 	 */
2146 
2147 	if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2148 
2149 		if (client->authRemote) {
2150 			/*
2151 			 * If initiator doing authentication,
2152 			 * don't offer authentication option none.
2153 			 */
2154 			option = 1;
2155 		} else if (!client->passwordPresent) {
2156 			/*
2157 			 * If initiator password not set,
2158 			 * only offer authentication option none.
2159 			 */
2160 			option = 2;
2161 		}
2162 	}
2163 
2164 	if (client->nodeType == iscsiAuthNodeTypeTarget) {
2165 
2166 		if (client->authRemote) {
2167 			/*
2168 			 * If target doing authentication,
2169 			 * don't accept authentication option none.
2170 			 */
2171 			option = 1;
2172 		} else {
2173 			/*
2174 			 * If target not doing authentication,
2175 			 * only accept authentication option none.
2176 			 */
2177 			option = 2;
2178 		}
2179 	}
2180 
2181 	for (i = 0; i < client->authMethodCount; i++) {
2182 
2183 		if (option == 1) {
2184 			if (client->authMethodList[i] == iscsiAuthOptionNone) {
2185 				continue;
2186 			}
2187 		} else if (option == 2) {
2188 			if (client->authMethodList[i] != iscsiAuthOptionNone) {
2189 				continue;
2190 			}
2191 		}
2192 
2193 		client->authMethodValidList[j++] = client->authMethodList[i];
2194 	}
2195 
2196 	client->authMethodValidCount = j;
2197 
2198 	iscsiAuthClientInitKeyBlock(&client->sendKeyBlock);
2199 
2200 	if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2201 		if (client->authRemote) {
2202 			/*
2203 			 * Initiator wants to authenticate target,
2204 			 * always send AuthMethod key.
2205 			 */
2206 			client->sendKeyBlock.transitBit = FALSE;
2207 			client->authMethodValidNegRole =
2208 			    iscsiAuthNegRoleOriginator;
2209 		} else {
2210 			client->sendKeyBlock.transitBit = TRUE;
2211 			client->authMethodValidNegRole =
2212 			    client->authMethodNegRole;
2213 		}
2214 	} else {
2215 		client->sendKeyBlock.transitBit = FALSE;
2216 		client->authMethodValidNegRole = iscsiAuthNegRoleResponder;
2217 	}
2218 
2219 	if (client->authMethodValidNegRole == iscsiAuthNegRoleOriginator) {
2220 		iscsiAuthClientSetAuthMethodKey(client,
2221 		    client->authMethodValidCount,
2222 		    client->authMethodValidList);
2223 	} else {
2224 		int value = iscsiAuthOptionNotPresent;
2225 		iscsiAuthClientSetAuthMethodKey(client, 1, &value);
2226 	}
2227 }
2228 
2229 
2230 static int
2231 iscsiAuthClientCheckAuthMethodList(unsigned int optionCount,
2232     const int *optionList)
2233 {
2234 	unsigned int i;
2235 
2236 	if (!optionList || optionCount < 2) {
2237 		return (TRUE);
2238 	}
2239 
2240 	if (optionList[optionCount - 1] != iscsiAuthOptionNone) {
2241 		return (TRUE);
2242 	}
2243 
2244 	for (i = 0; i < (optionCount - 1); i++) {
2245 		if (optionList[i] != iscsiAuthOptionNone) {
2246 			return (FALSE);
2247 		}
2248 	}
2249 
2250 	return (FALSE);
2251 }
2252 
2253 
2254 int
2255 iscsiAuthClientSetAuthMethodList(IscsiAuthClient * client,
2256     unsigned int optionCount, const int *optionList)
2257 {
2258 	int status;
2259 
2260 	status = iscsiAuthClientSetOptionList(
2261 	    client, optionCount, optionList, &client->authMethodCount,
2262 	    client->authMethodList, iscsiAuthMethodMaxCount,
2263 	    iscsiAuthClientCheckAuthMethodOption,
2264 	    iscsiAuthClientCheckAuthMethodList);
2265 
2266 	if (status != iscsiAuthStatusNoError) {
2267 		return (status);
2268 	}
2269 
2270 	/*
2271 	 * Setting authMethod affects authMethodValid.
2272 	 */
2273 	iscsiAuthClientSetAuthMethodValid(client);
2274 
2275 	return (iscsiAuthStatusNoError);
2276 }
2277 
2278 
2279 int
2280 iscsiAuthClientSetAuthMethodNegRole(IscsiAuthClient * client, int negRole)
2281 {
2282 	if (!client || client->signature != iscsiAuthClientSignature) {
2283 		return (iscsiAuthStatusError);
2284 	}
2285 
2286 	if (client->phase != iscsiAuthPhaseConfigure ||
2287 	    iscsiAuthClientCheckNegRole(negRole) ||
2288 	    client->nodeType != iscsiAuthNodeTypeInitiator) {
2289 
2290 		client->phase = iscsiAuthPhaseError;
2291 		return (iscsiAuthStatusError);
2292 	}
2293 
2294 	client->authMethodNegRole = (IscsiAuthNegRole) negRole;
2295 
2296 	/*
2297 	 * Setting negRole affects authMethodValid.
2298 	 */
2299 	iscsiAuthClientSetAuthMethodValid(client);
2300 
2301 	return (iscsiAuthStatusNoError);
2302 }
2303 
2304 
2305 static int
2306 iscsiAuthClientCheckChapAlgorithmList(unsigned int optionCount,
2307     const int *optionList)
2308 {
2309 	if (!optionList || optionCount < 1) {
2310 		return (TRUE);
2311 	}
2312 
2313 	return (FALSE);
2314 }
2315 
2316 
2317 int
2318 iscsiAuthClientSetChapAlgorithmList(IscsiAuthClient * client,
2319     unsigned int optionCount, const int *optionList)
2320 {
2321 	return (iscsiAuthClientSetOptionList(client,
2322 	    optionCount,
2323 	    optionList,
2324 	    &client->chapAlgorithmCount,
2325 	    client->chapAlgorithmList,
2326 	    iscsiAuthChapAlgorithmMaxCount,
2327 	    iscsiAuthClientCheckChapAlgorithmOption,
2328 	    iscsiAuthClientCheckChapAlgorithmList));
2329 }
2330 
2331 
2332 int
2333 iscsiAuthClientSetUsername(IscsiAuthClient * client, const char *username)
2334 {
2335 	if (!client || client->signature != iscsiAuthClientSignature) {
2336 		return (iscsiAuthStatusError);
2337 	}
2338 
2339 	if (client->phase != iscsiAuthPhaseConfigure ||
2340 	    iscsiAuthClientCheckString(username, iscsiAuthStringMaxLength, 0)) {
2341 		client->phase = iscsiAuthPhaseError;
2342 		return (iscsiAuthStatusError);
2343 	}
2344 
2345 	if (iscsiAuthClientStringCopy(client->username, username,
2346 	    iscsiAuthStringMaxLength)) {
2347 		client->phase = iscsiAuthPhaseError;
2348 		return (iscsiAuthStatusError);
2349 	}
2350 
2351 	return (iscsiAuthStatusNoError);
2352 }
2353 
2354 
2355 int
2356 iscsiAuthClientSetPassword(IscsiAuthClient * client,
2357     const unsigned char *passwordData, unsigned int passwordLength)
2358 {
2359 	if (!client || client->signature != iscsiAuthClientSignature) {
2360 		return (iscsiAuthStatusError);
2361 	}
2362 
2363 	if (client->phase != iscsiAuthPhaseConfigure ||
2364 	    passwordLength > iscsiAuthStringMaxLength) {
2365 
2366 		client->phase = iscsiAuthPhaseError;
2367 		return (iscsiAuthStatusError);
2368 	}
2369 
2370 	bcopy(passwordData, client->passwordData, passwordLength);
2371 	client->passwordLength = passwordLength;
2372 	if (client->passwordLength > 0) {
2373 		client->passwordPresent = TRUE;
2374 	} else {
2375 		client->passwordPresent = FALSE;
2376 	}
2377 
2378 	/*
2379 	 * Setting password may affect authMethodValid.
2380 	 */
2381 	iscsiAuthClientSetAuthMethodValid(client);
2382 
2383 	return (iscsiAuthStatusNoError);
2384 }
2385 
2386 
2387 int
2388 iscsiAuthClientSetAuthRemote(IscsiAuthClient * client, int authRemote)
2389 {
2390 	if (!client || client->signature != iscsiAuthClientSignature) {
2391 		return (iscsiAuthStatusError);
2392 	}
2393 
2394 	if (client->phase != iscsiAuthPhaseConfigure) {
2395 		client->phase = iscsiAuthPhaseError;
2396 		return (iscsiAuthStatusError);
2397 	}
2398 
2399 	client->authRemote = authRemote;
2400 
2401 	/*
2402 	 * Setting authRemote may affect authMethodValid.
2403 	 */
2404 	iscsiAuthClientSetAuthMethodValid(client);
2405 
2406 	return (iscsiAuthStatusNoError);
2407 }
2408 
2409 
2410 int
2411 iscsiAuthClientSetGlueHandle(IscsiAuthClient * client, void *glueHandle)
2412 {
2413 	if (!client || client->signature != iscsiAuthClientSignature) {
2414 		return (iscsiAuthStatusError);
2415 	}
2416 
2417 	if (client->phase != iscsiAuthPhaseConfigure &&
2418 	    client->phase != iscsiAuthPhaseNegotiate &&
2419 	    client->phase != iscsiAuthPhaseAuthenticate) {
2420 
2421 		client->phase = iscsiAuthPhaseError;
2422 		return (iscsiAuthStatusError);
2423 	}
2424 
2425 	client->glueHandle = glueHandle;
2426 
2427 	return (iscsiAuthStatusNoError);
2428 }
2429 
2430 
2431 int
2432 iscsiAuthClientSetMethodListName(IscsiAuthClient *client,
2433     const char *methodListName)
2434 {
2435 	if (!client || client->signature != iscsiAuthClientSignature) {
2436 		return (iscsiAuthStatusError);
2437 	}
2438 
2439 	if (client->phase != iscsiAuthPhaseConfigure ||
2440 	    iscsiAuthClientCheckString(methodListName,
2441 	    iscsiAuthStringMaxLength, 0)) {
2442 
2443 		client->phase = iscsiAuthPhaseError;
2444 		return (iscsiAuthStatusError);
2445 	}
2446 
2447 	if (iscsiAuthClientStringCopy(client->methodListName, methodListName,
2448 	    iscsiAuthStringMaxLength)) {
2449 
2450 		client->phase = iscsiAuthPhaseError;
2451 		return (iscsiAuthStatusError);
2452 	}
2453 
2454 	return (iscsiAuthStatusNoError);
2455 }
2456 
2457 
2458 int
2459 iscsiAuthClientSetVersion(IscsiAuthClient * client, int version)
2460 {
2461 	if (client == 0 ||
2462 	    client->signature != iscsiAuthClientSignature) {
2463 		return (iscsiAuthStatusError);
2464 	}
2465 
2466 	if (client->phase != iscsiAuthPhaseConfigure ||
2467 	    iscsiAuthClientCheckVersion(version)) {
2468 
2469 		client->phase = iscsiAuthPhaseError;
2470 		return (iscsiAuthStatusError);
2471 	}
2472 
2473 	client->version = (IscsiAuthVersion) version;
2474 
2475 	iscsiAuthClientSetAuthMethodValid(client);
2476 
2477 	return (iscsiAuthStatusNoError);
2478 }
2479 
2480 
2481 int
2482 iscsiAuthClientSetIpSec(IscsiAuthClient * client, int ipSec)
2483 {
2484 	if (!client || client->signature != iscsiAuthClientSignature) {
2485 		return (iscsiAuthStatusError);
2486 	}
2487 
2488 	if (client->phase != iscsiAuthPhaseConfigure) {
2489 		client->phase = iscsiAuthPhaseError;
2490 		return (iscsiAuthStatusError);
2491 	}
2492 
2493 	client->ipSec = ipSec;
2494 
2495 	return (iscsiAuthStatusNoError);
2496 }
2497 
2498 
2499 int
2500 iscsiAuthClientSetBase64(IscsiAuthClient * client, int base64)
2501 {
2502 	if (!client || client->signature != iscsiAuthClientSignature) {
2503 		return (iscsiAuthStatusError);
2504 	}
2505 
2506 	if (client->phase != iscsiAuthPhaseConfigure) {
2507 		client->phase = iscsiAuthPhaseError;
2508 		return (iscsiAuthStatusError);
2509 	}
2510 
2511 	client->base64 = base64;
2512 
2513 	return (iscsiAuthStatusNoError);
2514 }
2515 
2516 
2517 int
2518 iscsiAuthClientSetChapChallengeLength(IscsiAuthClient * client,
2519     unsigned int chapChallengeLength)
2520 {
2521 	if (!client || client->signature != iscsiAuthClientSignature) {
2522 		return (iscsiAuthStatusError);
2523 	}
2524 
2525 	if (client->phase != iscsiAuthPhaseConfigure ||
2526 	    chapChallengeLength < iscsiAuthChapResponseLength ||
2527 	    chapChallengeLength > iscsiAuthLargeBinaryMaxLength) {
2528 
2529 		client->phase = iscsiAuthPhaseError;
2530 		return (iscsiAuthStatusError);
2531 	}
2532 
2533 	client->chapChallengeLength = chapChallengeLength;
2534 
2535 	return (iscsiAuthStatusNoError);
2536 }
2537 
2538 
2539 int
2540 iscsiAuthClientCheckPasswordNeeded(IscsiAuthClient *client, int *passwordNeeded)
2541 {
2542 	if (!client || client->signature != iscsiAuthClientSignature) {
2543 		return (iscsiAuthStatusError);
2544 	}
2545 
2546 	if (client->phase != iscsiAuthPhaseConfigure) {
2547 		client->phase = iscsiAuthPhaseError;
2548 		return (iscsiAuthStatusError);
2549 	}
2550 
2551 	if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2552 		if (client->authRemote && !client->passwordPresent) {
2553 			*passwordNeeded = TRUE;
2554 		} else {
2555 			*passwordNeeded = FALSE;
2556 		}
2557 	} else {
2558 		*passwordNeeded = FALSE;
2559 	}
2560 
2561 	return (iscsiAuthStatusNoError);
2562 }
2563 
2564 
2565 int
2566 iscsiAuthClientGetAuthPhase(IscsiAuthClient * client, int *value)
2567 {
2568 	if (!client || client->signature != iscsiAuthClientSignature) {
2569 		return (iscsiAuthStatusError);
2570 	}
2571 
2572 	*value = client->phase;
2573 
2574 	return (iscsiAuthStatusNoError);
2575 }
2576 
2577 
2578 int
2579 iscsiAuthClientGetAuthStatus(IscsiAuthClient * client, int *value)
2580 {
2581 	if (!client || client->signature != iscsiAuthClientSignature) {
2582 		return (iscsiAuthStatusError);
2583 	}
2584 
2585 	if (client->phase != iscsiAuthPhaseDone) {
2586 
2587 		client->phase = iscsiAuthPhaseError;
2588 		return (iscsiAuthStatusError);
2589 	}
2590 
2591 	*value = client->remoteAuthStatus;
2592 
2593 	return (iscsiAuthStatusNoError);
2594 }
2595 
2596 
2597 int
2598 iscsiAuthClientAuthStatusPass(int authStatus)
2599 {
2600 	if (authStatus == iscsiAuthStatusPass) {
2601 		return (TRUE);
2602 	}
2603 
2604 	return (FALSE);
2605 }
2606 
2607 
2608 int
2609 iscsiAuthClientGetAuthMethod(IscsiAuthClient * client, int *value)
2610 {
2611 	if (!client || client->signature != iscsiAuthClientSignature) {
2612 		return (iscsiAuthStatusError);
2613 	}
2614 
2615 	if (client->phase != iscsiAuthPhaseDone &&
2616 	    client->phase != iscsiAuthPhaseAuthenticate) {
2617 		client->phase = iscsiAuthPhaseError;
2618 		return (iscsiAuthStatusError);
2619 	}
2620 
2621 	*value = client->negotiatedAuthMethod;
2622 
2623 	return (iscsiAuthStatusNoError);
2624 }
2625 
2626 
2627 int
2628 iscsiAuthClientGetChapAlgorithm(IscsiAuthClient * client, int *value)
2629 {
2630 	if (!client || client->signature != iscsiAuthClientSignature) {
2631 		return (iscsiAuthStatusError);
2632 	}
2633 
2634 	if (client->phase != iscsiAuthPhaseDone) {
2635 
2636 		client->phase = iscsiAuthPhaseError;
2637 		return (iscsiAuthStatusError);
2638 	}
2639 
2640 	*value = client->negotiatedChapAlgorithm;
2641 
2642 	return (iscsiAuthStatusNoError);
2643 }
2644 
2645 
2646 int
2647 iscsiAuthClientGetChapUsername(IscsiAuthClient * client,
2648     char *value, unsigned int maxLength)
2649 {
2650 	if (!client || client->signature != iscsiAuthClientSignature) {
2651 		return (iscsiAuthStatusError);
2652 	}
2653 
2654 	if (client->phase != iscsiAuthPhaseDone) {
2655 
2656 		client->phase = iscsiAuthPhaseError;
2657 		return (iscsiAuthStatusError);
2658 	}
2659 
2660 	if (iscsiAuthClientStringCopy(value, client->chapUsername, maxLength)) {
2661 		client->phase = iscsiAuthPhaseError;
2662 		return (iscsiAuthStatusError);
2663 	}
2664 
2665 	return (iscsiAuthStatusNoError);
2666 }
2667 
2668 
2669 int
2670 iscsiAuthClientSendStatusCode(IscsiAuthClient * client, int *statusCode)
2671 {
2672 	if (!client || client->signature != iscsiAuthClientSignature) {
2673 		return (iscsiAuthStatusError);
2674 	}
2675 
2676 	if (client->phase != iscsiAuthPhaseConfigure &&
2677 	    client->phase != iscsiAuthPhaseNegotiate &&
2678 	    client->phase != iscsiAuthPhaseAuthenticate &&
2679 	    client->phase != iscsiAuthPhaseDone) {
2680 
2681 		client->phase = iscsiAuthPhaseError;
2682 		return (iscsiAuthStatusError);
2683 	}
2684 
2685 	if (client->phase != iscsiAuthPhaseDone) {
2686 		*statusCode = 0x0000;
2687 		return (iscsiAuthStatusNoError);
2688 	}
2689 
2690 	switch (client->remoteAuthStatus) {
2691 	case iscsiAuthStatusPass:
2692 		*statusCode = 0x0000;	/* no error */
2693 		break;
2694 
2695 	case iscsiAuthStatusFail:
2696 		switch (client->debugStatus) {
2697 		case iscsiAuthDebugStatusAuthFail:
2698 			/*
2699 			 * Authentication error with peer.
2700 			 */
2701 			if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2702 				*statusCode = 0x0300;
2703 				/*
2704 				 * iSCSI Target error
2705 				 */
2706 			} else {
2707 				*statusCode = 0x0201;
2708 				/*
2709 				 * iSCSI Initiator error
2710 				 */
2711 			}
2712 			break;
2713 
2714 		case iscsiAuthDebugStatusAuthMethodExpected:
2715 		case iscsiAuthDebugStatusChapAlgorithmExpected:
2716 		case iscsiAuthDebugStatusChapIdentifierExpected:
2717 		case iscsiAuthDebugStatusChapChallengeExpected:
2718 		case iscsiAuthDebugStatusChapResponseExpected:
2719 		case iscsiAuthDebugStatusChapUsernameExpected:
2720 			/*
2721 			 * Missing parameter with peer.
2722 			 */
2723 			if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2724 				*statusCode = 0x0300;
2725 				/*
2726 				 * iSCSI Target error
2727 				 */
2728 			} else {
2729 				*statusCode = 0x0207;
2730 				/*
2731 				 * iSCSI Initiator error
2732 				 */
2733 			}
2734 			break;
2735 
2736 		case iscsiAuthDebugStatusAuthMethodNotPresent:
2737 		case iscsiAuthDebugStatusAuthMethodReject:
2738 		case iscsiAuthDebugStatusAuthMethodNone:
2739 		case iscsiAuthDebugStatusChapAlgorithmReject:
2740 		case iscsiAuthDebugStatusChapChallengeReflected:
2741 		case iscsiAuthDebugStatusPasswordIdentical:
2742 			/*
2743 			 * Could not authenticate with peer.
2744 			 */
2745 			if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2746 				*statusCode = 0x0300;
2747 				/*
2748 				 * iSCSI Target error
2749 				 */
2750 			} else {
2751 				*statusCode = 0x0201;
2752 				/*
2753 				 * iSCSI Initiator error
2754 				 */
2755 			}
2756 			break;
2757 
2758 		case iscsiAuthDebugStatusLocalPasswordNotSet:
2759 			/*
2760 			 * Local password not set.
2761 			 */
2762 			if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2763 				*statusCode = 0x0200;
2764 				/*
2765 				 * iSCSI Initiator error
2766 				 */
2767 			} else {
2768 				*statusCode = 0x0201;
2769 				/*
2770 				 * iSCSI Target error
2771 				 */
2772 			}
2773 			break;
2774 
2775 		case iscsiAuthDebugStatusChapIdentifierBad:
2776 		case iscsiAuthDebugStatusChapChallengeBad:
2777 		case iscsiAuthDebugStatusChapResponseBad:
2778 		case iscsiAuthDebugStatusUnexpectedKeyPresent:
2779 		case iscsiAuthDebugStatusTbitSetIllegal:
2780 		case iscsiAuthDebugStatusTbitSetPremature:
2781 		case iscsiAuthDebugStatusRecvMessageCountLimit:
2782 		case iscsiAuthDebugStatusRecvDuplicateSetKeyValue:
2783 		case iscsiAuthDebugStatusRecvStringTooLong:
2784 		case iscsiAuthDebugStatusRecvTooMuchData:
2785 			/*
2786 			 * Other error with peer.
2787 			 */
2788 			if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2789 				*statusCode = 0x0300;
2790 				/*
2791 				 * iSCSI Target error
2792 				 */
2793 			} else {
2794 				*statusCode = 0x0200;
2795 				/*
2796 				 * iSCSI Initiator error
2797 				 */
2798 			}
2799 			break;
2800 
2801 		case iscsiAuthDebugStatusNotSet:
2802 		case iscsiAuthDebugStatusAuthPass:
2803 		case iscsiAuthDebugStatusAuthRemoteFalse:
2804 		case iscsiAuthDebugStatusAuthMethodBad:
2805 		case iscsiAuthDebugStatusChapAlgorithmBad:
2806 		case iscsiAuthDebugStatusPasswordDecryptFailed:
2807 		case iscsiAuthDebugStatusPasswordTooShortWithNoIpSec:
2808 		case iscsiAuthDebugStatusAuthServerError:
2809 		case iscsiAuthDebugStatusAuthStatusBad:
2810 		case iscsiAuthDebugStatusAuthPassNotValid:
2811 		case iscsiAuthDebugStatusSendDuplicateSetKeyValue:
2812 		case iscsiAuthDebugStatusSendStringTooLong:
2813 		case iscsiAuthDebugStatusSendTooMuchData:
2814 		default:
2815 			/*
2816 			 * Error on this side.
2817 			 */
2818 			if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2819 				*statusCode = 0x0200;
2820 				/*
2821 				 * iSCSI Initiator error
2822 				 */
2823 			} else {
2824 				*statusCode = 0x0300;
2825 				/*
2826 				 * iSCSI Target error
2827 				 */
2828 			}
2829 
2830 		}
2831 		break;
2832 
2833 	case iscsiAuthStatusNoError:
2834 	case iscsiAuthStatusError:
2835 	case iscsiAuthStatusContinue:
2836 	case iscsiAuthStatusInProgress:
2837 	default:
2838 		/*
2839 		 * Bad authStatus
2840 		 */
2841 		if (client->nodeType == iscsiAuthNodeTypeInitiator) {
2842 			*statusCode = 0x0200;
2843 			/*
2844 			 * iSCSI Initiator error
2845 			 */
2846 		} else {
2847 			*statusCode = 0x0300;
2848 			/*
2849 			 * iSCSI Target error
2850 			 */
2851 		}
2852 	}
2853 
2854 	return (iscsiAuthStatusNoError);
2855 }
2856 
2857 
2858 int
2859 iscsiAuthClientGetDebugStatus(IscsiAuthClient * client, int *value)
2860 {
2861 	if (!client || client->signature != iscsiAuthClientSignature) {
2862 		return (iscsiAuthStatusError);
2863 	}
2864 
2865 	if (client->phase != iscsiAuthPhaseDone) {
2866 
2867 		client->phase = iscsiAuthPhaseError;
2868 		return (iscsiAuthStatusError);
2869 	}
2870 
2871 	*value = client->debugStatus;
2872 
2873 	return (iscsiAuthStatusNoError);
2874 }
2875 
2876 
2877 const char *
2878 iscsiAuthClientDebugStatusToText(int debugStatus)
2879 {
2880 	const char *s;
2881 
2882 	switch (debugStatus) {
2883 	case iscsiAuthDebugStatusNotSet:
2884 		s = "Debug status not set";
2885 		break;
2886 
2887 	case iscsiAuthDebugStatusAuthPass:
2888 		s = "Authentication request passed";
2889 		break;
2890 
2891 	case iscsiAuthDebugStatusAuthRemoteFalse:
2892 		s = "Authentication not enabled";
2893 		break;
2894 
2895 	case iscsiAuthDebugStatusAuthFail:
2896 		s = "Authentication request failed";
2897 		break;
2898 
2899 	case iscsiAuthDebugStatusAuthMethodBad:
2900 		s = "AuthMethod bad";
2901 		break;
2902 
2903 	case iscsiAuthDebugStatusChapAlgorithmBad:
2904 		s = "CHAP algorithm bad";
2905 		break;
2906 
2907 	case iscsiAuthDebugStatusPasswordDecryptFailed:
2908 		s = "Decrypt password failed";
2909 		break;
2910 
2911 	case iscsiAuthDebugStatusPasswordTooShortWithNoIpSec:
2912 		s = "Local password too short with no IPSec";
2913 		break;
2914 
2915 	case iscsiAuthDebugStatusAuthServerError:
2916 		s = "Unexpected error from authentication server";
2917 		break;
2918 
2919 	case iscsiAuthDebugStatusAuthStatusBad:
2920 		s = "Authentication request status bad";
2921 		break;
2922 
2923 	case iscsiAuthDebugStatusAuthPassNotValid:
2924 		s = "Authentication pass status not valid";
2925 		break;
2926 
2927 	case iscsiAuthDebugStatusSendDuplicateSetKeyValue:
2928 		s = "Same key set more than once on send";
2929 		break;
2930 
2931 	case iscsiAuthDebugStatusSendStringTooLong:
2932 		s = "Key value too long on send";
2933 		break;
2934 
2935 	case iscsiAuthDebugStatusSendTooMuchData:
2936 		s = "Too much data on send";
2937 		break;
2938 
2939 	case iscsiAuthDebugStatusAuthMethodExpected:
2940 		s = "AuthMethod key expected";
2941 		break;
2942 
2943 	case iscsiAuthDebugStatusChapAlgorithmExpected:
2944 		s = "CHAP algorithm key expected";
2945 		break;
2946 
2947 	case iscsiAuthDebugStatusChapIdentifierExpected:
2948 		s = "CHAP identifier expected";
2949 		break;
2950 
2951 	case iscsiAuthDebugStatusChapChallengeExpected:
2952 		s = "CHAP challenge expected";
2953 		break;
2954 
2955 	case iscsiAuthDebugStatusChapResponseExpected:
2956 		s = "CHAP response expected";
2957 		break;
2958 
2959 	case iscsiAuthDebugStatusChapUsernameExpected:
2960 		s = "CHAP username expected";
2961 		break;
2962 
2963 	case iscsiAuthDebugStatusAuthMethodNotPresent:
2964 		s = "AuthMethod key not present";
2965 		break;
2966 
2967 	case iscsiAuthDebugStatusAuthMethodReject:
2968 		s = "AuthMethod negotiation failed";
2969 		break;
2970 
2971 	case iscsiAuthDebugStatusAuthMethodNone:
2972 		s = "AuthMethod negotiated to none";
2973 		break;
2974 
2975 	case iscsiAuthDebugStatusChapAlgorithmReject:
2976 		s = "CHAP algorithm negotiation failed";
2977 		break;
2978 
2979 	case iscsiAuthDebugStatusChapChallengeReflected:
2980 		s = "CHAP challange reflected";
2981 		break;
2982 
2983 	case iscsiAuthDebugStatusPasswordIdentical:
2984 		s = "Local password same as remote";
2985 		break;
2986 
2987 	case iscsiAuthDebugStatusLocalPasswordNotSet:
2988 		s = "Local password not set";
2989 		break;
2990 
2991 	case iscsiAuthDebugStatusChapIdentifierBad:
2992 		s = "CHAP identifier bad";
2993 		break;
2994 
2995 	case iscsiAuthDebugStatusChapChallengeBad:
2996 		s = "CHAP challenge bad";
2997 		break;
2998 
2999 	case iscsiAuthDebugStatusChapResponseBad:
3000 		s = "CHAP response bad";
3001 		break;
3002 
3003 	case iscsiAuthDebugStatusUnexpectedKeyPresent:
3004 		s = "Unexpected key present";
3005 		break;
3006 
3007 	case iscsiAuthDebugStatusTbitSetIllegal:
3008 		s = "T bit set on response, but not on previous message";
3009 		break;
3010 
3011 	case iscsiAuthDebugStatusTbitSetPremature:
3012 		s = "T bit set on response, but authenticaton not complete";
3013 		break;
3014 
3015 	case iscsiAuthDebugStatusRecvMessageCountLimit:
3016 		s = "Message count limit reached on receive";
3017 		break;
3018 
3019 	case iscsiAuthDebugStatusRecvDuplicateSetKeyValue:
3020 		s = "Same key set more than once on receive";
3021 		break;
3022 
3023 	case iscsiAuthDebugStatusRecvStringTooLong:
3024 		s = "Key value too long on receive";
3025 		break;
3026 
3027 	case iscsiAuthDebugStatusRecvTooMuchData:
3028 		s = "Too much data on receive";
3029 		break;
3030 
3031 	default:
3032 		s = "Unknown error";
3033 	}
3034 
3035 	return (s);
3036 }
3037