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 2009 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