📄 iscsiauthclient.c
字号:
/* * iSCSI connection daemon * Copyright (C) 2001 Cisco Systems, Inc. * maintained by linux-iscsi@cisco.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. * * $Id: iscsiAuthClient.c,v 1.11 2002/09/23 17:46:00 smferris Exp $ *//* * This file implements the iSCSI CHAP authentication method based on * draft-ietf-ips-iscsi-15.txt. 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 "iscsiAuthClient.h"#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endifstruct iscsiAuthClientKeyInfo_t { const char *name;};typedef struct iscsiAuthClientKeyInfo_t IscsiAuthClientKeyInfo;IscsiAuthClientGlobalStats iscsiAuthClientGlobalStats;static IscsiAuthClientKeyInfo iscsiAuthClientKeyInfo[iscsiAuthKeyTypeMaxCount] = { {"AuthMethod"}, {"CHAP_A"}, {"CHAP_I"}, {"CHAP_C"}, {"CHAP_R"}, {"CHAP_N"}};static const char iscsiAuthClientHexString[] = "0123456789abcdefABCDEF";static const char iscsiAuthClientBase64String[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static const char iscsiAuthClientAuthMethodChapOptionName[] = "CHAP";static intiscsiAuthClientCheckString(const char *s, unsigned int *pLength){ unsigned int length; if (!s) { return TRUE; } for (length = 0; length < iscsiAuthStringMaxLength; length++) { if (*s++ == '\0') { if (pLength) *pLength = length; return FALSE; } } return TRUE;}static intiscsiAuthClientCheckNodeType(int nodeType){ if (nodeType == iscsiAuthNodeTypeInitiator || nodeType == iscsiAuthNodeTypeTarget) { return FALSE; } return TRUE;}static intiscsiAuthClientCheckVersion(int value){ if (value == iscsiAuthVersionDraft8 || value == iscsiAuthVersionRfc) { return FALSE; } return TRUE;}static intiscsiAuthClientCheckNegRole(int value){ if (value == iscsiAuthNegRoleOriginator || value == iscsiAuthNegRoleResponder) { return FALSE; } return TRUE;}static intiscsiAuthClientCheckAuthMethodOption(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 = NULL; } return s;}static intiscsiAuthClientCheckChapAlgorithmOption(int chapAlgorithm){ if (chapAlgorithm == iscsiAuthOptionNone || chapAlgorithm == iscsiAuthChapAlgorithmMd5) { return FALSE; } return TRUE;}static voidiscsiAuthClientDataToHex(unsigned char *data, unsigned int length, char *text){ *text++ = '0'; *text++ = 'x'; while (length > 0) { *text++ = iscsiAuthClientHexString[(*data >> 4) & 0xf]; *text++ = iscsiAuthClientHexString[*data & 0xf]; data++; length--; } *text++ = '\0';}static voidiscsiAuthClientDataToBase64( unsigned char *data, unsigned int length, char *text){ unsigned long n; *text++ = '0'; *text++ = 'b'; while (length > 3) { n = *data++; n = (n << 8) | *data++; n = (n << 8) | *data++; *text++ = iscsiAuthClientBase64String[(n >> 18) & 0x3f]; *text++ = iscsiAuthClientBase64String[(n >> 12) & 0x3f]; *text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f]; *text++ = iscsiAuthClientBase64String[n & 0x3f]; length -= 3; } if (length == 1) { n = *data++; n = n << 4; *text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f]; *text++ = iscsiAuthClientBase64String[n & 0x3f]; *text++ = '='; *text++ = '='; } else if (length == 2) { 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';}static voidiscsiAuthClientDataToText( int base64, unsigned char *data, unsigned int length, char *text){ if (base64) { iscsiAuthClientDataToBase64(data, length, text); } else { iscsiAuthClientDataToHex(data, length, text); }}static intiscsiAuthClientHexToData( const char *text, unsigned char *data, unsigned int *dataLength){ char *p; unsigned int n1; unsigned int n2; unsigned int length = 0; n1 = strlen(text); if (n1 == 0) return 1; /* error, no data */ if (((n1 + 1) / 2) > *dataLength) { return 1; /* error, length too long */ } if ((n1 % 2) == 1) { p = strchr(iscsiAuthClientHexString, *text++); if (!p) return 1; /* error, bad character */ n2 = p - iscsiAuthClientHexString; if (n2 > 15) n2 -= 6; *data++ = n2; length++; } while (*text != '\0') { p = strchr(iscsiAuthClientHexString, *text++); if (!p) return 1; /* error, bad character */ n1 = p - iscsiAuthClientHexString; if (n1 > 15) n1 -= 6; if (*text == '\0') return 1; /* error, odd string length */ p = strchr(iscsiAuthClientHexString, *text++); if (!p) return 1; /* error, bad character */ n2 = p - iscsiAuthClientHexString; if (n2 > 15) n2 -= 6; *data++ = (n1 << 4) | n2; length++; } *dataLength = length; return 0; /* no error */}static intiscsiAuthClientBase64ToData( const char *text, unsigned char *data, unsigned int *dataLength){ char *p; unsigned int n1; unsigned int length = 0; unsigned int n; int count; p = strchr(text, '='); while (p && *p != '\0') { if (*p != '=') return 1; /* bad pad character */ *p++ = '\0'; /* delete pad character */ } n1 = strlen(text); if (n1 == 0) return 1; /* error, no data */ if (((n1 * 3) / 4) > *dataLength) { return 1; /* error, length too long */ } n = 0; count = 0; while (*text != '\0') { p = strchr(iscsiAuthClientBase64String, *text++); if (!p) return 1; /* error, bad character */ n1 = p - iscsiAuthClientBase64String; n = (n << 6 | n1); count++; if (count >= 4) { *data++ = n >> 16; *data++ = n >> 8; *data++ = n; length += 3; n = 0; count = 0; } } if (count == 0) { /* do nothing */ } else if (count == 2) { n = n >> 4; *data++ = n; length += 1; } else if (count == 3) { n = n >> 2; *data++ = n >> 8; *data++ = n; length += 2; } else { return 1; /* bad encoding */ } *dataLength = length; return 0; /* no error */}static intiscsiAuthClientTextToData( const char *text, unsigned char *data, unsigned int *dataLength){ int status; if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) { /* skip prefix */ text += 2; status = iscsiAuthClientHexToData(text, data, dataLength); } else if (text[0] == '0' && (text[1] == 'b' || text[1] == 'B')) { /* skip prefix */ text += 2; status = iscsiAuthClientBase64ToData(text, data, dataLength); } else { status = 1; /* prefix not recognized. */ } return status;}static IscsiAuthDebugStatusiscsiAuthClientChapComputeResponse( IscsiAuthClient *client, unsigned char *passwordData, unsigned int passwordLength, unsigned int id, unsigned char *challengeData, unsigned int challengeLength, unsigned char *responseData){ unsigned char idData[1]; IscsiAuthMd5Context context; unsigned char *outData = client->scratchKeyValue; unsigned int outLength = sizeof(client->scratchKeyValue); if (!client->passwordPresent) { return iscsiAuthDebugStatusLocalPasswordNotSet; } iscsiAuthMd5Init(&context); /* id byte */ idData[0] = id; iscsiAuthMd5Update(&context, idData, 1); /* decrypt password */ if (iscsiAuthClientData( outData, &outLength, passwordData, passwordLength)) { return iscsiAuthDebugStatusPasswordDecryptFailed; } if (!client->ipSec && outLength < 12) { return iscsiAuthDebugStatusPasswordTooShortWithNoIpSec; } /* shared secret */ iscsiAuthMd5Update(&context, outData, outLength); /* clear decrypted password */ memset(outData, 0, sizeof(outData)); /* challenge value */ iscsiAuthMd5Update(&context, challengeData, challengeLength); iscsiAuthMd5Final(responseData, &context); return iscsiAuthDebugStatusNotSet; /* no error */}static voidiscsiAuthClientInitKeyBlock(IscsiAuthClientKeyBlock *keyBlock){ memset(keyBlock, 0, sizeof(*keyBlock));}static voidiscsiAuthClientSetKeyValue( IscsiAuthClientKeyBlock *keyBlock, int keyType, const char *keyValue){ unsigned int length; if (keyBlock->key[keyType].valueSet) { keyBlock->duplicateSet = TRUE; return; } keyBlock->key[keyType].valueSet = TRUE; if (!keyValue) { return; } if (iscsiAuthClientCheckString(keyValue, &length)) { keyBlock->stringTooLong = TRUE; return; } if ((keyBlock->blockLength + length + 1) > iscsiAuthStringBlockMaxLength) { keyBlock->tooMuchData = TRUE; return; } keyBlock->key[keyType].value = &keyBlock->block[keyBlock->blockLength]; keyBlock->blockLength += (length + 1); strcpy(keyBlock->key[keyType].value, keyValue); keyBlock->key[keyType].present = TRUE;}static const char *iscsiAuthClientGetKeyValue( IscsiAuthClientKeyBlock *keyBlock, int keyType){ keyBlock->key[keyType].processed = TRUE; if (!keyBlock->key[keyType].present) { return NULL; } return keyBlock->key[keyType].value;}static voidiscsiAuthClientCheckKey( 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 voidiscsiAuthClientSetKey( 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, NULL); return; } for (i = 0; i < optionCount; i++) { const char *s = (*valueToText)(client, optionList[i]); if (!s) continue; if (i == 0) { strcpy(client->scratchKeyValue, s); } else { strcat(client->scratchKeyValue, ","); strcat(client->scratchKeyValue, s); } } iscsiAuthClientSetKeyValue( &client->sendKeyBlock, keyType, client->scratchKeyValue);}static voidiscsiAuthClientCheckAuthMethodKey(IscsiAuthClient *client){ iscsiAuthClientCheckKey( client, iscsiAuthKeyTypeAuthMethod, &client->negotiatedAuthMethod, client->authMethodValidCount, client->authMethodValidList, iscsiAuthClientAuthMethodOptionToText);}static voidiscsiAuthClientSetAuthMethodKey( IscsiAuthClient *client, unsigned int authMethodCount, int *authMethodList){ iscsiAuthClientSetKey( client, iscsiAuthKeyTypeAuthMethod, authMethodCount, authMethodList, iscsiAuthClientAuthMethodOptionToText);}static voidiscsiAuthClientCheckChapAlgorithmKey(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') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -