📄 iscsi-auth-client.c
字号:
/* * iSCSI driver for Linux * Copyright (C) 2001 Cisco Systems, Inc. * maintained by linux-iscsi-devel@lists.sourceforge.net * * 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: iscsi-auth-client.c,v 1.14 2005/01/19 22:53:50 mikenc Exp $ * * This file implements the iSCSI CHAP authentication method based on * RFC 3720. The code in this file is meant to be common for both kernel and * user level and makes use of only limited library functions, presently only * string.h. Routines specific to kernel, user level are implemented in * seperate files under the appropriate directories. * This code in this files assumes a single thread of execution * for each iscsi_acl structure, and does no locking. */#include "iscsi-auth-client.h"#include "iscsi-session.h"#include "iscsi-protocol.h"#include "iscsi-sfnet.h"static const char acl_hexstring[] = "0123456789abcdefABCDEF";static const char acl_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static const char acl_authmethod_set_chap_alg_list[] = "CHAP";static const char acl_reject_option_name[] = "Reject";static const char acl_none_option_name[] = "None";static intacl_text_to_number(const char *text, unsigned long *num){ char *end; unsigned long number = *num; if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) number = simple_strtoul(text + 2, &end, 16); else number = simple_strtoul(text, &end, 10); if (*text != '\0' && *end == '\0') { *num = number; return 0; /* No error */ } else return 1; /* Error */}static intacl_chk_string(const char *s, unsigned int max_len, unsigned int *out_len){ unsigned int len; if (!s) return 1; for (len = 0; len < max_len; len++) if (*s++ == '\0') { if (out_len) *out_len = len; return 0; } return 1;}static intacl_str_index(const char *s, int c){ char *str = strchr(s, c); if (str) return (str - s); else return -1;}static intacl_chk_auth_mthd_optn(int val){ if (val == AUTH_OPTION_NONE || val == AUTH_METHOD_CHAP) return 0; return 1;}static const char *acl_authmethod_optn_to_text(int value){ const char *s; switch (value) { case AUTH_OPTION_REJECT: s = acl_reject_option_name; break; case AUTH_OPTION_NONE: s = acl_none_option_name; break; case AUTH_METHOD_CHAP: s = acl_authmethod_set_chap_alg_list; break; default: s = 0; } return s;}static intacl_chk_chap_alg_optn(int chap_algorithm){ if (chap_algorithm == AUTH_OPTION_NONE || chap_algorithm == AUTH_CHAP_ALG_MD5) return 0; return 1;}static intacl_data_to_text(unsigned char *data, unsigned int data_length, char *text, unsigned int text_length){ unsigned long n; if (!text || text_length == 0) return 1; if (!data || data_length == 0) { *text = '\0'; return 1; } if (text_length < 3) { *text = '\0'; return 1; } *text++ = '0'; *text++ = 'x'; text_length -= 2; while (data_length > 0) { if (text_length < 3) { *text = '\0'; return 1; } n = *data++; data_length--; *text++ = acl_hexstring[(n >> 4) & 0xf]; *text++ = acl_hexstring[n & 0xf]; text_length -= 2; } *text = '\0'; return 0;}static intacl_hex_to_data(const char *text, unsigned int text_length, unsigned char *data, unsigned int *data_lenp){ int i; unsigned int n1; unsigned int n2; unsigned int data_length = *data_lenp; if ((text_length % 2) == 1) { i = acl_str_index(acl_hexstring, *text++); if (i < 0) return 1; /* error, bad character */ if (i > 15) i -= 6; n2 = i; if (data_length < 1) return 1; /* error, too much data */ *data++ = n2; data_length--; } while (*text != '\0') { i = acl_str_index(acl_hexstring, *text++); if (i < 0) return 1; /* error, bad character */ if (i > 15) i -= 6; n1 = i; if (*text == '\0') return 1; /* error, odd string length */ i = acl_str_index(acl_hexstring, *text++); if (i < 0) return 1; /* error, bad character */ if (i > 15) i -= 6; n2 = i; if (data_length < 1) return 1; /* error, too much data */ *data++ = (n1 << 4) | n2; data_length--; } if (data_length >= *data_lenp) return 1; /* error, no data */ *data_lenp = *data_lenp - data_length; return 0; /* no error */}static intacl_base64_to_data(const char *text, unsigned char *data, unsigned int *data_lenp){ int i; unsigned int n; unsigned int count; unsigned int data_length = *data_lenp; n = 0; count = 0; while (*text != '\0' && *text != '=') { i = acl_str_index(acl_base64_string, *text++); if (i < 0) return 1; /* error, bad character */ n = (n << 6 | (unsigned int)i); count++; if (count >= 4) { if (data_length < 3) return 1; /* error, too much data */ *data++ = n >> 16; *data++ = n >> 8; *data++ = n; data_length -= 3; n = 0; count = 0; } } while (*text != '\0') if (*text++ != '=') return 1; /* error, bad pad */ if (count == 0) { /* do nothing */ } else if (count == 2) { if (data_length < 1) return 1; /* error, too much data */ n = n >> 4; *data++ = n; data_length--; } else if (count == 3) { if (data_length < 2) return 1; /* error, too much data */ n = n >> 2; *data++ = n >> 8; *data++ = n; data_length -= 2; } else return 1; /* bad encoding */ if (data_length >= *data_lenp) return 1; /* error, no data */ *data_lenp = *data_lenp - data_length; return 0; /* no error */}static intacl_text_to_data(const char *text, unsigned char *data, unsigned int *data_length){ int status; unsigned int text_length; status = acl_chk_string(text, 2 + 2 * AUTH_LARGE_BINARY_MAX_LEN + 1, &text_length); if (status) return status; if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) { /* skip prefix */ text += 2; text_length -= 2; status = acl_hex_to_data(text, text_length, data, data_length); } else if (text[0] == '0' && (text[1] == 'b' || text[1] == 'B')) { /* skip prefix */ text += 2; text_length -= 2; status = acl_base64_to_data(text, data, data_length); } else status = 1; /* prefix not recognized. */ return status;}static voidacl_init_key_blk(struct auth_key_block *key_blk){ char *str_block = key_blk->str_block; memset(key_blk, 0, sizeof(*key_blk)); key_blk->str_block = str_block;}static voidacl_set_key_value(struct auth_key_block *key_blk, int key_type, const char *key_val){ unsigned int length; char *string; if (key_blk->key[key_type].value_set) { key_blk->dup_set = 1; return; } key_blk->key[key_type].value_set = 1; if (!key_val) return; if (acl_chk_string(key_val, AUTH_STR_MAX_LEN, &length)) { key_blk->str_too_long = 1; return; } length += 1; if ((key_blk->blk_length + length) > AUTH_STR_BLOCK_MAX_LEN) { key_blk->too_much_data = 1; return; } string = &key_blk->str_block[key_blk->blk_length]; if (strlcpy(string, key_val, length) >= length) { key_blk->too_much_data = 1; return; } key_blk->blk_length += length; key_blk->key[key_type].string = string; key_blk->key[key_type].present = 1;}static const char *acl_get_key_val(struct auth_key_block *key_blk, int key_type){ key_blk->key[key_type].processed = 1; if (!key_blk->key[key_type].present) return 0; return key_blk->key[key_type].string;}static voidacl_chk_key(struct iscsi_acl *client, int key_type, int *negotiated_option, unsigned int option_count, int *option_list, const char *(*value_to_text) (int)){ const char *key_val; int length; unsigned int i; key_val = acl_get_key_val(&client->recv_key_block, key_type); if (!key_val) { *negotiated_option = AUTH_OPTION_NOT_PRESENT; return; } while (*key_val != '\0') { length = 0; while (*key_val != '\0' && *key_val != ',') client->scratch_key_value[length++] = *key_val++; if (*key_val == ',') key_val++; client->scratch_key_value[length++] = '\0'; for (i = 0; i < option_count; i++) { const char *s = (*value_to_text)(option_list[i]); if (!s) continue; if (strcmp(client->scratch_key_value, s) == 0) { *negotiated_option = option_list[i]; return; } } } *negotiated_option = AUTH_OPTION_REJECT;}static voidacl_set_key(struct iscsi_acl *client, int key_type, unsigned int option_count, int *option_list, const char *(*value_to_text)(int)){ unsigned int i; if (option_count == 0) { /* * No valid options to send, but we always want to * send something. */ acl_set_key_value(&client->send_key_block, key_type, acl_none_option_name); return; } if (option_count == 1 && option_list[0] == AUTH_OPTION_NOT_PRESENT) { acl_set_key_value(&client->send_key_block, key_type, 0); return; } for (i = 0; i < option_count; i++) { const char *s = (*value_to_text)(option_list[i]); if (!s) continue; if (i == 0) strlcpy(client->scratch_key_value, s, AUTH_STR_MAX_LEN); else { strlcat(client->scratch_key_value, ",", AUTH_STR_MAX_LEN); strlcat(client->scratch_key_value, s, AUTH_STR_MAX_LEN); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -