From: Mike Christie <michaelc@cs.wisc.edu>
To: linux-scsi@vger.kernel.org
Subject: [PATCH 8/10][RFC] linux-iscsi driver
Date: Mon, 10 Jan 2005 15:02:50 -0800 [thread overview]
Message-ID: <41E3099A.9020108@cs.wisc.edu> (raw)
[-- Attachment #1: Type: text/plain, Size: 353 bytes --]
iSCSI Authentication.
Sorry about the blkdev include in iscsi-auth.h. will
correct when we figure out what file (or correct order
of files), to include when using scatterlists and
sg_init_one. Can we include an asm file before a linux
one in this case, or does linux/scatterlist.h need
a forward declaration, or is there sone other file
we should use?
[-- Attachment #2: 08-iscsi-auth.patch --]
[-- Type: text/x-patch, Size: 61693 bytes --]
diff -Naurp scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-auth.c scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-auth.c
--- scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-auth.c 1969-12-31 16:00:00.000000000 -0800
+++ scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-auth.c 2005-01-10 12:32:30.131322392 -0800
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ *
+ * This file contains kernel wrappers around the iscsi auth common code.
+ */
+#include <linux/crypto.h>
+#include <linux/blkdev.h>
+#include <linux/scatterlist.h>
+
+#include "iscsi-sfnet.h"
+#include "iscsi-protocol.h"
+#include "iscsi-session.h"
+
+/*
+ * Authenticate a target's CHAP response.
+ *
+ * Use the kernel crypto API
+ */
+enum auth_dbg_status
+acl_chap_compute_rsp(struct iscsi_acl *client, int rmt_auth, u32 id,
+ u8 *challenge_data, u32 challenge_length,
+ u8 *response_data)
+{
+ struct iscsi_session *session = client->session_handle;
+ u8 id_data[1];
+ struct scatterlist sg;
+ struct crypto_tfm *tfm = session->md5_tfm;
+ u8 out_data[AUTH_STR_MAX_LEN];
+ u32 out_length = AUTH_STR_MAX_LEN;
+
+ if (!client->passwd_present)
+ return AUTH_DBG_STATUS_LOCAL_PASSWD_NOT_SET;
+
+ crypto_digest_init(tfm);
+ /* id byte */
+ id_data[0] = id;
+ sg_init_one(&sg, &id_data[0], 1);
+ crypto_digest_update(tfm, &sg, 1);
+
+ /* decrypt password */
+ if (acl_data(out_data, &out_length, client->passwd_data,
+ client->passwd_length))
+ return AUTH_DBG_STATUS_PASSWD_DECRYPT_FAILED;
+
+ if (!rmt_auth && !client->ip_sec && out_length < 12)
+ return AUTH_DBG_STATUS_PASSWD_TOO_SHORT_WITH_NO_IPSEC;
+
+ /* shared secret */
+ sg_init_one(&sg, out_data, out_length);
+ crypto_digest_update(tfm, &sg, 1);
+
+ /* clear decrypted password */
+ memset(out_data, 0, AUTH_STR_MAX_LEN);
+
+ /* challenge value */
+ sg_init_one(&sg, challenge_data, challenge_length);
+ crypto_digest_update(tfm, &sg, 1);
+ crypto_digest_final(tfm, response_data);
+
+ return AUTH_DBG_STATUS_NOT_SET; /* no error */
+}
+
+int
+acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id,
+ unsigned char *challenge_data,
+ unsigned int challenge_length,
+ unsigned char *response_data,
+ unsigned int rsp_length)
+{
+ struct iscsi_session *session = client->session_handle;
+ struct crypto_tfm *tfm = session->md5_tfm;
+ struct scatterlist sg[3];
+ unsigned char id_byte = id;
+ unsigned char verify_data[16];
+
+ /* the expected credentials are in the session */
+ if (session->username_in == NULL) {
+ iscsi_err("Failing authentication, no incoming username "
+ "configured to authenticate target %s\n",
+ session->target_name);
+ return AUTH_STATUS_FAIL;
+ }
+ if (strcmp(username, session->username_in) != 0) {
+ iscsi_err("Failing authentication, received incorrect username "
+ "from target %s\n", session->target_name);
+ return AUTH_STATUS_FAIL;
+ }
+
+ if ((session->password_length_in < 1) ||
+ (session->password_in == NULL) ||
+ (session->password_in[0] == '\0')) {
+ iscsi_err("Failing authentication, no incoming password "
+ "configured to authenticate target %s\n",
+ session->target_name);
+ return AUTH_STATUS_FAIL;
+ }
+
+ /* challenge length is I->T, and shouldn't need to be checked */
+
+ if (rsp_length != sizeof(verify_data)) {
+ iscsi_err("Failing authentication, received incorrect CHAP "
+ "response length %u from target %s\n", rsp_length,
+ session->target_name);
+ return AUTH_STATUS_FAIL;
+ }
+
+ /* id byte */
+ id_byte = id;
+ sg_init_one(&sg[0], &id_byte, 1);
+
+ /* shared secret */
+ sg_init_one(&sg[1], session->password_in, session->password_length_in);
+
+ /* challenge value */
+ sg_init_one(&sg[2], challenge_data, challenge_length);
+
+ memset(verify_data, 0, sizeof(verify_data));
+ crypto_digest_init(tfm);
+ crypto_digest_digest(tfm, sg, 3, verify_data);
+
+ if (memcmp(response_data, verify_data, sizeof(verify_data)) == 0)
+ return AUTH_STATUS_PASS;
+
+ iscsi_err("Failing authentication, received incorrect CHAP response "
+ "from target %s\n", session->target_name);
+
+ return AUTH_STATUS_FAIL;
+}
diff -Naurp scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-auth-client.c scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-auth-client.c
--- scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-auth-client.c 1969-12-31 16:00:00.000000000 -0800
+++ scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-auth-client.c 2005-01-10 12:32:30.131322392 -0800
@@ -0,0 +1,1839 @@
+/*
+ * 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.
+ *
+ * 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 int
+acl_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 int
+acl_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 int
+acl_str_index(const char *s, int c)
+{
+ char *str = strchr(s, c);
+
+ if (str)
+ return (str - s);
+ else
+ return -1;
+}
+
+static int
+acl_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 int
+acl_chk_chap_alg_optn(int chap_algorithm)
+{
+ if (chap_algorithm == AUTH_OPTION_NONE ||
+ chap_algorithm == AUTH_CHAP_ALG_MD5)
+ return 0;
+
+ return 1;
+}
+
+static int
+acl_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 int
+acl_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 int
+acl_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 int
+acl_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 void
+acl_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 void
+acl_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 void
+acl_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 void
+acl_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);
+ }
+ }
+
+ acl_set_key_value(&client->send_key_block, key_type,
+ client->scratch_key_value);
+}
+
+static void
+acl_chk_auth_method_key(struct iscsi_acl *client)
+{
+ acl_chk_key(client, AUTH_KEY_TYPE_AUTH_METHOD,
+ &client->negotiated_auth_method,
+ client->auth_method_valid_count,
+ client->auth_method_valid_list,
+ acl_authmethod_optn_to_text);
+}
+
+static void
+acl_set_auth_method_key(struct iscsi_acl *client,
+ unsigned int auth_method_count, int *auth_method_list)
+{
+ acl_set_key(client, AUTH_KEY_TYPE_AUTH_METHOD, auth_method_count,
+ auth_method_list, acl_authmethod_optn_to_text);
+}
+
+static void
+acl_chk_chap_alg_key(struct iscsi_acl *client)
+{
+ const char *key_val;
+ int length;
+ unsigned long number;
+ unsigned int i;
+
+ key_val = acl_get_key_val(&client->recv_key_block,
+ AUTH_KEY_TYPE_CHAP_ALG);
+ if (!key_val) {
+ client->negotiated_chap_alg = 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';
+
+ if (acl_text_to_number(client->scratch_key_value, &number))
+ continue;
+
+
+ for (i = 0; i < client->chap_alg_count; i++)
+ if (number == (unsigned long)client->chap_alg_list[i])
+ {
+ client->negotiated_chap_alg = number;
+ return;
+ }
+ }
+
+ client->negotiated_chap_alg = AUTH_OPTION_REJECT;
+}
+
+static void
+acl_set_chap_alg_key(struct iscsi_acl *client, unsigned int chap_alg_count,
+ int *chap_alg_list)
+{
+ unsigned int i;
+
+ if (chap_alg_count == 0) {
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_ALG, 0);
+ return;
+ }
+
+ if (chap_alg_count == 1 &&
+ chap_alg_list[0] == AUTH_OPTION_NOT_PRESENT) {
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_ALG, 0);
+ return;
+ }
+
+ if (chap_alg_count == 1 && chap_alg_list[0] == AUTH_OPTION_REJECT) {
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_ALG,
+ acl_reject_option_name);
+ return;
+ }
+
+ for (i = 0; i < chap_alg_count; i++) {
+ char s[20];
+
+ snprintf(s, sizeof(s), "%lu",(unsigned long)chap_alg_list[i]);
+
+ 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);
+ }
+ }
+
+ acl_set_key_value(&client->send_key_block, AUTH_KEY_TYPE_CHAP_ALG,
+ client->scratch_key_value);
+}
+
+static void
+acl_next_phase(struct iscsi_acl *client)
+{
+ switch (client->phase) {
+ case AUTH_PHASE_CONFIGURE:
+ client->phase = AUTH_PHASE_NEGOTIATE;
+ break;
+ case AUTH_PHASE_NEGOTIATE:
+ client->phase = AUTH_PHASE_AUTHENTICATE;
+
+ if (client->negotiated_auth_method == AUTH_OPTION_REJECT ||
+ client->negotiated_auth_method == AUTH_OPTION_NOT_PRESENT ||
+ client->negotiated_auth_method == AUTH_OPTION_NONE) {
+
+ client->local_state = AUTH_LOCAL_STATE_DONE;
+ client->rmt_state = AUTH_RMT_STATE_DONE;
+
+ if (client->auth_rmt) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ } else
+ client->rmt_auth_status = AUTH_STATUS_PASS;
+
+ switch (client->negotiated_auth_method) {
+ case AUTH_OPTION_REJECT:
+ client->dbg_status =
+ AUTH_DBG_STATUS_AUTH_METHOD_REJECT;
+ break;
+ case AUTH_OPTION_NOT_PRESENT:
+ client->dbg_status =
+ AUTH_DBG_STATUS_AUTH_METHOD_NOT_PRESENT;
+ break;
+ case AUTH_OPTION_NONE:
+ client->dbg_status =
+ AUTH_DBG_STATUS_AUTH_METHOD_NONE;
+ }
+
+ } else if (client->negotiated_auth_method == AUTH_METHOD_CHAP) {
+ client->local_state = AUTH_LOCAL_STATE_SEND_ALG;
+ client->rmt_state = AUTH_RMT_STATE_SEND_ALG;
+ } else {
+
+ client->local_state = AUTH_LOCAL_STATE_DONE;
+ client->rmt_state = AUTH_RMT_STATE_DONE;
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->dbg_status = AUTH_DBG_STATUS_AUTH_METHOD_BAD;
+ }
+ break;
+ case AUTH_PHASE_AUTHENTICATE:
+ client->phase = AUTH_PHASE_DONE;
+ break;
+ case AUTH_PHASE_DONE:
+ case AUTH_PHASE_ERROR:
+ default:
+ client->phase = AUTH_PHASE_ERROR;
+ }
+}
+
+static void
+acl_local_auth(struct iscsi_acl *client)
+{
+ unsigned int chap_identifier;
+ unsigned char response_data[AUTH_CHAP_RSP_LEN];
+ unsigned long number;
+ int status;
+ enum auth_dbg_status dbg_status;
+ const char *chap_identifier_key_val;
+ const char *chap_challenge_key_val;
+
+ switch (client->local_state) {
+ case AUTH_LOCAL_STATE_SEND_ALG:
+ if (client->node_type == TYPE_INITIATOR) {
+ acl_set_chap_alg_key(client, client->chap_alg_count,
+ client->chap_alg_list);
+ client->local_state = AUTH_LOCAL_STATE_RECV_ALG;
+ break;
+ }
+ /* Fall through */
+ case AUTH_LOCAL_STATE_RECV_ALG:
+ acl_chk_chap_alg_key(client);
+
+ if (client->node_type == TYPE_TARGET)
+ acl_set_chap_alg_key(client, 1,
+ &client->negotiated_chap_alg);
+
+ /* Make sure only supported CHAP algorithm is used. */
+ if (client->negotiated_chap_alg == AUTH_OPTION_NOT_PRESENT) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_EXPECTED;
+ break;
+ } else if (client->negotiated_chap_alg == AUTH_OPTION_REJECT) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_REJECT;
+ break;
+ } else if (client->negotiated_chap_alg != AUTH_CHAP_ALG_MD5) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_BAD;
+ break;
+ }
+ if (client->node_type == TYPE_TARGET) {
+ client->local_state = AUTH_LOCAL_STATE_RECV_CHALLENGE;
+ break;
+ }
+ /* Fall through */
+ case AUTH_LOCAL_STATE_RECV_CHALLENGE:
+ chap_identifier_key_val = acl_get_key_val(&client->recv_key_block,
+ AUTH_KEY_TYPE_CHAP_IDENTIFIER);
+ chap_challenge_key_val = acl_get_key_val(&client->recv_key_block,
+ AUTH_KEY_TYPE_CHAP_CHALLENGE);
+ if (client->node_type == TYPE_TARGET) {
+ if (!chap_identifier_key_val &&
+ !chap_challenge_key_val) {
+ client->local_state = AUTH_LOCAL_STATE_DONE;
+ break;
+ }
+ }
+
+ if (!chap_identifier_key_val) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status =
+ AUTH_DBG_STATUS_CHAP_IDENTIFIER_EXPECTED;
+ break;
+ }
+
+ if (!chap_challenge_key_val) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status =
+ AUTH_DBG_STATUS_CHAP_CHALLENGE_EXPECTED;
+ break;
+ }
+
+ status = acl_text_to_number(chap_identifier_key_val, &number);
+ if (status || (255 < number)) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHAP_IDENTIFIER_BAD;
+ break;
+ }
+ chap_identifier = number;
+
+ if (client->recv_chap_challenge_status) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHALLENGE_BAD;
+ break;
+ }
+
+ if (client->node_type == TYPE_TARGET &&
+ client->recv_chap_challenge.length ==
+ client->send_chap_challenge.length &&
+ memcmp(client->recv_chap_challenge.large_binary,
+ client->send_chap_challenge.large_binary,
+ client->send_chap_challenge.length) == 0) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status =
+ AUTH_DBG_STATUS_CHAP_CHALLENGE_REFLECTED;
+ break;
+ }
+
+ dbg_status = acl_chap_compute_rsp(client, 0,
+ chap_identifier,
+ client->recv_chap_challenge.large_binary,
+ client->recv_chap_challenge.length,
+ response_data);
+
+ if (dbg_status != AUTH_DBG_STATUS_NOT_SET) {
+ client->local_state = AUTH_LOCAL_STATE_ERROR;
+ client->dbg_status = dbg_status;
+ break;
+ }
+
+ acl_data_to_text(response_data,
+ AUTH_CHAP_RSP_LEN, client->scratch_key_value,
+ AUTH_STR_MAX_LEN);
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_RSP,
+ client->scratch_key_value);
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_USERNAME,
+ client->username);
+
+ client->local_state = AUTH_LOCAL_STATE_DONE;
+ break;
+ case AUTH_LOCAL_STATE_DONE:
+ break;
+ case AUTH_LOCAL_STATE_ERROR:
+ default:
+ client->phase = AUTH_PHASE_ERROR;
+ }
+}
+
+static void
+acl_rmt_auth(struct iscsi_acl *client)
+{
+ unsigned char id_data[1];
+ unsigned char response_data[AUTH_STR_MAX_LEN];
+ unsigned int rsp_len = AUTH_STR_MAX_LEN;
+ unsigned char my_rsp_data[AUTH_CHAP_RSP_LEN];
+ int status;
+ enum auth_dbg_status dbg_status;
+ const char *chap_rsp_key_val;
+ const char *chap_username_key_val;
+
+ switch (client->rmt_state) {
+ case AUTH_RMT_STATE_SEND_ALG:
+ if (client->node_type == TYPE_INITIATOR) {
+ client->rmt_state = AUTH_RMT_STATE_SEND_CHALLENGE;
+ break;
+ }
+ /* Fall through */
+ case AUTH_RMT_STATE_SEND_CHALLENGE:
+ if (!client->auth_rmt) {
+ client->rmt_auth_status = AUTH_STATUS_PASS;
+ client->dbg_status = AUTH_DBG_STATUS_AUTH_RMT_FALSE;
+ client->rmt_state = AUTH_RMT_STATE_DONE;
+ break;
+ }
+ get_random_bytes(id_data, 1);
+ client->send_chap_identifier = id_data[0];
+ snprintf(client->scratch_key_value, AUTH_STR_MAX_LEN, "%lu",
+ (unsigned long)client->send_chap_identifier);
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_IDENTIFIER,
+ client->scratch_key_value);
+
+ client->send_chap_challenge.length = client->chap_challenge_len;
+ get_random_bytes(client->send_chap_challenge.large_binary,
+ client->send_chap_challenge.length);
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_CHALLENGE, "");
+
+ client->rmt_state = AUTH_RMT_STATE_RECV_RSP;
+ break;
+ case AUTH_RMT_STATE_RECV_RSP:
+ chap_rsp_key_val = acl_get_key_val(&client->recv_key_block,
+ AUTH_KEY_TYPE_CHAP_RSP);
+ chap_username_key_val = acl_get_key_val(&client->recv_key_block,
+ AUTH_KEY_TYPE_CHAP_USERNAME);
+
+ if (!chap_rsp_key_val) {
+ client->rmt_state = AUTH_RMT_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHAP_RSP_EXPECTED;
+ break;
+ }
+
+ if (!chap_username_key_val) {
+ client->rmt_state = AUTH_RMT_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHAP_USERNAME_EXPECTED;
+ break;
+ }
+
+ status = acl_text_to_data(chap_rsp_key_val, response_data,
+ &rsp_len);
+
+ if (status) {
+ client->rmt_state = AUTH_RMT_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_CHAP_RSP_BAD;
+ break;
+ }
+
+ if (rsp_len == AUTH_CHAP_RSP_LEN) {
+ dbg_status = acl_chap_compute_rsp(client, 1,
+ client->send_chap_identifier,
+ client->send_chap_challenge.large_binary,
+ client->send_chap_challenge.length,
+ my_rsp_data);
+
+ if (dbg_status == AUTH_DBG_STATUS_NOT_SET &&
+ memcmp(my_rsp_data, response_data,
+ AUTH_CHAP_RSP_LEN) == 0) {
+ client->rmt_state = AUTH_RMT_STATE_ERROR;
+ client->dbg_status = AUTH_DBG_STATUS_PASSWD_IDENTICAL;
+ break;
+ }
+ }
+
+ strlcpy(client->chap_username, chap_username_key_val,
+ AUTH_STR_MAX_LEN);
+
+ status = acl_chap_auth_request(client, client->chap_username,
+ client->send_chap_identifier,
+ client->send_chap_challenge.
+ large_binary,
+ client->send_chap_challenge.
+ length, response_data,
+ rsp_len);
+
+ client->rmt_auth_status = (enum auth_status) status;
+ client->auth_rsp_flag = 1;
+
+ if (client->auth_server_error_flag) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->dbg_status = AUTH_DBG_STATUS_AUTH_SERVER_ERROR;
+ } else if (client->rmt_auth_status == AUTH_STATUS_PASS)
+ client->dbg_status = AUTH_DBG_STATUS_AUTH_PASS;
+ else if (client->rmt_auth_status == AUTH_STATUS_FAIL)
+ client->dbg_status = AUTH_DBG_STATUS_AUTH_FAIL;
+ else {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->dbg_status = AUTH_DBG_STATUS_AUTH_STATUS_BAD;
+ }
+ client->rmt_state = AUTH_RMT_STATE_DONE;
+
+ /* Fall through */
+ case AUTH_RMT_STATE_DONE:
+ break;
+ case AUTH_RMT_STATE_ERROR:
+ default:
+ client->phase = AUTH_PHASE_ERROR;
+ }
+}
+
+static void
+acl_hand_shake(struct iscsi_acl *client)
+{
+ if (client->phase == AUTH_PHASE_DONE)
+
+ /*
+ * Should only happen if authentication
+ * protocol error occured.
+ */
+ return;
+
+ if (client->node_type == TYPE_INITIATOR)
+
+ /*
+ * Target should only have set T bit on response if
+ * initiator set it on previous message.
+ */
+ if (client->recv_key_block.transit_bit &&
+ !client->transit_bit_sent_flag) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status =
+ AUTH_DBG_STATUS_T_BIT_SET_ILLEGAL;
+ return;
+ }
+
+ if (client->phase == AUTH_PHASE_NEGOTIATE) {
+ /*
+ * Should only happen if waiting for peer
+ * to send AuthMethod key or set Transit Bit.
+ */
+ if (client->node_type == TYPE_INITIATOR)
+ client->send_key_block.transit_bit = 1;
+ return;
+ }
+
+ if (client->rmt_state == AUTH_RMT_STATE_RECV_RSP ||
+ client->rmt_state == AUTH_RMT_STATE_DONE) {
+ if (client->node_type == TYPE_INITIATOR) {
+ if (client->recv_key_block.transit_bit) {
+ if (client->rmt_state !=
+ AUTH_RMT_STATE_DONE)
+ goto recv_transit_bit_err;
+ acl_next_phase(client);
+ } else
+ client->send_key_block.transit_bit = 1;
+ } else {
+ if (client->rmt_state == AUTH_RMT_STATE_DONE &&
+ client->rmt_auth_status != AUTH_STATUS_PASS)
+ /*
+ * Authentication failed, don't do T bit
+ * handshake.
+ */
+ acl_next_phase(client);
+ else {
+ /*
+ * Target can only set T bit on response if
+ * initiator set it on current message.
+ */
+ if (client->recv_key_block.transit_bit) {
+ client->send_key_block.transit_bit = 1;
+ acl_next_phase(client);
+ }
+ }
+ }
+ } else
+ if (client->node_type == TYPE_INITIATOR)
+ if (client->recv_key_block.transit_bit)
+ goto recv_transit_bit_err;
+ return;
+
+ recv_transit_bit_err:
+ /*
+ * Target set T bit on response but
+ * initiator was not done with authentication.
+ */
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status = AUTH_DBG_STATUS_T_BIT_SET_PREMATURE;
+}
+
+static int
+acl_rcv_end_status(struct iscsi_acl *client)
+{
+ int auth_status;
+ int key_type;
+
+ if (client->phase == AUTH_PHASE_ERROR)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase == AUTH_PHASE_DONE) {
+
+ /* Perform sanity check against configured parameters. */
+ if (client->auth_rmt && !client->auth_rsp_flag &&
+ client->rmt_auth_status == AUTH_STATUS_PASS) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->dbg_status = AUTH_DBG_STATUS_AUTHPASS_NOT_VALID;
+ }
+
+ auth_status = client->rmt_auth_status;
+
+ } else
+ auth_status = AUTH_STATUS_CONTINUE;
+
+ if (auth_status == AUTH_STATUS_CONTINUE ||
+ auth_status == AUTH_STATUS_PASS) {
+ if (client->send_key_block.dup_set) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status =
+ AUTH_DBG_STATUS_SEND_DUP_SET_KEY_VALUE;
+ auth_status = AUTH_STATUS_FAIL;
+ } else if (client->send_key_block.str_too_long) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status =
+ AUTH_DBG_STATUS_SEND_STR_TOO_LONG;
+ auth_status = AUTH_STATUS_FAIL;
+ } else if (client->send_key_block.too_much_data) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status =
+ AUTH_DBG_STATUS_SEND_TOO_MUCH_DATA;
+ auth_status = AUTH_STATUS_FAIL;
+ } else {
+ /* Check that all incoming keys have been processed. */
+
+ for (key_type = AUTH_KEY_TYPE_FIRST;
+ key_type < AUTH_KEY_TYPE_MAX_COUNT; key_type++)
+ if (client->recv_key_block.key[key_type].present &&
+ !client->recv_key_block.key[key_type].
+ processed)
+ break;
+
+ if (key_type < AUTH_KEY_TYPE_MAX_COUNT) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status =
+ AUTH_DBG_STATUS_UNEXPECTED_KEY_PRESENT;
+ auth_status = AUTH_STATUS_FAIL;
+ }
+ }
+ }
+
+ if (auth_status != AUTH_STATUS_PASS &&
+ auth_status != AUTH_STATUS_CONTINUE) {
+ int auth_method_key_present = 0;
+ int chap_alg_key_present = 0;
+
+ /*
+ * Suppress send keys on error,
+ * except for AuthMethod and CHAP_A.
+ */
+ if (client->node_type == TYPE_TARGET) {
+ if (acl_get_key_val(&client->send_key_block,
+ AUTH_KEY_TYPE_AUTH_METHOD))
+ auth_method_key_present = 1;
+ else if (acl_get_key_val(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_ALG))
+ chap_alg_key_present = 1;
+ }
+
+ acl_init_key_blk(&client->send_key_block);
+
+ if (client->node_type == TYPE_TARGET) {
+ if (auth_method_key_present &&
+ client->negotiated_auth_method ==
+ AUTH_OPTION_REJECT)
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_AUTH_METHOD,
+ acl_reject_option_name);
+ else if (chap_alg_key_present &&
+ client->negotiated_chap_alg ==
+ AUTH_OPTION_REJECT)
+ acl_set_key_value(&client->send_key_block,
+ AUTH_KEY_TYPE_CHAP_ALG,
+ acl_reject_option_name);
+ }
+ }
+ client->recv_in_progress_flag = 0;
+
+ return auth_status;
+}
+
+int
+acl_recv_begin(struct iscsi_acl *client)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase == AUTH_PHASE_ERROR)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase == AUTH_PHASE_DONE) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ if (client->recv_in_progress_flag) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ client->recv_in_progress_flag = 1;
+
+ if (client->phase == AUTH_PHASE_CONFIGURE)
+ acl_next_phase(client);
+
+ client->transit_bit_sent_flag = client->send_key_block.transit_bit;
+
+ acl_init_key_blk(&client->recv_key_block);
+ acl_init_key_blk(&client->send_key_block);
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_recv_end(struct iscsi_acl *client)
+{
+ int next_phase_flag = 0;
+
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase == AUTH_PHASE_ERROR)
+ return AUTH_STATUS_ERROR;
+
+ if (!client->recv_in_progress_flag) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ if (client->recv_end_count > AUTH_RECV_END_MAX_COUNT) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status = AUTH_DBG_STATUS_RECV_MSG_COUNT_LIMIT;
+ } else if (client->recv_key_block.dup_set) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status = AUTH_DBG_STATUS_RECV_DUP_SET_KEY_VALUE;
+ } else if (client->recv_key_block.str_too_long) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status = AUTH_DBG_STATUS_RECV_STR_TOO_LONG;
+ } else if (client->recv_key_block.too_much_data) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status = AUTH_DBG_STATUS_RECV_TOO_MUCH_DATA;
+ }
+
+ client->recv_end_count++;
+
+ switch (client->phase) {
+ case AUTH_PHASE_NEGOTIATE:
+ acl_chk_auth_method_key(client);
+ if (client->auth_method_valid_neg_role ==
+ AUTH_NEG_ROLE_RESPONDER) {
+ if (client->negotiated_auth_method ==
+ AUTH_OPTION_NOT_PRESENT) {
+ if (client->auth_rmt ||
+ !client->recv_key_block.transit_bit) {
+ /*
+ * No AuthMethod key from peer on
+ * first message, try moving the
+ * process along by sending the
+ * AuthMethod key.
+ */
+
+ client->auth_method_valid_neg_role =
+ AUTH_NEG_ROLE_ORIGINATOR;
+ acl_set_auth_method_key(client,
+ client->auth_method_valid_count,
+ client->auth_method_valid_list);
+ 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. */
+ acl_set_auth_method_key(client, 1,
+ &client->negotiated_auth_method);
+
+ if (client->node_type == TYPE_INITIATOR)
+ acl_next_phase(client);
+ else
+ next_phase_flag = 1;
+ } else {
+
+ if (client->negotiated_auth_method ==
+ AUTH_OPTION_NOT_PRESENT) {
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ client->dbg_status =
+ AUTH_DBG_STATUS_AUTH_METHOD_EXPECTED;
+ break;
+ }
+
+ acl_next_phase(client);
+ }
+ break;
+ case AUTH_PHASE_AUTHENTICATE:
+ case AUTH_PHASE_DONE:
+ break;
+ default:
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ switch (client->phase) {
+ case AUTH_PHASE_NEGOTIATE:
+ if (next_phase_flag)
+ acl_next_phase(client);
+ break;
+ case AUTH_PHASE_AUTHENTICATE:
+ /*
+ * Must call acl_local_auth()
+ * before acl_rmt_auth()
+ * to insure processing of the CHAP algorithm key,
+ * and to avoid leaving an in progress request to the
+ * authentication service.
+ */
+ acl_local_auth(client);
+
+ if (client->local_state != AUTH_LOCAL_STATE_ERROR)
+ acl_rmt_auth(client);
+
+ if (client->local_state == AUTH_LOCAL_STATE_ERROR ||
+ client->rmt_state == AUTH_RMT_STATE_ERROR) {
+
+ client->rmt_auth_status = AUTH_STATUS_FAIL;
+ client->phase = AUTH_PHASE_DONE;
+ /* client->dbg_status should already be set. */
+ }
+ break;
+ case AUTH_PHASE_DONE:
+ break;
+ default:
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ acl_hand_shake(client);
+
+ return acl_rcv_end_status(client);
+}
+
+const char *
+acl_get_key_name(int key_type)
+{
+ /*
+ * Note: The ordering of this table must match the order
+ * defined by enum auth_key_type in iscsi-auth-client.h.
+ */
+ static char *const key_names[AUTH_KEY_TYPE_MAX_COUNT] = {
+ "AuthMethod",
+ "CHAP_A",
+ "CHAP_N",
+ "CHAP_R",
+ "CHAP_I",
+ "CHAP_C"
+ };
+
+ if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST)
+ return 0;
+
+ return key_names[key_type];
+}
+
+int
+acl_get_next_key_type(int *key_type)
+{
+ if (*key_type >= AUTH_KEY_TYPE_LAST)
+ return AUTH_STATUS_ERROR;
+
+ if (*key_type < AUTH_KEY_TYPE_FIRST)
+ *key_type = AUTH_KEY_TYPE_FIRST;
+ else
+ (*key_type)++;
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_recv_key_value(struct iscsi_acl *client, int key_type,
+ const char *user_key_val)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_NEGOTIATE &&
+ client->phase != AUTH_PHASE_AUTHENTICATE) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ if (key_type == AUTH_KEY_TYPE_CHAP_CHALLENGE) {
+ client->recv_chap_challenge.length =
+ AUTH_LARGE_BINARY_MAX_LEN;
+ client->recv_chap_challenge_status =
+ acl_text_to_data(user_key_val,
+ client->recv_chap_challenge.large_binary,
+ &client->recv_chap_challenge.length);
+ user_key_val = "";
+ }
+
+ acl_set_key_value(&client->recv_key_block, key_type, user_key_val);
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_send_key_val(struct iscsi_acl *client, int key_type, int *key_present,
+ char *user_key_val, unsigned int max_length)
+{
+ const char *key_val;
+
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_CONFIGURE &&
+ client->phase != AUTH_PHASE_NEGOTIATE &&
+ client->phase != AUTH_PHASE_AUTHENTICATE &&
+ client->phase != AUTH_PHASE_DONE) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ key_val = acl_get_key_val(&client->send_key_block, key_type);
+ if (key_val) {
+ if (key_type == AUTH_KEY_TYPE_CHAP_CHALLENGE) {
+ if (acl_data_to_text(client->send_chap_challenge.large_binary,
+ client->send_chap_challenge.length, user_key_val,
+ max_length)) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+ } else if (strlcpy(user_key_val, key_val, max_length) >=
+ max_length) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+ *key_present = 1;
+ } else
+ *key_present = 0;
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_recv_transit_bit(struct iscsi_acl *client, int value)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_NEGOTIATE &&
+ client->phase != AUTH_PHASE_AUTHENTICATE) {
+
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ if (value)
+ client->recv_key_block.transit_bit = 1;
+ else
+ client->recv_key_block.transit_bit = 0;
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_send_transit_bit(struct iscsi_acl *client, int *value)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_CONFIGURE &&
+ client->phase != AUTH_PHASE_NEGOTIATE &&
+ client->phase != AUTH_PHASE_AUTHENTICATE &&
+ client->phase != AUTH_PHASE_DONE) {
+
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ *value = client->send_key_block.transit_bit;
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+static int
+acl_set_option_list(struct iscsi_acl *client, unsigned int opt_count,
+ const int *opt_list, unsigned int *clnt_optn_count,
+ int *clnt_optn_list, unsigned int optn_max_count,
+ int (*chk_option)(int),
+ int (*chk_list)(unsigned int opt_count, const int *opt_list))
+{
+ unsigned int i, j;
+
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_CONFIGURE ||
+ opt_count > optn_max_count) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ for (i = 0; i < opt_count; i++)
+ if (chk_option(opt_list[i])) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ /* Check for duplicate entries. */
+ for (i = 0; i < opt_count; i++)
+ for (j = 0; j < opt_count; j++) {
+ if (j == i)
+ continue;
+ if (opt_list[i] == opt_list[j]) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+ }
+
+ /* Check for key specific constraints. */
+ if (chk_list)
+ if (chk_list(opt_count, opt_list)) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ for (i = 0; i < opt_count; i++)
+ clnt_optn_list[i] = opt_list[i];
+
+ *clnt_optn_count = opt_count;
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+static int
+acl_chk_auth_method_list(unsigned int option_count, const int *option_list)
+{
+ unsigned int i;
+
+ if (!option_list || option_count < 2)
+ return 1;
+
+ if (option_list[option_count - 1] != AUTH_OPTION_NONE)
+ return 1;
+
+ for (i = 0; i < (option_count - 1); i++)
+ if (option_list[i] != AUTH_OPTION_NONE)
+ return 0;
+
+ return 0;
+}
+
+static void
+acl_set_auth_method_valid(struct iscsi_acl *client)
+{
+ unsigned int i, j = 0;
+ int option = 0;
+
+ /*
+ * Following checks may need to be revised if
+ * authentication options other than CHAP and none
+ * are supported.
+ */
+ if (client->node_type == TYPE_INITIATOR) {
+ if (client->auth_rmt)
+ /*
+ * If initiator doing authentication,
+ * don't offer authentication option none.
+ */
+ option = 1;
+ else if (!client->passwd_present)
+ /*
+ * If initiator password not set,
+ * only offer authentication option none.
+ */
+ option = 2;
+ }
+
+ if (client->node_type == TYPE_TARGET) {
+ if (client->auth_rmt)
+ /*
+ * 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->auth_method_count; i++) {
+ if (option == 1) {
+ if (client->auth_method_list[i] == AUTH_OPTION_NONE)
+ continue;
+ } else if (option == 2)
+ if (client->auth_method_list[i] != AUTH_OPTION_NONE)
+ continue;
+ client->auth_method_valid_list[j++] = client->auth_method_list[i];
+ }
+
+ client->auth_method_valid_count = j;
+
+ acl_init_key_blk(&client->send_key_block);
+
+ if (client->node_type == TYPE_INITIATOR) {
+ if (client->auth_rmt) {
+ /*
+ * Initiator wants to authenticate target,
+ * always send AuthMethod key.
+ */
+ client->send_key_block.transit_bit = 0;
+ client->auth_method_valid_neg_role =
+ AUTH_NEG_ROLE_ORIGINATOR;
+ } else {
+ client->send_key_block.transit_bit = 1;
+ client->auth_method_valid_neg_role =
+ client->auth_method_neg_role;
+ }
+ } else {
+ client->send_key_block.transit_bit = 0;
+ client->auth_method_valid_neg_role = AUTH_NEG_ROLE_RESPONDER;
+ }
+
+ if (client->auth_method_valid_neg_role == AUTH_NEG_ROLE_ORIGINATOR)
+ acl_set_auth_method_key(client, client->auth_method_valid_count,
+ client->auth_method_valid_list);
+ else {
+ int value = AUTH_OPTION_NOT_PRESENT;
+ acl_set_auth_method_key(client, 1, &value);
+ }
+}
+
+static int
+acl_set_auth_method_list(struct iscsi_acl *client, unsigned int option_count,
+ const int *option_list)
+{
+ int status;
+
+ status = acl_set_option_list(client, option_count, option_list,
+ &client->auth_method_count,
+ client->auth_method_list,
+ AUTH_METHOD_MAX_COUNT,
+ acl_chk_auth_mthd_optn,
+ acl_chk_auth_method_list);
+
+ if (status != AUTH_STATUS_NO_ERROR)
+ return status;
+
+ /* Setting authMethod affects auth_method_valid. */
+ acl_set_auth_method_valid(client);
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+static int
+acl_chk_chap_alg_list(unsigned int option_count, const int *option_list)
+{
+ if (!option_list || option_count < 1)
+ return 1;
+
+ return 0;
+}
+
+static int
+acl_set_chap_alg_list(struct iscsi_acl *client, unsigned int option_count,
+ const int *option_list)
+{
+ return acl_set_option_list(client, option_count, option_list,
+ &client->chap_alg_count,
+ client->chap_alg_list,
+ AUTH_CHAP_ALG_MAX_COUNT,
+ acl_chk_chap_alg_optn,
+ acl_chk_chap_alg_list);
+}
+
+int
+acl_init(int node_type, struct iscsi_session *session)
+{
+ struct iscsi_acl *client;
+ struct auth_str_block *rcv_str_blk;
+ struct auth_str_block *snd_str_blk;
+ struct auth_large_binary *rcv_chap_chlng;
+ struct auth_large_binary *snd_chap_chlng;
+ int value_list[2];
+
+ if (!session->auth_client_block)
+ return AUTH_STATUS_ERROR;
+ client = session->auth_client_block;
+
+ if (!session->auth_recv_string_block)
+ return AUTH_STATUS_ERROR;
+ rcv_str_blk = session->auth_recv_string_block;
+
+ if (!session->auth_send_string_block)
+ return AUTH_STATUS_ERROR;
+ snd_str_blk = session->auth_send_string_block;
+
+ if (!session->auth_recv_binary_block)
+ return AUTH_STATUS_ERROR;
+ rcv_chap_chlng = session->auth_recv_binary_block;
+
+ if (!session->auth_send_binary_block)
+ return AUTH_STATUS_ERROR;
+ snd_chap_chlng = session->auth_send_binary_block;
+
+ memset(client, 0, sizeof(*client));
+ memset(rcv_str_blk, 0, sizeof(*rcv_str_blk));
+ memset(snd_str_blk, 0, sizeof(*snd_str_blk));
+ memset(rcv_chap_chlng, 0, sizeof(*rcv_chap_chlng));
+ memset(snd_chap_chlng, 0, sizeof(*snd_chap_chlng));
+
+ client->recv_key_block.str_block = rcv_str_blk->str_block;
+ client->send_key_block.str_block = snd_str_blk->str_block;
+ client->recv_chap_challenge.large_binary = rcv_chap_chlng->large_binary;
+ client->send_chap_challenge.large_binary = snd_chap_chlng->large_binary;
+
+ if (node_type != TYPE_INITIATOR && node_type != TYPE_TARGET) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ client->signature = ACL_SIGNATURE;
+ client->node_type = (enum auth_node_type) node_type;
+ client->auth_rmt = 1;
+ client->passwd_present = 0;
+ client->chap_challenge_len = AUTH_CHAP_RSP_LEN;
+ client->ip_sec = 0;
+ client->session_handle = session;
+
+ client->phase = AUTH_PHASE_CONFIGURE;
+ client->negotiated_auth_method = AUTH_OPTION_NOT_PRESENT;
+ client->negotiated_chap_alg = AUTH_OPTION_NOT_PRESENT;
+
+ if (client->node_type == TYPE_INITIATOR)
+ client->auth_method_neg_role = AUTH_NEG_ROLE_ORIGINATOR;
+ else
+ /* Initial value ignored for Target. */
+ client->auth_method_neg_role = AUTH_NEG_ROLE_RESPONDER;
+
+ value_list[0] = AUTH_METHOD_CHAP;
+ value_list[1] = AUTH_OPTION_NONE;
+
+ /*
+ * Must call after setting auth_rmt, password,
+ * and auth_method_neg_role
+ */
+ if (acl_set_auth_method_list(client, 2, value_list) !=
+ AUTH_STATUS_NO_ERROR) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ value_list[0] = AUTH_CHAP_ALG_MD5;
+
+ if (acl_set_chap_alg_list(client, 1, value_list) !=
+ AUTH_STATUS_NO_ERROR) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_finish(struct iscsi_acl *client)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ memset(client, 0, sizeof(*client));
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_user_name(struct iscsi_acl *client, const char *username)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_CONFIGURE ||
+ acl_chk_string(username, AUTH_STR_MAX_LEN, 0)) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ if (strlcpy(client->username, username, AUTH_STR_MAX_LEN) >=
+ AUTH_STR_MAX_LEN) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_passwd(struct iscsi_acl *client, const unsigned char *passwd_data,
+ unsigned int passwd_length)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_CONFIGURE ||
+ passwd_length > AUTH_STR_MAX_LEN) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ memcpy(client->passwd_data, passwd_data, passwd_length);
+ client->passwd_length = passwd_length;
+ client->passwd_present = 1;
+
+ /* Setting password may affect auth_method_valid. */
+ acl_set_auth_method_valid(client);
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_auth_rmt(struct iscsi_acl *client, int auth_rmt)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_CONFIGURE) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ client->auth_rmt = auth_rmt;
+
+ /* Setting auth_rmt may affect auth_method_valid. */
+ acl_set_auth_method_valid(client);
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_set_ip_sec(struct iscsi_acl *client, int ip_sec)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_CONFIGURE) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ client->ip_sec = ip_sec;
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+int
+acl_get_dbg_status(struct iscsi_acl *client, int *value)
+{
+ if (!client || client->signature != ACL_SIGNATURE)
+ return AUTH_STATUS_ERROR;
+
+ if (client->phase != AUTH_PHASE_DONE) {
+ client->phase = AUTH_PHASE_ERROR;
+ return AUTH_STATUS_ERROR;
+ }
+
+ *value = client->dbg_status;
+
+ return AUTH_STATUS_NO_ERROR;
+}
+
+const char *
+acl_dbg_status_to_text(int dbg_status)
+{
+ /*
+ * Note: The ordering of this table must match the order
+ * defined by enum auth_dbg_status in iscsi-auth-client.h.
+ */
+ static char *const dbg_text[AUTH_DBG_STATUS_MAX_COUNT] = {
+ "Debug status not set",
+ "Authentication request passed",
+ "Authentication not enabled",
+ "Authentication request failed",
+ "AuthMethod bad",
+ "CHAP algorithm bad",
+ "Decrypt password failed",
+ "Local password too short with no IPSec",
+ "Unexpected error from authentication server",
+ "Authentication request status bad",
+ "Authentication pass status not valid",
+ "Same key set more than once on send",
+ "Key value too long on send",
+ "Too much data on send",
+ "AuthMethod key expected",
+ "CHAP algorithm key expected",
+ "CHAP identifier expected",
+ "CHAP challenge expected",
+ "CHAP response expected",
+ "CHAP username expected",
+ "AuthMethod key not present",
+ "AuthMethod negotiation failed",
+ "AuthMethod negotiated to none",
+ "CHAP algorithm negotiation failed",
+ "CHAP challange reflected",
+ "Local password same as remote",
+ "Local password not set",
+ "CHAP identifier bad",
+ "CHAP challenge bad",
+ "CHAP response bad",
+ "Unexpected key present",
+ "T bit set on response, but not on previous message",
+ "T bit set on response, but authenticaton not complete",
+ "Message count limit reached on receive",
+ "Same key set more than once on receive",
+ "Key value too long on receive",
+ "Too much data on receive"
+ };
+
+ if (dbg_status < 0 || dbg_status >= AUTH_DBG_STATUS_MAX_COUNT)
+ return "Unknown error";
+
+ return dbg_text[dbg_status];
+}
+
+int
+acl_data(unsigned char *out_data, unsigned int *out_length,
+ unsigned char *in_data, unsigned int in_length)
+{
+ if (*out_length < in_length)
+ return 1; /* error */
+
+ memcpy(out_data, in_data, in_length);
+ *out_length = in_length;
+
+ return 0; /* no error */
+}
+
diff -Naurp scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-auth-client.h scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-auth-client.h
--- scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-auth-client.h 1969-12-31 16:00:00.000000000 -0800
+++ scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-auth-client.h 2005-01-10 12:32:30.131322392 -0800
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ *
+ * This file is the include file for for iscsi-auth-client.c
+ */
+#ifndef ISCSIAUTHCLIENT_H
+#define ISCSIAUTHCLIENT_H
+
+struct iscsi_session;
+
+enum {
+ AUTH_STR_MAX_LEN = 256,
+ AUTH_STR_BLOCK_MAX_LEN = 1024,
+ AUTH_LARGE_BINARY_MAX_LEN = 1024,
+ AUTH_RECV_END_MAX_COUNT = 10,
+ ACL_SIGNATURE = 0x5984B2E3,
+ AUTH_CHAP_RSP_LEN = 16,
+};
+
+/*
+ * Note: The ordering of these values are chosen to match
+ * the ordering of the keys as shown in the iSCSI spec.
+ * The order of table key_names in acl_get_key_name()
+ * must match the order defined by enum auth_key_type.
+ */
+enum auth_key_type {
+ AUTH_KEY_TYPE_NONE = -1,
+ AUTH_KEY_TYPE_FIRST = 0,
+ AUTH_KEY_TYPE_AUTH_METHOD = AUTH_KEY_TYPE_FIRST,
+ AUTH_KEY_TYPE_CHAP_ALG,
+ AUTH_KEY_TYPE_CHAP_USERNAME,
+ AUTH_KEY_TYPE_CHAP_RSP,
+ AUTH_KEY_TYPE_CHAP_IDENTIFIER,
+ AUTH_KEY_TYPE_CHAP_CHALLENGE,
+ AUTH_KEY_TYPE_MAX_COUNT,
+ AUTH_KEY_TYPE_LAST = AUTH_KEY_TYPE_MAX_COUNT - 1
+};
+
+enum {
+ /* Common options for all keys. */
+ AUTH_OPTION_REJECT = -2,
+ AUTH_OPTION_NOT_PRESENT = -1,
+ AUTH_OPTION_NONE = 1,
+
+ AUTH_METHOD_CHAP = 2,
+ AUTH_METHOD_MAX_COUNT = 2,
+
+ AUTH_CHAP_ALG_MD5 = 5,
+ AUTH_CHAP_ALG_MAX_COUNT = 2
+};
+
+enum auth_neg_role {
+ AUTH_NEG_ROLE_ORIGINATOR = 1,
+ AUTH_NEG_ROLE_RESPONDER = 2
+};
+
+enum auth_status {
+ AUTH_STATUS_NO_ERROR = 0,
+ AUTH_STATUS_ERROR,
+ AUTH_STATUS_PASS,
+ AUTH_STATUS_FAIL,
+ AUTH_STATUS_CONTINUE,
+};
+
+/*
+ * Note: The order of table dbg_text in acl_dbg_status_to_text()
+ * must match the ordered defined by enum auth_dbg_status.
+ */
+enum auth_dbg_status {
+ AUTH_DBG_STATUS_NOT_SET = 0,
+
+ AUTH_DBG_STATUS_AUTH_PASS,
+ AUTH_DBG_STATUS_AUTH_RMT_FALSE,
+
+ AUTH_DBG_STATUS_AUTH_FAIL,
+
+ AUTH_DBG_STATUS_AUTH_METHOD_BAD,
+ AUTH_DBG_STATUS_CHAP_ALG_BAD,
+ AUTH_DBG_STATUS_PASSWD_DECRYPT_FAILED,
+ AUTH_DBG_STATUS_PASSWD_TOO_SHORT_WITH_NO_IPSEC,
+ AUTH_DBG_STATUS_AUTH_SERVER_ERROR,
+ AUTH_DBG_STATUS_AUTH_STATUS_BAD,
+ AUTH_DBG_STATUS_AUTHPASS_NOT_VALID,
+ AUTH_DBG_STATUS_SEND_DUP_SET_KEY_VALUE,
+ AUTH_DBG_STATUS_SEND_STR_TOO_LONG,
+ AUTH_DBG_STATUS_SEND_TOO_MUCH_DATA,
+
+ AUTH_DBG_STATUS_AUTH_METHOD_EXPECTED,
+ AUTH_DBG_STATUS_CHAP_ALG_EXPECTED,
+ AUTH_DBG_STATUS_CHAP_IDENTIFIER_EXPECTED,
+ AUTH_DBG_STATUS_CHAP_CHALLENGE_EXPECTED,
+ AUTH_DBG_STATUS_CHAP_RSP_EXPECTED,
+ AUTH_DBG_STATUS_CHAP_USERNAME_EXPECTED,
+
+ AUTH_DBG_STATUS_AUTH_METHOD_NOT_PRESENT,
+ AUTH_DBG_STATUS_AUTH_METHOD_REJECT,
+ AUTH_DBG_STATUS_AUTH_METHOD_NONE,
+ AUTH_DBG_STATUS_CHAP_ALG_REJECT,
+ AUTH_DBG_STATUS_CHAP_CHALLENGE_REFLECTED,
+ AUTH_DBG_STATUS_PASSWD_IDENTICAL,
+
+ AUTH_DBG_STATUS_LOCAL_PASSWD_NOT_SET,
+
+ AUTH_DBG_STATUS_CHAP_IDENTIFIER_BAD,
+ AUTH_DBG_STATUS_CHALLENGE_BAD,
+ AUTH_DBG_STATUS_CHAP_RSP_BAD,
+ AUTH_DBG_STATUS_UNEXPECTED_KEY_PRESENT,
+ AUTH_DBG_STATUS_T_BIT_SET_ILLEGAL,
+ AUTH_DBG_STATUS_T_BIT_SET_PREMATURE,
+
+ AUTH_DBG_STATUS_RECV_MSG_COUNT_LIMIT,
+ AUTH_DBG_STATUS_RECV_DUP_SET_KEY_VALUE,
+ AUTH_DBG_STATUS_RECV_STR_TOO_LONG,
+ AUTH_DBG_STATUS_RECV_TOO_MUCH_DATA,
+ AUTH_DBG_STATUS_MAX_COUNT
+};
+
+enum auth_node_type {
+ TYPE_INITIATOR = 1,
+ TYPE_TARGET = 2
+};
+
+enum auth_phase {
+ AUTH_PHASE_CONFIGURE = 1,
+ AUTH_PHASE_NEGOTIATE,
+ AUTH_PHASE_AUTHENTICATE,
+ AUTH_PHASE_DONE,
+ AUTH_PHASE_ERROR
+};
+
+enum auth_local_state {
+ AUTH_LOCAL_STATE_SEND_ALG = 1,
+ AUTH_LOCAL_STATE_RECV_ALG,
+ AUTH_LOCAL_STATE_RECV_CHALLENGE,
+ AUTH_LOCAL_STATE_DONE,
+ AUTH_LOCAL_STATE_ERROR
+};
+
+enum auth_rmt_state {
+ AUTH_RMT_STATE_SEND_ALG = 1,
+ AUTH_RMT_STATE_SEND_CHALLENGE,
+ AUTH_RMT_STATE_RECV_RSP,
+ AUTH_RMT_STATE_DONE,
+ AUTH_RMT_STATE_ERROR
+};
+
+struct auth_key {
+ unsigned int present:1;
+ unsigned int processed:1;
+ unsigned int value_set:1;
+ char *string;
+};
+
+struct auth_large_binary_key {
+ unsigned int length;
+ unsigned char *large_binary;
+};
+
+struct auth_key_block {
+ unsigned int transit_bit:1;
+ unsigned int dup_set:1;
+ unsigned int str_too_long:1;
+ unsigned int too_much_data:1;
+ unsigned int blk_length:16;
+ char *str_block;
+ struct auth_key key[AUTH_KEY_TYPE_MAX_COUNT];
+};
+
+struct auth_str_block {
+ char str_block[AUTH_STR_BLOCK_MAX_LEN];
+};
+
+struct auth_large_binary {
+ unsigned char large_binary[AUTH_LARGE_BINARY_MAX_LEN];
+};
+
+struct iscsi_acl {
+ unsigned long signature;
+
+ enum auth_node_type node_type;
+ unsigned int auth_method_count;
+ int auth_method_list[AUTH_METHOD_MAX_COUNT];
+ enum auth_neg_role auth_method_neg_role;
+ unsigned int chap_alg_count;
+ int chap_alg_list[AUTH_CHAP_ALG_MAX_COUNT];
+ int auth_rmt;
+ char username[AUTH_STR_MAX_LEN];
+ int passwd_present;
+ unsigned int passwd_length;
+ unsigned char passwd_data[AUTH_STR_MAX_LEN];
+ unsigned int chap_challenge_len;
+ int ip_sec;
+
+ unsigned int auth_method_valid_count;
+ int auth_method_valid_list[AUTH_METHOD_MAX_COUNT];
+ int auth_method_valid_neg_role;
+
+ int recv_in_progress_flag;
+ int recv_end_count;
+ /*
+ * session for callbacks
+ */
+ struct iscsi_session *session_handle;
+ enum auth_phase phase;
+ enum auth_local_state local_state;
+ enum auth_rmt_state rmt_state;
+ enum auth_status rmt_auth_status;
+ enum auth_dbg_status dbg_status;
+ int negotiated_auth_method;
+ int negotiated_chap_alg;
+ int auth_rsp_flag;
+ int auth_server_error_flag;
+ int transit_bit_sent_flag;
+
+ unsigned int send_chap_identifier;
+ struct auth_large_binary_key send_chap_challenge;
+ char chap_username[AUTH_STR_MAX_LEN];
+
+ int recv_chap_challenge_status;
+ struct auth_large_binary_key recv_chap_challenge;
+
+ char scratch_key_value[AUTH_STR_MAX_LEN];
+
+ struct auth_key_block recv_key_block;
+ struct auth_key_block send_key_block;
+};
+
+extern int acl_init(int node_type, struct iscsi_session *session);
+extern int acl_finish(struct iscsi_acl *client);
+
+extern int acl_recv_begin(struct iscsi_acl *client);
+extern int acl_recv_end(struct iscsi_acl *client);
+extern const char *acl_get_key_name(int key_type);
+extern int acl_get_next_key_type(int *key_type);
+extern int acl_recv_key_value(struct iscsi_acl *client, int key_type,
+ const char *user_key_val);
+extern int acl_send_key_val(struct iscsi_acl *client, int key_type,
+ int *key_present, char *user_key_val,
+ unsigned int max_length);
+extern int acl_recv_transit_bit(struct iscsi_acl *client, int value);
+extern int acl_send_transit_bit(struct iscsi_acl *client, int *value);
+extern int acl_set_user_name(struct iscsi_acl *client, const char *username);
+extern int acl_set_passwd(struct iscsi_acl *client,
+ const unsigned char *pw_data, unsigned int pw_len);
+extern int acl_set_auth_rmt(struct iscsi_acl *client, int auth_rmt);
+extern int acl_set_ip_sec(struct iscsi_acl *client, int ip_sec);
+extern int acl_get_dbg_status(struct iscsi_acl *client, int *value);
+extern const char *acl_dbg_status_to_text(int dbg_status);
+extern enum auth_dbg_status acl_chap_compute_rsp(struct iscsi_acl *client,
+ int rmt_auth,
+ unsigned int id,
+ unsigned char *challenge_data,
+ unsigned int challenge_len,
+ unsigned char *response_data);
+extern int acl_chap_auth_request(struct iscsi_acl *client, char *username,
+ unsigned int id,
+ unsigned char *challenge_data,
+ unsigned int challenge_length,
+ unsigned char *response_data,
+ unsigned int rsp_length);
+extern int acl_data(unsigned char *out_data, unsigned int *out_length,
+ unsigned char *in_data, unsigned int in_length);
+#endif /* #ifndef ISCSIAUTHCLIENT_H */
reply other threads:[~2005-01-10 23:02 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=41E3099A.9020108@cs.wisc.edu \
--to=michaelc@cs.wisc.edu \
--cc=linux-scsi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox