/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2000 by Cisco Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* This file implements the iSCSI CHAP authentication method based.
* The code in this file is meant to be platform independent, and
* makes use of only limited library functions, presently only string.h.
* Platform dependent routines are defined in iscsiAuthClient.h, but
* implemented in another file.
*
* This code in this files assumes a single thread of execution
* for each IscsiAuthClient structure, and does no locking.
*/
#include "iscsi.h"
#include "iscsiAuthClient.h"
struct iscsiAuthKeyInfo_t {
const char *name;
};
typedef struct iscsiAuthKeyInfo_t IscsiAuthKeyInfo;
IscsiAuthClientGlobalStats iscsiAuthClientGlobalStats;
/*
* Note: The ordering of this table must match the order
* defined by IscsiAuthKeyType in iscsiAuthClient.h.
*/
static IscsiAuthKeyInfo iscsiAuthClientKeyInfo[iscsiAuthKeyTypeMaxCount] = {
{"AuthMethod"},
{"CHAP_A"},
{"CHAP_N"},
{"CHAP_R"},
{"CHAP_I"},
{"CHAP_C"}
};
static const char iscsiAuthClientHexString[] = "0123456789abcdefABCDEF";
static const char iscsiAuthClientBase64String[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char iscsiAuthClientAuthMethodChapOptionName[] = "CHAP";
static int
iscsiAuthClientCheckString(const char *s,
unsigned int maxLength, unsigned int *pOutLength)
{
unsigned int length;
if (!s) {
return (TRUE);
}
for (length = 0; length < maxLength; length++) {
if (*s++ == '\0') {
if (pOutLength) {
*pOutLength = length;
}
return (FALSE);
}
}
return (TRUE);
}
static int
iscsiAuthClientStringCopy(char *stringOut, const char *stringIn,
unsigned int length)
{
if (!stringOut || !stringIn || length == 0) {
return (TRUE);
}
while ((*stringOut++ = *stringIn++) != '\0') {
if (--length == 0) {
stringOut--;
*stringOut = '\0';
return (TRUE);
}
}
return (FALSE);
}
static int
iscsiAuthClientStringAppend(char *stringOut, const char *stringIn,
unsigned int length)
{
if (!stringOut || !stringIn || length == 0) {
return (TRUE);
}
while (*stringOut++ != '\0') {
if (--length == 0) {
stringOut--;
*stringOut = '\0';
return (TRUE);
}
}
stringOut--;
while ((*stringOut++ = *stringIn++) != '\0') {
if (--length == 0) {
stringOut--;
*stringOut = '\0';
return (TRUE);
}
}
return (FALSE);
}
static int
iscsiAuthClientStringIndex(const char *s, int c)
{
int n = 0;
while (*s != '\0') {
if (*s++ == c) {
return (n);
}
n++;
}
return (-1);
}
static int
iscsiAuthClientCheckNodeType(int nodeType)
{
if (nodeType == iscsiAuthNodeTypeInitiator ||
nodeType == iscsiAuthNodeTypeTarget) {
return (FALSE);
}
return (TRUE);
}
static int
iscsiAuthClientCheckVersion(int value)
{
if (value == iscsiAuthVersionDraft8 || value == iscsiAuthVersionRfc) {
return (FALSE);
}
return (TRUE);
}
static int
iscsiAuthClientCheckNegRole(int value)
{
if (value == iscsiAuthNegRoleOriginator ||
value == iscsiAuthNegRoleResponder) {
return (FALSE);
}
return (TRUE);
}
static int
iscsiAuthClientCheckAuthMethodOption(int value)
{
if (value == iscsiAuthOptionNone || value == iscsiAuthMethodChap) {
return (FALSE);
}
return (TRUE);
}
static const char *
iscsiAuthClientAuthMethodOptionToText(IscsiAuthClient * client, int value)
{
const char *s;
switch (value) {
case iscsiAuthOptionReject:
s = client->rejectOptionName;
break;
case iscsiAuthOptionNone:
s = client->noneOptionName;
break;
case iscsiAuthMethodChap:
s = iscsiAuthClientAuthMethodChapOptionName;
break;
default:
s = 0;
}
return (s);
}
static int
iscsiAuthClientCheckChapAlgorithmOption(int chapAlgorithm)
{
if (chapAlgorithm == iscsiAuthOptionNone ||
chapAlgorithm == iscsiAuthChapAlgorithmMd5) {
return (FALSE);
}
return (TRUE);
}
static int
iscsiAuthClientDataToHex(unsigned char *data, unsigned int dataLength,
char *text, unsigned int textLength)
{
unsigned long n;
if (!text || textLength == 0) {
return (TRUE);
}
if (!data || dataLength == 0) {
*text = '\0';
return (TRUE);
}
if (textLength < 3) {
*text = '\0';
return (TRUE);
}
*text++ = '0';
*text++ = 'x';
textLength -= 2;
while (dataLength > 0) {
if (textLength < 3) {
*text = '\0';
return (TRUE);
}
n = *data++;
dataLength--;
*text++ = iscsiAuthClientHexString[(n >> 4) & 0xf];
*text++ = iscsiAuthClientHexString[n & 0xf];
textLength -= 2;
}
*text = '\0';
return (FALSE);
}
static int
iscsiAuthClientDataToBase64(unsigned char *data, unsigned int dataLength,
char *text, unsigned int textLength)
{
unsigned long n;
if (!text || textLength == 0) {
return (TRUE);
}
if (!data || dataLength == 0) {
*text = '\0';
return (TRUE);
}
if (textLength < 3) {
*text = '\0';
return (TRUE);
}
*text++ = '0';
*text++ = 'b';
textLength -= 2;
while (dataLength >= 3) {
if (textLength < 5) {
*text = '\0';
return (TRUE);
}
n = *data++;
n = (n << 8) | *data++;
n = (n << 8) | *data++;
dataLength -= 3;
*text++ = iscsiAuthClientBase64String[(n >> 18) & 0x3f];
*text++ = iscsiAuthClientBase64String[(n >> 12) & 0x3f];
*text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f];
*text++ = iscsiAuthClientBase64String[n & 0x3f];
textLength -= 4;
}
if (dataLength == 1) {
if (textLength < 5) {
*text = '\0';
return (TRUE);
}
n = *data++;
n = n << 4;
*text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f];
*text++ = iscsiAuthClientBase64String[n & 0x3f];
*text++ = '=';
*text++ = '=';
} else if (dataLength == 2) {
if (textLength < 5) {
return (TRUE);
}
n = *data++;
n = (n << 8) | *data++;
n = n << 2;
*text++ = iscsiAuthClientBase64String[(n >> 12) & 0x3f];
*text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f];
*text++ = iscsiAuthClientBase64String[n & 0x3f];
*text++ = '=';
}
*text = '\0';
return (FALSE);
}
static int
iscsiAuthClientDataToText(int base64, unsigned char *data,
unsigned int dataLength, char *text, unsigned int textLength)
{
int status;
if (base64) {
status = iscsiAuthClientDataToBase64(
data, dataLength, text, textLength);
} else {
status = iscsiAuthClientDataToHex(
data, dataLength, text, textLength);
}
return (status);
}
static int
iscsiAuthClientHexToData(const char *text, unsigned int textLength,
unsigned char *data, unsigned int *pDataLength)
{
int i;
unsigned int n1;
unsigned int n2;
unsigned int dataLength = *pDataLength;
if ((textLength % 2) == 1) {
i = iscsiAuthClientStringIndex(iscsiAuthClientHexString,
*text++);
if (i < 0) {
return (TRUE); /* error, bad character */
}
if (i > 15)
i -= 6;
n2 = i;
if (dataLength < 1) {
return (TRUE); /* error, too much data */
}
*data++ = n2;
dataLength--;
}
while (*text != '\0') {
i = iscsiAuthClientStringIndex(
iscsiAuthClientHexString, *text++);
if (i < 0) {
return (TRUE); /* error, bad character */
}
if (i > 15)
i -= 6;
n1 = i;
if (*text == '\0') {
return (TRUE); /* error, odd string length */
}
i = iscsiAuthClientStringIndex(
iscsiAuthClientHexString, *text++);
if (i < 0) {
return (TRUE); /* error, bad character */
}
if (i > 15)
i -= 6;
n2 = i;
if (dataLength < 1) {
return (TRUE); /* error, too much data */
}
*data++ = (n1 << 4) | n2;
dataLength--;
}
if (dataLength >= *pDataLength) {
return (TRUE); /* error, no data */
}
*pDataLength = *pDataLength - dataLength;
return (FALSE); /* no error */
}
static int
iscsiAuthClientBase64ToData(const char *text, unsigned int textLength,
unsigned char *data, unsigned int *pDataLength)
{
int i;
unsigned int n;
unsigned int count;
unsigned int dataLength = *pDataLength;
textLength = textLength; /* not used */
n = 0;
count = 0;
while (*text != '\0' && *text != '=') {
i = iscsiAuthClientStringIndex(
iscsiAuthClientBase64String, *text++);
if (i < 0) {
return (TRUE); /* error, bad character */
}
n = (n << 6 | (unsigned int)i);
count++;
if (count >= 4) {
if (dataLength < 3) {
return (TRUE); /* error, too much data */
}
*data++ = n >> 16;
*data++ = n >> 8;
*data++ = n;
dataLength -= 3;
n = 0;
count = 0;
}
}
while (*text != '\0') {
if (*text++ != '=') {
return (TRUE); /* error, bad pad */
}
}
if (count == 0) {
/*
* do nothing
*/
/* EMPTY */
} else if (count == 2) {
if (dataLength < 1) {
return (TRUE); /* error, too much data */
}
n = n >> 4;
*data++ = n;
dataLength--;
} else if (count == 3) {
if (dataLength < 2) {
return (TRUE); /* error, too much data */
}
n = n >> 2;
*data++ = n >> 8;
*data++ = n;
dataLength -= 2;
} else {
return (TRUE); /* bad encoding */
}
if (dataLength >= *pDataLength) {
return (TRUE); /* error, no data */
}
*pDataLength = *pDataLength - dataLength;
return (FALSE); /* no error */
}
static int
iscsiAuthClientTextToData(const char *text, unsigned char *data,
unsigned int *dataLength)
{
int status;
unsigned int textLength;
status = iscsiAuthClientCheckString(text,
2 + 2 * iscsiAuthLargeBinaryMaxLength + 1, &textLength);
if (status) {
return (status);
}
if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
/*
* skip prefix
*/
text += 2;
textLength -= 2;
status = iscsiAuthClientHexToData(text,
textLength, data, dataLength);
} else if (text[0] == '0' && (text[1] == 'b' || text[1] == 'B')) {
/*
* skip prefix
*/
text += 2;
textLength -= 2;
status = iscsiAuthClientBase64ToData(text,
textLength, data, dataLength);
} else {
status = TRUE; /* prefix not recognized. */
}
return (status);
}
static IscsiAuthDebugStatus
iscsiAuthClientChapComputeResponse(IscsiAuthClient * client,
int remoteAuthentication, unsigned int id,
unsigned char *challengeData, unsigned int challengeLength,
unsigned char *responseData)
{
unsigned char idData[1];
IscsiAuthMd5Context context;
unsigned char outData[iscsiAuthStringMaxLength];
unsigned int outLength = iscsiAuthStringMaxLength;
if (!client->passwordPresent) {
return (iscsiAuthDebugStatusLocalPasswordNotSet);
}
iscsiAuthMd5Init(&context);
/*
* id byte
*/
idData[0] = id;
iscsiAuthMd5Update(&context, idData, 1);
/*
* decrypt password
*/
if (iscsiAuthClientData(outData, &outLength,
client->passwordData, client->passwordLength)) {
return (iscsiAuthDebugStatusPasswordDecryptFailed);
}
if (!remoteAuthentication && !client->ipSec && outLength < 12) {
return (iscsiAuthDebugStatusPasswordTooShortWithNoIpSec);
}
/*
* shared secret
*/
iscsiAuthMd5Update(&context, outData, outLength);
/*
* clear decrypted password
*/
bzero(outData, iscsiAuthStringMaxLength);
/*
* challenge value
*/
iscsiAuthMd5Update(&context, challengeData, challengeLength);
iscsiAuthMd5Final(responseData, &context);
return (iscsiAuthDebugStatusNotSet); /* no error */
}
static void
iscsiAuthClientInitKeyBlock(IscsiAuthKeyBlock * keyBlock)
{
char *stringBlock = keyBlock->stringBlock;
bzero(keyBlock, sizeof (*keyBlock));
keyBlock->stringBlock = stringBlock;
}
static void
iscsiAuthClientSetKeyValue(IscsiAuthKeyBlock * keyBlock,
int keyType, const char *keyValue)
{
unsigned int length;
char *string;
if (keyBlock->key[keyType].valueSet) {
keyBlock->duplicateSet = TRUE;
return;
}
keyBlock->key[keyType].valueSet = TRUE;
if (!keyValue) {
return;
}
if (iscsiAuthClientCheckString(keyValue,
iscsiAuthStringMaxLength, &length)) {
keyBlock->stringTooLong = TRUE;
return;
}
length += 1;
if ((keyBlock->blockLength + length) > iscsiAuthStringBlockMaxLength) {
keyBlock->tooMuchData = TRUE;
return;
}
string = &keyBlock->stringBlock[keyBlock->blockLength];
if (iscsiAuthClientStringCopy(string, keyValue, length)) {
keyBlock->tooMuchData = TRUE;
return;
}
keyBlock->blockLength += length;
keyBlock->key[keyType].string = string;
keyBlock->key[keyType].present = TRUE;
}
static const char *
iscsiAuthClientGetKeyValue(IscsiAuthKeyBlock * keyBlock, int keyType)
{
keyBlock->key[keyType].processed = TRUE;
if (!keyBlock->key[keyType].present) {
return (0);
}
return (keyBlock->key[keyType].string);
}
static void
iscsiAuthClientCheckKey(IscsiAuthClient * client,
int keyType,
int *negotiatedOption,
unsigned int optionCount,
int *optionList, const char *(*valueToText) (IscsiAuthClient *, int))
{
const char *keyValue;
int length;
unsigned int i;
keyValue = iscsiAuthClientGetKeyValue(&client->recvKeyBlock, keyType);
if (!keyValue) {
*negotiatedOption = iscsiAuthOptionNotPresent;
return;
}
while (*keyValue != '\0') {
length = 0;
while (*keyValue != '\0' && *keyValue != ',') {
client->scratchKeyValue[length++] = *keyValue++;
}
if (*keyValue == ',')
keyValue++;
client->scratchKeyValue[length++] = '\0';
for (i = 0; i < optionCount; i++) {
const char *s = (*valueToText) (client, optionList[i]);
if (!s)
continue;
if (strcmp(client->scratchKeyValue, s) == 0) {
*negotiatedOption = optionList[i];
return;
}
}
}
*negotiatedOption = iscsiAuthOptionReject;
}
static void
iscsiAuthClientSetKey(IscsiAuthClient * client,
int keyType,
unsigned int optionCount,
int *optionList, const char *(*valueToText) (IscsiAuthClient *, int))
{
unsigned int i;
if (optionCount == 0) {
/*
* No valid options to send, but we always want to
* send something.
*/
iscsiAuthClientSetKeyValue(&client->sendKeyBlock, keyType,
client->noneOptionName);
return;
}
if (optionCount == 1 && optionList[0] == iscsiAuthOptionNotPresent) {
iscsiAuthClientSetKeyValue(&client->sendKeyBlock, keyType, 0);
return;
}
for (i = 0; i < optionCount; i++) {
const char *s = (*valueToText) (client, optionList[i]);
if (!s)
continue;
if (i == 0) {
(void) iscsiAuthClientStringCopy(
client->scratchKeyValue,
s, iscsiAuthStringMaxLength);
} else {
(void) iscsiAuthClientStringAppend(
client->scratchKeyValue,
",", iscsiAuthStringMaxLength);
(void) iscsiAuthClientStringAppend(
client->scratchKeyValue,
s, iscsiAuthStringMaxLength);
}
}
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
keyType, client->scratchKeyValue);
}
static void
iscsiAuthClientCheckAuthMethodKey(IscsiAuthClient * client)
{
iscsiAuthClientCheckKey(client,
iscsiAuthKeyTypeAuthMethod,
&client->negotiatedAuthMethod,
client->authMethodValidCount,
client->authMethodValidList, iscsiAuthClientAuthMethodOptionToText);
}
static void
iscsiAuthClientSetAuthMethodKey(IscsiAuthClient * client,
unsigned int authMethodCount, int *authMethodList)
{
iscsiAuthClientSetKey(client, iscsiAuthKeyTypeAuthMethod,
authMethodCount, authMethodList,
iscsiAuthClientAuthMethodOptionToText);
}
static void
iscsiAuthClientCheckChapAlgorithmKey(IscsiAuthClient * client)
{
const char *keyValue;
int length;
unsigned long number;
unsigned int i;
keyValue = iscsiAuthClientGetKeyValue(&client->recvKeyBlock,
iscsiAuthKeyTypeChapAlgorithm);
if (!keyValue) {
client->negotiatedChapAlgorithm = iscsiAuthOptionNotPresent;
return;
}
while (*keyValue != '\0') {
length = 0;
while (*keyValue != '\0' && *keyValue != ',') {
client->scratchKeyValue[length++] = *keyValue++;
}
if (*keyValue == ',')
keyValue++;
client->scratchKeyValue[length++] = '\0';
if (iscsiAuthClientTextToNumber(client->scratchKeyValue,
&number)) {
continue;
}
for (i = 0; i < client->chapAlgorithmCount; i++) {
if (number == (unsigned long)client->
chapAlgorithmList[i]) {
client->negotiatedChapAlgorithm = number;
return;
}
}
}
client->negotiatedChapAlgorithm = iscsiAuthOptionReject;
}
static void
iscsiAuthClientSetChapAlgorithmKey(IscsiAuthClient * client,
unsigned int chapAlgorithmCount, int *chapAlgorithmList)
{
unsigned int i;
if (chapAlgorithmCount == 0) {
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapAlgorithm, 0);
return;
}
if (chapAlgorithmCount == 1 &&
chapAlgorithmList[0] == iscsiAuthOptionNotPresent) {
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapAlgorithm, 0);
return;
}
if (chapAlgorithmCount == 1 &&
chapAlgorithmList[0] == iscsiAuthOptionReject) {
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapAlgorithm, client->rejectOptionName);
return;
}
for (i = 0; i < chapAlgorithmCount; i++) {
char s[20];
iscsiAuthClientNumberToText(chapAlgorithmList[i],
s, sizeof (s));
if (i == 0) {
(void) iscsiAuthClientStringCopy(
client->scratchKeyValue, s,
iscsiAuthStringMaxLength);
} else {
(void) iscsiAuthClientStringAppend(
client->scratchKeyValue,
",", iscsiAuthStringMaxLength);
(void) iscsiAuthClientStringAppend(
client->scratchKeyValue,
s, iscsiAuthStringMaxLength);
}
}
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapAlgorithm, client->scratchKeyValue);
}
static void
iscsiAuthClientNextPhase(IscsiAuthClient * client)
{
switch (client->phase) {
case iscsiAuthPhaseConfigure:
client->phase = iscsiAuthPhaseNegotiate;
break;
case iscsiAuthPhaseNegotiate:
client->phase = iscsiAuthPhaseAuthenticate;
if (client->negotiatedAuthMethod ==
iscsiAuthOptionReject ||
client->negotiatedAuthMethod ==
iscsiAuthOptionNotPresent ||
client->negotiatedAuthMethod == iscsiAuthOptionNone) {
client->localState = iscsiAuthLocalStateDone;
client->remoteState = iscsiAuthRemoteStateDone;
if (client->authRemote) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
} else {
client->remoteAuthStatus = iscsiAuthStatusPass;
}
switch (client->negotiatedAuthMethod) {
case iscsiAuthOptionReject:
client->debugStatus =
iscsiAuthDebugStatusAuthMethodReject;
break;
case iscsiAuthOptionNotPresent:
client->debugStatus =
iscsiAuthDebugStatusAuthMethodNotPresent;
break;
case iscsiAuthOptionNone:
client->debugStatus =
iscsiAuthDebugStatusAuthMethodNone;
}
} else if (client->negotiatedAuthMethod ==
iscsiAuthMethodChap) {
client->localState = iscsiAuthLocalStateSendAlgorithm;
client->remoteState = iscsiAuthRemoteStateSendAlgorithm;
} else {
client->localState = iscsiAuthLocalStateDone;
client->remoteState = iscsiAuthRemoteStateDone;
client->remoteAuthStatus = iscsiAuthStatusFail;
client->debugStatus = iscsiAuthDebugStatusAuthMethodBad;
}
break;
case iscsiAuthPhaseAuthenticate:
client->phase = iscsiAuthPhaseDone;
break;
case iscsiAuthPhaseDone:
case iscsiAuthPhaseError:
default:
client->phase = iscsiAuthPhaseError;
}
}
static void
iscsiAuthClientLocalAuthentication(IscsiAuthClient * client)
{
unsigned int chapIdentifier;
unsigned char responseData[iscsiAuthChapResponseLength];
unsigned long number;
int status;
IscsiAuthDebugStatus debugStatus;
const char *chapIdentifierKeyValue;
const char *chapChallengeKeyValue;
switch (client->localState) {
case iscsiAuthLocalStateSendAlgorithm:
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
iscsiAuthClientSetChapAlgorithmKey(
client, client->chapAlgorithmCount,
client->chapAlgorithmList);
client->localState = iscsiAuthLocalStateRecvAlgorithm;
break;
}
/* FALLTHRU */
case iscsiAuthLocalStateRecvAlgorithm:
iscsiAuthClientCheckChapAlgorithmKey(client);
if (client->nodeType == iscsiAuthNodeTypeTarget) {
iscsiAuthClientSetChapAlgorithmKey(client, 1,
&client->negotiatedChapAlgorithm);
}
/*
* Make sure only supported CHAP algorithm is used.
*/
if (client->negotiatedChapAlgorithm ==
iscsiAuthOptionNotPresent) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapAlgorithmExpected;
break;
} else if (client->negotiatedChapAlgorithm ==
iscsiAuthOptionReject) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapAlgorithmReject;
break;
} else if (client->negotiatedChapAlgorithm !=
iscsiAuthChapAlgorithmMd5) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapAlgorithmBad;
break;
}
if (client->nodeType == iscsiAuthNodeTypeTarget) {
client->localState = iscsiAuthLocalStateRecvChallenge;
break;
}
/* FALLTHRU */
case iscsiAuthLocalStateRecvChallenge:
chapIdentifierKeyValue = iscsiAuthClientGetKeyValue(
&client->recvKeyBlock, iscsiAuthKeyTypeChapIdentifier);
chapChallengeKeyValue = iscsiAuthClientGetKeyValue(
&client->recvKeyBlock, iscsiAuthKeyTypeChapChallenge);
if (client->nodeType == iscsiAuthNodeTypeTarget) {
if (!chapIdentifierKeyValue && !chapChallengeKeyValue) {
client->localState = iscsiAuthLocalStateDone;
break;
}
}
if (!chapIdentifierKeyValue) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapIdentifierExpected;
break;
}
if (!chapChallengeKeyValue) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapChallengeExpected;
break;
}
status = iscsiAuthClientTextToNumber(
chapIdentifierKeyValue, &number);
if (status || (255 < number)) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapIdentifierBad;
break;
}
chapIdentifier = number;
if (client->recvChapChallengeStatus) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapChallengeBad;
break;
}
if (client->nodeType == iscsiAuthNodeTypeTarget &&
client->recvChapChallenge.length ==
client->sendChapChallenge.length &&
bcmp(client->recvChapChallenge.largeBinary,
client->sendChapChallenge.largeBinary,
client->sendChapChallenge.length) == 0) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus =
iscsiAuthDebugStatusChapChallengeReflected;
break;
}
debugStatus = iscsiAuthClientChapComputeResponse(client,
FALSE,
chapIdentifier,
client->recvChapChallenge.largeBinary,
client->recvChapChallenge.length, responseData);
if (debugStatus != iscsiAuthDebugStatusNotSet) {
client->localState = iscsiAuthLocalStateError;
client->debugStatus = debugStatus;
break;
}
(void) iscsiAuthClientDataToText(client->base64,
responseData, iscsiAuthChapResponseLength,
client->scratchKeyValue, iscsiAuthStringMaxLength);
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapResponse, client->scratchKeyValue);
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapUsername, client->username);
client->localState = iscsiAuthLocalStateDone;
break;
case iscsiAuthLocalStateDone:
break;
case iscsiAuthLocalStateError:
default:
client->phase = iscsiAuthPhaseError;
}
}
static void
iscsiAuthClientRemoteAuthentication(IscsiAuthClient * client)
{
unsigned char idData[1];
unsigned char responseData[iscsiAuthStringMaxLength];
unsigned int responseLength = iscsiAuthStringMaxLength;
unsigned char myResponseData[iscsiAuthChapResponseLength];
int status;
IscsiAuthDebugStatus debugStatus;
const char *chapResponseKeyValue;
const char *chapUsernameKeyValue;
switch (client->remoteState) {
case iscsiAuthRemoteStateSendAlgorithm:
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
client->remoteState = iscsiAuthRemoteStateSendChallenge;
break;
}
/* FALLTHRU */
case iscsiAuthRemoteStateSendChallenge:
if (!client->authRemote) {
client->remoteAuthStatus = iscsiAuthStatusPass;
client->debugStatus =
iscsiAuthDebugStatusAuthRemoteFalse;
client->remoteState = iscsiAuthRemoteStateDone;
break;
}
iscsiAuthRandomSetData(idData, 1);
client->sendChapIdentifier = idData[0];
iscsiAuthClientNumberToText(client->sendChapIdentifier,
client->scratchKeyValue, iscsiAuthStringMaxLength);
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapIdentifier, client->scratchKeyValue);
client->sendChapChallenge.length = client->chapChallengeLength;
iscsiAuthRandomSetData(client->sendChapChallenge.largeBinary,
client->sendChapChallenge.length);
iscsiAuthClientSetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeChapChallenge, "");
client->remoteState = iscsiAuthRemoteStateRecvResponse;
break;
case iscsiAuthRemoteStateRecvResponse:
chapResponseKeyValue = iscsiAuthClientGetKeyValue(
&client->recvKeyBlock, iscsiAuthKeyTypeChapResponse);
chapUsernameKeyValue = iscsiAuthClientGetKeyValue(
&client->recvKeyBlock, iscsiAuthKeyTypeChapUsername);
if (!chapResponseKeyValue) {
client->remoteState = iscsiAuthRemoteStateError;
client->debugStatus =
iscsiAuthDebugStatusChapResponseExpected;
break;
}
if (!chapUsernameKeyValue) {
client->remoteState = iscsiAuthRemoteStateError;
client->debugStatus =
iscsiAuthDebugStatusChapUsernameExpected;
break;
}
status = iscsiAuthClientTextToData(chapResponseKeyValue,
responseData, &responseLength);
if (status) {
client->remoteState = iscsiAuthRemoteStateError;
client->debugStatus =
iscsiAuthDebugStatusChapResponseBad;
break;
}
if (responseLength == iscsiAuthChapResponseLength) {
debugStatus = iscsiAuthClientChapComputeResponse(
client, TRUE, client->sendChapIdentifier,
client->sendChapChallenge.largeBinary,
client->sendChapChallenge.length, myResponseData);
/*
* Check if the same CHAP secret is being used for
* authentication in both directions.
*/
if (debugStatus == iscsiAuthDebugStatusNotSet &&
bcmp(myResponseData, responseData,
iscsiAuthChapResponseLength) == 0) {
client->remoteState =
iscsiAuthRemoteStateError;
client->debugStatus =
iscsiAuthDebugStatusPasswordIdentical;
break;
}
}
(void) iscsiAuthClientStringCopy(client->chapUsername,
chapUsernameKeyValue, iscsiAuthStringMaxLength);
/* To verify the target's response. */
status = iscsiAuthClientChapAuthRequest(
client, client->chapUsername, client->sendChapIdentifier,
client->sendChapChallenge.largeBinary,
client->sendChapChallenge.length, responseData,
responseLength);
if (status == iscsiAuthStatusInProgress) {
iscsiAuthClientGlobalStats.requestSent++;
client->remoteState = iscsiAuthRemoteStateAuthRequest;
break;
}
client->remoteAuthStatus = (IscsiAuthStatus) status;
client->authResponseFlag = TRUE;
/* FALLTHRU */
case iscsiAuthRemoteStateAuthRequest:
/*
* client->remoteAuthStatus already set
*/
if (client->authServerErrorFlag) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->debugStatus =
iscsiAuthDebugStatusAuthServerError;
} else if (client->remoteAuthStatus == iscsiAuthStatusPass) {
client->debugStatus = iscsiAuthDebugStatusAuthPass;
} else if (client->remoteAuthStatus == iscsiAuthStatusFail) {
client->debugStatus = iscsiAuthDebugStatusAuthFail;
} else {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->debugStatus = iscsiAuthDebugStatusAuthStatusBad;
}
client->remoteState = iscsiAuthRemoteStateDone;
/* FALLTHRU */
case iscsiAuthRemoteStateDone:
break;
case iscsiAuthRemoteStateError:
default:
client->phase = iscsiAuthPhaseError;
}
}
static void
iscsiAuthClientHandshake(IscsiAuthClient * client)
{
if (client->phase == iscsiAuthPhaseDone) {
/*
* Should only happen if authentication
* protocol error occured.
*/
return;
}
if (client->remoteState == iscsiAuthRemoteStateAuthRequest) {
/*
* Defer until authentication response received
* from internal authentication service.
*/
return;
}
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
/*
* Target should only have set T bit on response if
* initiator set it on previous message.
*/
if (client->recvKeyBlock.transitBit &&
client->transitBitSentFlag == 0) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusTbitSetIllegal;
return;
}
}
if (client->phase == iscsiAuthPhaseNegotiate) {
/*
* Should only happen if waiting for peer
* to send AuthMethod key or set Transit Bit.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
client->sendKeyBlock.transitBit = TRUE;
}
return;
}
if (client->remoteState == iscsiAuthRemoteStateRecvResponse ||
client->remoteState == iscsiAuthRemoteStateDone) {
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
if (client->recvKeyBlock.transitBit) {
if (client->remoteState !=
iscsiAuthRemoteStateDone) {
goto recvTransitBitError;
}
iscsiAuthClientNextPhase(client);
} else {
client->sendKeyBlock.transitBit = TRUE;
}
} else {
if (client->remoteState == iscsiAuthRemoteStateDone &&
client->remoteAuthStatus != iscsiAuthStatusPass) {
/*
* Authentication failed, don't
* do T bit handshake.
*/
iscsiAuthClientNextPhase(client);
} else {
/*
* Target can only set T bit on response if
* initiator set it on current message.
*/
if (client->recvKeyBlock.transitBit) {
client->sendKeyBlock.transitBit = TRUE;
iscsiAuthClientNextPhase(client);
}
}
}
} else {
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
if (client->recvKeyBlock.transitBit) {
goto recvTransitBitError;
}
}
}
return;
recvTransitBitError:
/*
* Target set T bit on response but
* initiator was not done with authentication.
*/
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus = iscsiAuthDebugStatusTbitSetPremature;
}
static int
iscsiAuthClientRecvEndStatus(IscsiAuthClient * client)
{
int authStatus;
int keyType;
if (client->phase == iscsiAuthPhaseError) {
return (iscsiAuthStatusError);
}
if (client->phase == iscsiAuthPhaseDone) {
/*
* Perform sanity check against configured parameters.
*/
if (client->authRemote && !client->authResponseFlag &&
client->remoteAuthStatus == iscsiAuthStatusPass) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->debugStatus =
iscsiAuthDebugStatusAuthPassNotValid;
}
authStatus = client->remoteAuthStatus;
} else if (client->remoteState == iscsiAuthRemoteStateAuthRequest) {
authStatus = iscsiAuthStatusInProgress;
} else {
authStatus = iscsiAuthStatusContinue;
}
if (authStatus != iscsiAuthStatusInProgress) {
client->recvInProgressFlag = FALSE;
}
if (authStatus == iscsiAuthStatusContinue ||
authStatus == iscsiAuthStatusPass) {
if (client->sendKeyBlock.duplicateSet) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusSendDuplicateSetKeyValue;
authStatus = iscsiAuthStatusFail;
} else if (client->sendKeyBlock.stringTooLong) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusSendStringTooLong;
authStatus = iscsiAuthStatusFail;
} else if (client->sendKeyBlock.tooMuchData) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusSendTooMuchData;
authStatus = iscsiAuthStatusFail;
} else {
/*
* Check that all incoming keys have been processed.
*/
for (keyType = iscsiAuthKeyTypeFirst;
keyType < iscsiAuthKeyTypeMaxCount; keyType++) {
if (client->recvKeyBlock.key[keyType].present &&
client->recvKeyBlock.key[keyType].
processed == 0) {
break;
}
}
if (keyType < iscsiAuthKeyTypeMaxCount) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusUnexpectedKeyPresent;
authStatus = iscsiAuthStatusFail;
}
}
}
if (authStatus != iscsiAuthStatusPass &&
authStatus != iscsiAuthStatusContinue &&
authStatus != iscsiAuthStatusInProgress) {
int authMethodKeyPresent = FALSE;
int chapAlgorithmKeyPresent = FALSE;
/*
* Suppress send keys on error, except
* for AuthMethod and CHAP_A.
*/
if (client->nodeType == iscsiAuthNodeTypeTarget) {
if (iscsiAuthClientGetKeyValue(&client->sendKeyBlock,
iscsiAuthKeyTypeAuthMethod)) {
authMethodKeyPresent = TRUE;
} else if (iscsiAuthClientGetKeyValue(
&client->sendKeyBlock,
iscsiAuthKeyTypeChapAlgorithm)) {
chapAlgorithmKeyPresent = TRUE;
}
}
iscsiAuthClientInitKeyBlock(&client->sendKeyBlock);
if (client->nodeType == iscsiAuthNodeTypeTarget) {
if (authMethodKeyPresent &&
client->negotiatedAuthMethod ==
iscsiAuthOptionReject) {
iscsiAuthClientSetKeyValue(
&client->sendKeyBlock,
iscsiAuthKeyTypeAuthMethod,
client->rejectOptionName);
} else if (chapAlgorithmKeyPresent &&
client->negotiatedChapAlgorithm ==
iscsiAuthOptionReject) {
iscsiAuthClientSetKeyValue(
&client->sendKeyBlock,
iscsiAuthKeyTypeChapAlgorithm,
client->rejectOptionName);
}
}
}
return (authStatus);
}
int
iscsiAuthClientRecvBegin(IscsiAuthClient * client)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase == iscsiAuthPhaseError) {
return (iscsiAuthStatusError);
}
if (client->phase == iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (client->recvInProgressFlag) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->recvInProgressFlag = TRUE;
if (client->phase == iscsiAuthPhaseConfigure) {
iscsiAuthClientNextPhase(client);
}
client->transitBitSentFlag = client->sendKeyBlock.transitBit;
iscsiAuthClientInitKeyBlock(&client->recvKeyBlock);
iscsiAuthClientInitKeyBlock(&client->sendKeyBlock);
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientRecvEnd(IscsiAuthClient * client,
IscsiAuthClientCallback * callback, void *userHandle, void *messageHandle)
{
int nextPhaseFlag = FALSE;
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase == iscsiAuthPhaseError) {
return (iscsiAuthStatusError);
}
if (!callback || !client->recvInProgressFlag) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (client->recvEndCount > iscsiAuthRecvEndMaxCount) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusRecvMessageCountLimit;
} else if (client->recvKeyBlock.duplicateSet) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusRecvDuplicateSetKeyValue;
} else if (client->recvKeyBlock.stringTooLong) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus = iscsiAuthDebugStatusRecvStringTooLong;
} else if (client->recvKeyBlock.tooMuchData) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus = iscsiAuthDebugStatusRecvTooMuchData;
}
client->recvEndCount++;
client->callback = callback;
client->userHandle = userHandle;
client->messageHandle = messageHandle;
switch (client->phase) {
case iscsiAuthPhaseNegotiate:
iscsiAuthClientCheckAuthMethodKey(client);
if (client->authMethodValidNegRole ==
iscsiAuthNegRoleResponder) {
if (client->negotiatedAuthMethod ==
iscsiAuthOptionNotPresent) {
if (client->authRemote ||
client->recvKeyBlock.transitBit == 0) {
/*
* No AuthMethod key from peer
* on first message, try moving
* the process along by sending
* the AuthMethod key.
*/
client->authMethodValidNegRole =
iscsiAuthNegRoleOriginator;
iscsiAuthClientSetAuthMethodKey(client,
client->authMethodValidCount,
client->authMethodValidList);
break;
}
/*
* Special case if peer sent no
* AuthMethod key, but did set Transit
* Bit, allowing this side to do a
* null authentication, and compelete
* the iSCSI security phase without
* either side sending the AuthMethod
* key.
*/
} else {
/*
* Send response to AuthMethod key.
*/
iscsiAuthClientSetAuthMethodKey(client, 1,
&client->negotiatedAuthMethod);
}
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
iscsiAuthClientNextPhase(client);
} else {
nextPhaseFlag = TRUE;
}
} else {
if (client->negotiatedAuthMethod ==
iscsiAuthOptionNotPresent) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
client->debugStatus =
iscsiAuthDebugStatusAuthMethodExpected;
break;
}
iscsiAuthClientNextPhase(client);
}
break;
case iscsiAuthPhaseAuthenticate:
case iscsiAuthPhaseDone:
break;
default:
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
switch (client->phase) {
case iscsiAuthPhaseNegotiate:
if (nextPhaseFlag) {
iscsiAuthClientNextPhase(client);
}
break;
case iscsiAuthPhaseAuthenticate:
/*
* Must call iscsiAuthClientLocalAuthentication()
* before iscsiAuthClientRemoteAuthentication()
* to insure processing of the CHAP algorithm key,
* and to avoid leaving an in progress request to the
* authentication service.
*/
iscsiAuthClientLocalAuthentication(client);
if (client->localState != iscsiAuthLocalStateError) {
iscsiAuthClientRemoteAuthentication(client);
}
if (client->localState == iscsiAuthLocalStateError ||
client->remoteState == iscsiAuthRemoteStateError) {
client->remoteAuthStatus = iscsiAuthStatusFail;
client->phase = iscsiAuthPhaseDone;
/*
* client->debugStatus should already be set.
*/
}
break;
case iscsiAuthPhaseDone:
break;
default:
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
iscsiAuthClientHandshake(client);
return (iscsiAuthClientRecvEndStatus(client));
}
void
iscsiAuthClientAuthResponse(IscsiAuthClient * client, int authStatus)
{
iscsiAuthClientGlobalStats.responseReceived++;
if (!client || client->signature != iscsiAuthClientSignature) {
return;
}
if (!client->recvInProgressFlag ||
client->phase != iscsiAuthPhaseAuthenticate ||
client->remoteState != iscsiAuthRemoteStateAuthRequest) {
client->phase = iscsiAuthPhaseError;
return;
}
client->remoteAuthStatus = (IscsiAuthStatus) authStatus;
client->authResponseFlag = TRUE;
iscsiAuthClientRemoteAuthentication(client);
iscsiAuthClientHandshake(client);
authStatus = iscsiAuthClientRecvEndStatus(client);
client->callback(client->userHandle, client->messageHandle, authStatus);
}
const char *
iscsiAuthClientGetKeyName(int keyType)
{
if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) {
return (0);
}
return (iscsiAuthClientKeyInfo[keyType].name);
}
int
iscsiAuthClientGetNextKeyType(int *pKeyType)
{
int keyType = *pKeyType;
if (keyType >= iscsiAuthKeyTypeLast) {
return (iscsiAuthStatusError);
}
if (keyType < iscsiAuthKeyTypeFirst) {
keyType = iscsiAuthKeyTypeFirst;
} else {
keyType++;
}
*pKeyType = keyType;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientKeyNameToKeyType(const char *keyName)
{
int keyType = iscsiAuthKeyTypeNone;
while (iscsiAuthClientGetNextKeyType(&keyType) ==
iscsiAuthStatusNoError) {
const char *keyName2 = iscsiAuthClientGetKeyName(keyType);
if (!keyName2) {
return (iscsiAuthKeyTypeNone);
}
if (strcmp(keyName, keyName2) == 0) {
return (keyType);
}
}
return (iscsiAuthKeyTypeNone);
}
int
iscsiAuthClientRecvKeyValue(IscsiAuthClient * client, int keyType,
const char *userKeyValue)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseNegotiate &&
client->phase != iscsiAuthPhaseAuthenticate) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (keyType == iscsiAuthKeyTypeChapChallenge) {
client->recvChapChallenge.length =
iscsiAuthLargeBinaryMaxLength;
client->recvChapChallengeStatus =
iscsiAuthClientTextToData(userKeyValue,
client->recvChapChallenge.largeBinary,
&client->recvChapChallenge.length);
userKeyValue = "";
}
iscsiAuthClientSetKeyValue(&client->recvKeyBlock,
keyType, userKeyValue);
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSendKeyValue(IscsiAuthClient * client, int keyType,
int *keyPresent, char *userKeyValue, unsigned int maxLength)
{
const char *keyValue;
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure &&
client->phase != iscsiAuthPhaseNegotiate &&
client->phase != iscsiAuthPhaseAuthenticate &&
client->phase != iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
keyValue = iscsiAuthClientGetKeyValue(&client->sendKeyBlock, keyType);
if (keyValue) {
if (keyType == iscsiAuthKeyTypeChapChallenge) {
if (iscsiAuthClientDataToText(client->base64,
client->sendChapChallenge.largeBinary,
client->sendChapChallenge.length,
userKeyValue, maxLength)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
} else {
if (iscsiAuthClientStringCopy(userKeyValue,
keyValue, maxLength)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
}
*keyPresent = TRUE;
} else {
*keyPresent = FALSE;
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientRecvTransitBit(IscsiAuthClient * client, int value)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseNegotiate &&
client->phase != iscsiAuthPhaseAuthenticate) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (value) {
client->recvKeyBlock.transitBit = TRUE;
} else {
client->recvKeyBlock.transitBit = FALSE;
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSendTransitBit(IscsiAuthClient * client, int *value)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure &&
client->phase != iscsiAuthPhaseNegotiate &&
client->phase != iscsiAuthPhaseAuthenticate &&
client->phase != iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
*value = client->sendKeyBlock.transitBit;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientInit(int nodeType, int bufferDescCount,
IscsiAuthBufferDesc * bufferDesc)
{
IscsiAuthClient *client;
IscsiAuthStringBlock *recvStringBlock;
IscsiAuthStringBlock *sendStringBlock;
IscsiAuthLargeBinary *recvChapChallenge;
IscsiAuthLargeBinary *sendChapChallenge;
int valueList[2];
if (bufferDescCount != 5 ||
bufferDesc == 0) {
return (iscsiAuthStatusError);
}
if (!bufferDesc[0].address ||
bufferDesc[0].length != sizeof (*client)) {
return (iscsiAuthStatusError);
}
client = (IscsiAuthClient *) bufferDesc[0].address;
if (bufferDesc[1].address == 0 ||
bufferDesc[1].length != sizeof (*recvStringBlock)) {
return (iscsiAuthStatusError);
}
recvStringBlock = (IscsiAuthStringBlock *) bufferDesc[1].address;
if (bufferDesc[2].address == 0 ||
bufferDesc[2].length != sizeof (*sendStringBlock)) {
return (iscsiAuthStatusError);
}
sendStringBlock = (IscsiAuthStringBlock *) bufferDesc[2].address;
if (bufferDesc[3].address == 0 ||
bufferDesc[3].length != sizeof (*recvChapChallenge)) {
return (iscsiAuthStatusError);
}
recvChapChallenge = (IscsiAuthLargeBinary *) bufferDesc[3].address;
if (bufferDesc[4].address == 0 ||
bufferDesc[4].length != sizeof (*sendChapChallenge)) {
return (iscsiAuthStatusError);
}
sendChapChallenge = (IscsiAuthLargeBinary *) bufferDesc[4].address;
bzero(client, sizeof (*client));
bzero(recvStringBlock, sizeof (*recvStringBlock));
bzero(sendStringBlock, sizeof (*sendStringBlock));
bzero(recvChapChallenge, sizeof (*recvChapChallenge));
bzero(sendChapChallenge, sizeof (*sendChapChallenge));
client->recvKeyBlock.stringBlock = recvStringBlock->stringBlock;
client->sendKeyBlock.stringBlock = sendStringBlock->stringBlock;
client->recvChapChallenge.largeBinary = recvChapChallenge->largeBinary;
client->sendChapChallenge.largeBinary = sendChapChallenge->largeBinary;
if (iscsiAuthClientCheckNodeType(nodeType)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->signature = iscsiAuthClientSignature;
client->nodeType = (IscsiAuthNodeType) nodeType;
/* Assume bi-directional authentication enabled. */
client->authRemote = TRUE;
client->passwordPresent = FALSE;
client->version = iscsiAuthVersionRfc;
client->chapChallengeLength = iscsiAuthChapResponseLength;
client->ipSec = TRUE;
client->base64 = FALSE;
client->phase = iscsiAuthPhaseConfigure;
client->negotiatedAuthMethod = iscsiAuthOptionNotPresent;
client->negotiatedChapAlgorithm = iscsiAuthOptionNotPresent;
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
client->authMethodNegRole = iscsiAuthNegRoleOriginator;
} else {
/*
* Initial value ignored for Target.
*/
client->authMethodNegRole = iscsiAuthNegRoleResponder;
}
/* All supported authentication methods */
valueList[0] = iscsiAuthMethodChap;
valueList[1] = iscsiAuthOptionNone;
/*
* Must call after setting authRemote, password,
* version and authMethodNegRole
*/
if (iscsiAuthClientSetAuthMethodList(client, 2, valueList) !=
iscsiAuthStatusNoError) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
valueList[0] = iscsiAuthChapAlgorithmMd5;
if (iscsiAuthClientSetChapAlgorithmList(client, 1, valueList) !=
iscsiAuthStatusNoError) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientFinish(IscsiAuthClient * client)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
iscsiAuthClientChapAuthCancel(client);
bzero(client, sizeof (*client));
return (iscsiAuthStatusNoError);
}
static int
iscsiAuthClientSetOptionList(IscsiAuthClient * client,
unsigned int optionCount,
const int *optionList,
unsigned int *clientOptionCount,
int *clientOptionList,
unsigned int optionMaxCount,
int (*checkOption) (int),
int (*checkList) (unsigned int optionCount, const int *optionList))
{
unsigned int i;
unsigned int j;
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure ||
optionCount > optionMaxCount) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
for (i = 0; i < optionCount; i++) {
if ((*checkOption) (optionList[i])) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
}
/*
* Check for duplicate entries.
*/
for (i = 0; i < optionCount; i++) {
for (j = 0; j < optionCount; j++) {
if (j == i)
continue;
if (optionList[i] == optionList[j]) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
}
}
/*
* Check for key specific constraints.
*/
if (checkList) {
if ((*checkList) (optionCount, optionList)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
}
for (i = 0; i < optionCount; i++) {
clientOptionList[i] = optionList[i];
}
*clientOptionCount = optionCount;
return (iscsiAuthStatusNoError);
}
static void
iscsiAuthClientSetAuthMethodValid(IscsiAuthClient * client)
{
static const char rejectOptionNameDraft8[] = "reject";
static const char rejectOptionNameRfc[] = "Reject";
static const char noneOptionNameDraft8[] = "none";
static const char noneOptionNameRfc[] = "None";
unsigned int i;
unsigned int j = 0;
int option = 0;
if (client->version == iscsiAuthVersionDraft8) {
client->rejectOptionName = rejectOptionNameDraft8;
client->noneOptionName = noneOptionNameDraft8;
} else {
client->rejectOptionName = rejectOptionNameRfc;
client->noneOptionName = noneOptionNameRfc;
}
/*
* Following checks may need to be revised if
* authentication options other than CHAP and none
* are supported.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
if (client->authRemote) {
/*
* If initiator doing authentication,
* don't offer authentication option none.
*/
option = 1;
} else if (!client->passwordPresent) {
/*
* If initiator password not set,
* only offer authentication option none.
*/
option = 2;
}
}
if (client->nodeType == iscsiAuthNodeTypeTarget) {
if (client->authRemote) {
/*
* If target doing authentication,
* don't accept authentication option none.
*/
option = 1;
} else {
/*
* If target not doing authentication,
* only accept authentication option none.
*/
option = 2;
}
}
for (i = 0; i < client->authMethodCount; i++) {
if (option == 1) {
if (client->authMethodList[i] == iscsiAuthOptionNone) {
continue;
}
} else if (option == 2) {
if (client->authMethodList[i] != iscsiAuthOptionNone) {
continue;
}
}
client->authMethodValidList[j++] = client->authMethodList[i];
}
client->authMethodValidCount = j;
iscsiAuthClientInitKeyBlock(&client->sendKeyBlock);
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
if (client->authRemote) {
/*
* Initiator wants to authenticate target,
* always send AuthMethod key.
*/
client->sendKeyBlock.transitBit = FALSE;
client->authMethodValidNegRole =
iscsiAuthNegRoleOriginator;
} else {
client->sendKeyBlock.transitBit = TRUE;
client->authMethodValidNegRole =
client->authMethodNegRole;
}
} else {
client->sendKeyBlock.transitBit = FALSE;
client->authMethodValidNegRole = iscsiAuthNegRoleResponder;
}
if (client->authMethodValidNegRole == iscsiAuthNegRoleOriginator) {
iscsiAuthClientSetAuthMethodKey(client,
client->authMethodValidCount,
client->authMethodValidList);
} else {
int value = iscsiAuthOptionNotPresent;
iscsiAuthClientSetAuthMethodKey(client, 1, &value);
}
}
static int
iscsiAuthClientCheckAuthMethodList(unsigned int optionCount,
const int *optionList)
{
unsigned int i;
if (!optionList || optionCount < 2) {
return (TRUE);
}
if (optionList[optionCount - 1] != iscsiAuthOptionNone) {
return (TRUE);
}
for (i = 0; i < (optionCount - 1); i++) {
if (optionList[i] != iscsiAuthOptionNone) {
return (FALSE);
}
}
return (FALSE);
}
int
iscsiAuthClientSetAuthMethodList(IscsiAuthClient * client,
unsigned int optionCount, const int *optionList)
{
int status;
status = iscsiAuthClientSetOptionList(
client, optionCount, optionList, &client->authMethodCount,
client->authMethodList, iscsiAuthMethodMaxCount,
iscsiAuthClientCheckAuthMethodOption,
iscsiAuthClientCheckAuthMethodList);
if (status != iscsiAuthStatusNoError) {
return (status);
}
/*
* Setting authMethod affects authMethodValid.
*/
iscsiAuthClientSetAuthMethodValid(client);
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetAuthMethodNegRole(IscsiAuthClient * client, int negRole)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure ||
iscsiAuthClientCheckNegRole(negRole) ||
client->nodeType != iscsiAuthNodeTypeInitiator) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->authMethodNegRole = (IscsiAuthNegRole) negRole;
/*
* Setting negRole affects authMethodValid.
*/
iscsiAuthClientSetAuthMethodValid(client);
return (iscsiAuthStatusNoError);
}
static int
iscsiAuthClientCheckChapAlgorithmList(unsigned int optionCount,
const int *optionList)
{
if (!optionList || optionCount < 1) {
return (TRUE);
}
return (FALSE);
}
int
iscsiAuthClientSetChapAlgorithmList(IscsiAuthClient * client,
unsigned int optionCount, const int *optionList)
{
return (iscsiAuthClientSetOptionList(client,
optionCount,
optionList,
&client->chapAlgorithmCount,
client->chapAlgorithmList,
iscsiAuthChapAlgorithmMaxCount,
iscsiAuthClientCheckChapAlgorithmOption,
iscsiAuthClientCheckChapAlgorithmList));
}
int
iscsiAuthClientSetUsername(IscsiAuthClient * client, const char *username)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure ||
iscsiAuthClientCheckString(username, iscsiAuthStringMaxLength, 0)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (iscsiAuthClientStringCopy(client->username, username,
iscsiAuthStringMaxLength)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetPassword(IscsiAuthClient * client,
const unsigned char *passwordData, unsigned int passwordLength)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure ||
passwordLength > iscsiAuthStringMaxLength) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
bcopy(passwordData, client->passwordData, passwordLength);
client->passwordLength = passwordLength;
if (client->passwordLength > 0) {
client->passwordPresent = TRUE;
} else {
client->passwordPresent = FALSE;
}
/*
* Setting password may affect authMethodValid.
*/
iscsiAuthClientSetAuthMethodValid(client);
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetAuthRemote(IscsiAuthClient * client, int authRemote)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->authRemote = authRemote;
/*
* Setting authRemote may affect authMethodValid.
*/
iscsiAuthClientSetAuthMethodValid(client);
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetGlueHandle(IscsiAuthClient * client, void *glueHandle)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure &&
client->phase != iscsiAuthPhaseNegotiate &&
client->phase != iscsiAuthPhaseAuthenticate) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->glueHandle = glueHandle;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetMethodListName(IscsiAuthClient *client,
const char *methodListName)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure ||
iscsiAuthClientCheckString(methodListName,
iscsiAuthStringMaxLength, 0)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (iscsiAuthClientStringCopy(client->methodListName, methodListName,
iscsiAuthStringMaxLength)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetVersion(IscsiAuthClient * client, int version)
{
if (client == 0 ||
client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure ||
iscsiAuthClientCheckVersion(version)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->version = (IscsiAuthVersion) version;
iscsiAuthClientSetAuthMethodValid(client);
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetIpSec(IscsiAuthClient * client, int ipSec)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->ipSec = ipSec;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetBase64(IscsiAuthClient * client, int base64)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->base64 = base64;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSetChapChallengeLength(IscsiAuthClient * client,
unsigned int chapChallengeLength)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure ||
chapChallengeLength < iscsiAuthChapResponseLength ||
chapChallengeLength > iscsiAuthLargeBinaryMaxLength) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
client->chapChallengeLength = chapChallengeLength;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientCheckPasswordNeeded(IscsiAuthClient *client, int *passwordNeeded)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
if (client->authRemote && !client->passwordPresent) {
*passwordNeeded = TRUE;
} else {
*passwordNeeded = FALSE;
}
} else {
*passwordNeeded = FALSE;
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientGetAuthPhase(IscsiAuthClient * client, int *value)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
*value = client->phase;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientGetAuthStatus(IscsiAuthClient * client, int *value)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
*value = client->remoteAuthStatus;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientAuthStatusPass(int authStatus)
{
if (authStatus == iscsiAuthStatusPass) {
return (TRUE);
}
return (FALSE);
}
int
iscsiAuthClientGetAuthMethod(IscsiAuthClient * client, int *value)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseDone &&
client->phase != iscsiAuthPhaseAuthenticate) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
*value = client->negotiatedAuthMethod;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientGetChapAlgorithm(IscsiAuthClient * client, int *value)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
*value = client->negotiatedChapAlgorithm;
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientGetChapUsername(IscsiAuthClient * client,
char *value, unsigned int maxLength)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (iscsiAuthClientStringCopy(value, client->chapUsername, maxLength)) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientSendStatusCode(IscsiAuthClient * client, int *statusCode)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseConfigure &&
client->phase != iscsiAuthPhaseNegotiate &&
client->phase != iscsiAuthPhaseAuthenticate &&
client->phase != iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseDone) {
*statusCode = 0x0000;
return (iscsiAuthStatusNoError);
}
switch (client->remoteAuthStatus) {
case iscsiAuthStatusPass:
*statusCode = 0x0000; /* no error */
break;
case iscsiAuthStatusFail:
switch (client->debugStatus) {
case iscsiAuthDebugStatusAuthFail:
/*
* Authentication error with peer.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
*statusCode = 0x0300;
/*
* iSCSI Target error
*/
} else {
*statusCode = 0x0201;
/*
* iSCSI Initiator error
*/
}
break;
case iscsiAuthDebugStatusAuthMethodExpected:
case iscsiAuthDebugStatusChapAlgorithmExpected:
case iscsiAuthDebugStatusChapIdentifierExpected:
case iscsiAuthDebugStatusChapChallengeExpected:
case iscsiAuthDebugStatusChapResponseExpected:
case iscsiAuthDebugStatusChapUsernameExpected:
/*
* Missing parameter with peer.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
*statusCode = 0x0300;
/*
* iSCSI Target error
*/
} else {
*statusCode = 0x0207;
/*
* iSCSI Initiator error
*/
}
break;
case iscsiAuthDebugStatusAuthMethodNotPresent:
case iscsiAuthDebugStatusAuthMethodReject:
case iscsiAuthDebugStatusAuthMethodNone:
case iscsiAuthDebugStatusChapAlgorithmReject:
case iscsiAuthDebugStatusChapChallengeReflected:
case iscsiAuthDebugStatusPasswordIdentical:
/*
* Could not authenticate with peer.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
*statusCode = 0x0300;
/*
* iSCSI Target error
*/
} else {
*statusCode = 0x0201;
/*
* iSCSI Initiator error
*/
}
break;
case iscsiAuthDebugStatusLocalPasswordNotSet:
/*
* Local password not set.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
*statusCode = 0x0200;
/*
* iSCSI Initiator error
*/
} else {
*statusCode = 0x0201;
/*
* iSCSI Target error
*/
}
break;
case iscsiAuthDebugStatusChapIdentifierBad:
case iscsiAuthDebugStatusChapChallengeBad:
case iscsiAuthDebugStatusChapResponseBad:
case iscsiAuthDebugStatusUnexpectedKeyPresent:
case iscsiAuthDebugStatusTbitSetIllegal:
case iscsiAuthDebugStatusTbitSetPremature:
case iscsiAuthDebugStatusRecvMessageCountLimit:
case iscsiAuthDebugStatusRecvDuplicateSetKeyValue:
case iscsiAuthDebugStatusRecvStringTooLong:
case iscsiAuthDebugStatusRecvTooMuchData:
/*
* Other error with peer.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
*statusCode = 0x0300;
/*
* iSCSI Target error
*/
} else {
*statusCode = 0x0200;
/*
* iSCSI Initiator error
*/
}
break;
case iscsiAuthDebugStatusNotSet:
case iscsiAuthDebugStatusAuthPass:
case iscsiAuthDebugStatusAuthRemoteFalse:
case iscsiAuthDebugStatusAuthMethodBad:
case iscsiAuthDebugStatusChapAlgorithmBad:
case iscsiAuthDebugStatusPasswordDecryptFailed:
case iscsiAuthDebugStatusPasswordTooShortWithNoIpSec:
case iscsiAuthDebugStatusAuthServerError:
case iscsiAuthDebugStatusAuthStatusBad:
case iscsiAuthDebugStatusAuthPassNotValid:
case iscsiAuthDebugStatusSendDuplicateSetKeyValue:
case iscsiAuthDebugStatusSendStringTooLong:
case iscsiAuthDebugStatusSendTooMuchData:
default:
/*
* Error on this side.
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
*statusCode = 0x0200;
/*
* iSCSI Initiator error
*/
} else {
*statusCode = 0x0300;
/*
* iSCSI Target error
*/
}
}
break;
case iscsiAuthStatusNoError:
case iscsiAuthStatusError:
case iscsiAuthStatusContinue:
case iscsiAuthStatusInProgress:
default:
/*
* Bad authStatus
*/
if (client->nodeType == iscsiAuthNodeTypeInitiator) {
*statusCode = 0x0200;
/*
* iSCSI Initiator error
*/
} else {
*statusCode = 0x0300;
/*
* iSCSI Target error
*/
}
}
return (iscsiAuthStatusNoError);
}
int
iscsiAuthClientGetDebugStatus(IscsiAuthClient * client, int *value)
{
if (!client || client->signature != iscsiAuthClientSignature) {
return (iscsiAuthStatusError);
}
if (client->phase != iscsiAuthPhaseDone) {
client->phase = iscsiAuthPhaseError;
return (iscsiAuthStatusError);
}
*value = client->debugStatus;
return (iscsiAuthStatusNoError);
}
const char *
iscsiAuthClientDebugStatusToText(int debugStatus)
{
const char *s;
switch (debugStatus) {
case iscsiAuthDebugStatusNotSet:
s = "Debug status not set";
break;
case iscsiAuthDebugStatusAuthPass:
s = "Authentication request passed";
break;
case iscsiAuthDebugStatusAuthRemoteFalse:
s = "Authentication not enabled";
break;
case iscsiAuthDebugStatusAuthFail:
s = "Authentication request failed";
break;
case iscsiAuthDebugStatusAuthMethodBad:
s = "AuthMethod bad";
break;
case iscsiAuthDebugStatusChapAlgorithmBad:
s = "CHAP algorithm bad";
break;
case iscsiAuthDebugStatusPasswordDecryptFailed:
s = "Decrypt password failed";
break;
case iscsiAuthDebugStatusPasswordTooShortWithNoIpSec:
s = "Local password too short with no IPSec";
break;
case iscsiAuthDebugStatusAuthServerError:
s = "Unexpected error from authentication server";
break;
case iscsiAuthDebugStatusAuthStatusBad:
s = "Authentication request status bad";
break;
case iscsiAuthDebugStatusAuthPassNotValid:
s = "Authentication pass status not valid";
break;
case iscsiAuthDebugStatusSendDuplicateSetKeyValue:
s = "Same key set more than once on send";
break;
case iscsiAuthDebugStatusSendStringTooLong:
s = "Key value too long on send";
break;
case iscsiAuthDebugStatusSendTooMuchData:
s = "Too much data on send";
break;
case iscsiAuthDebugStatusAuthMethodExpected:
s = "AuthMethod key expected";
break;
case iscsiAuthDebugStatusChapAlgorithmExpected:
s = "CHAP algorithm key expected";
break;
case iscsiAuthDebugStatusChapIdentifierExpected:
s = "CHAP identifier expected";
break;
case iscsiAuthDebugStatusChapChallengeExpected:
s = "CHAP challenge expected";
break;
case iscsiAuthDebugStatusChapResponseExpected:
s = "CHAP response expected";
break;
case iscsiAuthDebugStatusChapUsernameExpected:
s = "CHAP username expected";
break;
case iscsiAuthDebugStatusAuthMethodNotPresent:
s = "AuthMethod key not present";
break;
case iscsiAuthDebugStatusAuthMethodReject:
s = "AuthMethod negotiation failed";
break;
case iscsiAuthDebugStatusAuthMethodNone:
s = "AuthMethod negotiated to none";
break;
case iscsiAuthDebugStatusChapAlgorithmReject:
s = "CHAP algorithm negotiation failed";
break;
case iscsiAuthDebugStatusChapChallengeReflected:
s = "CHAP challange reflected";
break;
case iscsiAuthDebugStatusPasswordIdentical:
s = "Local password same as remote";
break;
case iscsiAuthDebugStatusLocalPasswordNotSet:
s = "Local password not set";
break;
case iscsiAuthDebugStatusChapIdentifierBad:
s = "CHAP identifier bad";
break;
case iscsiAuthDebugStatusChapChallengeBad:
s = "CHAP challenge bad";
break;
case iscsiAuthDebugStatusChapResponseBad:
s = "CHAP response bad";
break;
case iscsiAuthDebugStatusUnexpectedKeyPresent:
s = "Unexpected key present";
break;
case iscsiAuthDebugStatusTbitSetIllegal:
s = "T bit set on response, but not on previous message";
break;
case iscsiAuthDebugStatusTbitSetPremature:
s = "T bit set on response, but authenticaton not complete";
break;
case iscsiAuthDebugStatusRecvMessageCountLimit:
s = "Message count limit reached on receive";
break;
case iscsiAuthDebugStatusRecvDuplicateSetKeyValue:
s = "Same key set more than once on receive";
break;
case iscsiAuthDebugStatusRecvStringTooLong:
s = "Key value too long on receive";
break;
case iscsiAuthDebugStatusRecvTooMuchData:
s = "Too much data on receive";
break;
default:
s = "Unknown error";
}
return (s);
}