|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI Authorization Library
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* maintained by open-iscsi@@googlegroups.com
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Originally based on:
|
|
Packit |
eace71 |
* Copyright (C) 2001 Cisco Systems, Inc.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published
|
|
Packit |
eace71 |
* by the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
eace71 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eace71 |
* General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This file implements the iSCSI CHAP authentication method based on
|
|
Packit |
eace71 |
* RFC 3720. The code in this file is meant to be common for both kernel and
|
|
Packit |
eace71 |
* user level and makes use of only limited library functions, presently only
|
|
Packit |
eace71 |
* string.h. Routines specific to kernel, user level are implemented in
|
|
Packit |
eace71 |
* separate files under the appropriate directories.
|
|
Packit |
eace71 |
* This code in this files assumes a single thread of execution
|
|
Packit |
eace71 |
* for each iscsi_acl structure, and does no locking.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <fcntl.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "sysdeps.h"
|
|
Packit |
eace71 |
#include "auth.h"
|
|
Packit |
eace71 |
#include "initiator.h"
|
|
Packit |
eace71 |
#include "log.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static const char acl_hexstring[] = "0123456789abcdefABCDEF";
|
|
Packit |
eace71 |
static const char acl_base64_string[] =
|
|
Packit |
eace71 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
Packit |
eace71 |
static const char acl_authmethod_set_chap_alg_list[] = "CHAP";
|
|
Packit |
eace71 |
static const char acl_reject_option_name[] = "Reject";
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include <openssl/evp.h>
|
|
Packit |
eace71 |
static int auth_hash_init(EVP_MD_CTX **context, int chap_alg);
|
|
Packit |
eace71 |
static void auth_hash_update(EVP_MD_CTX *context, unsigned char *md, unsigned int);
|
|
Packit |
eace71 |
static unsigned int auth_hash_final(unsigned char *, EVP_MD_CTX *context);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void get_random_bytes(unsigned char *data, unsigned int length);
|
|
Packit |
eace71 |
size_t strlcpy(char *, const char *, size_t);
|
|
Packit |
eace71 |
size_t strlcat(char *, const char *, size_t);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
enum auth_dbg_status
|
|
Packit |
eace71 |
acl_chap_compute_rsp(struct iscsi_acl *client, int rmt_auth, unsigned int id,
|
|
Packit |
eace71 |
unsigned char *challenge_data,
|
|
Packit |
eace71 |
unsigned int challenge_length,
|
|
Packit |
eace71 |
unsigned char *response_data)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned char id_data[1];
|
|
Packit |
eace71 |
EVP_MD_CTX *context = NULL;
|
|
Packit |
eace71 |
unsigned char out_data[AUTH_STR_MAX_LEN];
|
|
Packit |
eace71 |
unsigned int out_length = AUTH_STR_MAX_LEN;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!client->passwd_present)
|
|
Packit |
eace71 |
return AUTH_DBG_STATUS_LOCAL_PASSWD_NOT_SET;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (auth_hash_init(&context, client->negotiated_chap_alg) != 0)
|
|
Packit |
eace71 |
return AUTH_DBG_STATUS_AUTH_FAIL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* id byte */
|
|
Packit |
eace71 |
id_data[0] = id;
|
|
Packit |
eace71 |
auth_hash_update(context, id_data, 1);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* decrypt password */
|
|
Packit |
eace71 |
if (acl_data(out_data, &out_length, client->passwd_data,
|
|
Packit |
eace71 |
client->passwd_length))
|
|
Packit |
eace71 |
return AUTH_DBG_STATUS_PASSWD_DECRYPT_FAILED;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!rmt_auth && !client->ip_sec && out_length < 12)
|
|
Packit |
eace71 |
return AUTH_DBG_STATUS_PASSWD_TOO_SHORT_WITH_NO_IPSEC;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* shared secret */
|
|
Packit |
eace71 |
auth_hash_update(context, out_data, out_length);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* clear decrypted password */
|
|
Packit |
eace71 |
memset(out_data, 0, AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* challenge value */
|
|
Packit |
eace71 |
auth_hash_update(context, challenge_data, challenge_length);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
auth_hash_final(response_data, context);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_DBG_STATUS_NOT_SET; /* no error */
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Authenticate a target's CHAP response.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id,
|
|
Packit |
eace71 |
unsigned char *challenge_data,
|
|
Packit |
eace71 |
unsigned int challenge_length,
|
|
Packit |
eace71 |
unsigned char *response_data,
|
|
Packit |
eace71 |
unsigned int rsp_length)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
iscsi_session_t *session = client->session_handle;
|
|
Packit |
eace71 |
EVP_MD_CTX *context = NULL;
|
|
Packit |
eace71 |
unsigned char verify_data[client->chap_challenge_len];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* the expected credentials are in the session */
|
|
Packit |
eace71 |
if (session->username_in == NULL) {
|
|
Packit |
eace71 |
log_error("failing authentication, no incoming username "
|
|
Packit |
eace71 |
"configured to authenticate target %s",
|
|
Packit |
eace71 |
session->target_name);
|
|
Packit |
eace71 |
return AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (strcmp(username, session->username_in) != 0) {
|
|
Packit |
eace71 |
log_error("failing authentication, received incorrect "
|
|
Packit |
eace71 |
"username from target %s", session->target_name);
|
|
Packit |
eace71 |
return AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((session->password_in_length < 1) ||
|
|
Packit |
eace71 |
(session->password_in == NULL) ||
|
|
Packit |
eace71 |
(session->password_in[0] == '\0')) {
|
|
Packit |
eace71 |
log_error("failing authentication, no incoming password "
|
|
Packit |
eace71 |
"configured to authenticate target %s",
|
|
Packit |
eace71 |
session->target_name);
|
|
Packit |
eace71 |
return AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* challenge length is I->T, and shouldn't need to be checked */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rsp_length != sizeof(verify_data)) {
|
|
Packit |
eace71 |
log_error("failing authentication, received incorrect "
|
|
Packit |
eace71 |
"CHAP response length %u from target %s",
|
|
Packit |
eace71 |
rsp_length, session->target_name);
|
|
Packit |
eace71 |
return AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (auth_hash_init(&context, client->negotiated_chap_alg) != 0)
|
|
Packit |
eace71 |
return AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* id byte */
|
|
Packit |
eace71 |
verify_data[0] = id;
|
|
Packit |
eace71 |
auth_hash_update(context, verify_data, 1);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* shared secret */
|
|
Packit |
eace71 |
auth_hash_update(context, (unsigned char *)session->password_in,
|
|
Packit |
eace71 |
session->password_in_length);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* challenge value */
|
|
Packit |
eace71 |
auth_hash_update(context, (unsigned char *)challenge_data,
|
|
Packit |
eace71 |
challenge_length);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
auth_hash_final(verify_data, context);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (memcmp(response_data, verify_data, sizeof(verify_data)) == 0) {
|
|
Packit |
eace71 |
log_debug(1, "initiator authenticated target %s",
|
|
Packit |
eace71 |
session->target_name);
|
|
Packit |
eace71 |
return AUTH_STATUS_PASS;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_error("failing authentication, received incorrect CHAP "
|
|
Packit |
eace71 |
"response from target %s", session->target_name);
|
|
Packit |
eace71 |
return AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int auth_hash_init(EVP_MD_CTX **context, int chap_alg) {
|
|
Packit |
eace71 |
const EVP_MD *digest = NULL;
|
|
Packit |
eace71 |
*context = EVP_MD_CTX_new();
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (chap_alg) {
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_MD5:
|
|
Packit |
eace71 |
digest = EVP_md5();
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_SHA1:
|
|
Packit |
eace71 |
digest = EVP_sha1();
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_SHA256:
|
|
Packit |
eace71 |
digest = EVP_sha256();
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_SHA3_256:
|
|
Packit |
eace71 |
digest = EVP_sha3_256();
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (*context == NULL)
|
|
Packit |
eace71 |
goto fail_context;
|
|
Packit |
eace71 |
if (digest == NULL)
|
|
Packit |
eace71 |
goto fail_digest;
|
|
Packit |
eace71 |
rc = EVP_DigestInit_ex(*context, digest, NULL);
|
|
Packit |
eace71 |
if (!rc)
|
|
Packit |
eace71 |
goto fail_init;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fail_init:
|
|
Packit |
eace71 |
fail_digest:
|
|
Packit |
eace71 |
EVP_MD_CTX_free(*context);
|
|
Packit |
eace71 |
*context = NULL;
|
|
Packit |
eace71 |
fail_context:
|
|
Packit |
eace71 |
return -1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void auth_hash_update(EVP_MD_CTX *context, unsigned char *data, unsigned int length) {
|
|
Packit |
eace71 |
EVP_DigestUpdate(context, data, length);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static unsigned int auth_hash_final(unsigned char *hash, EVP_MD_CTX *context) {
|
|
Packit |
eace71 |
unsigned int md_len;
|
|
Packit |
eace71 |
EVP_DigestFinal_ex(context, hash, &md_len);
|
|
Packit |
eace71 |
EVP_MD_CTX_free(context);
|
|
Packit |
eace71 |
context = NULL;
|
|
Packit |
eace71 |
return md_len;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void
|
|
Packit |
eace71 |
get_random_bytes(unsigned char *data, unsigned int length)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
long r;
|
|
Packit |
eace71 |
unsigned n;
|
|
Packit |
eace71 |
int fd, r_size = sizeof(r);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fd = open("/dev/urandom", O_RDONLY);
|
|
Packit |
eace71 |
while (length > 0) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (fd == -1 || read(fd, &r, r_size) != r_size)
|
|
Packit |
eace71 |
r = rand();
|
|
Packit |
eace71 |
r = r ^ (r >> 8);
|
|
Packit |
eace71 |
r = r ^ (r >> 4);
|
|
Packit |
eace71 |
n = r & 0x7;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (fd == -1 || read(fd, &r, r_size) != r_size)
|
|
Packit |
eace71 |
r = rand();
|
|
Packit |
eace71 |
r = r ^ (r >> 8);
|
|
Packit |
eace71 |
r = r ^ (r >> 5);
|
|
Packit |
eace71 |
n = (n << 3) | (r & 0x7);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (fd == -1 || read(fd, &r, r_size) != r_size)
|
|
Packit |
eace71 |
r = rand();
|
|
Packit |
eace71 |
r = r ^ (r >> 8);
|
|
Packit |
eace71 |
r = r ^ (r >> 5);
|
|
Packit |
eace71 |
n = (n << 2) | (r & 0x3);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*data++ = n;
|
|
Packit |
eace71 |
length--;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (fd)
|
|
Packit |
eace71 |
close(fd);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static const char acl_none_option_name[] = "None";
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_text_to_number(const char *text, unsigned long *num)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
char *end;
|
|
Packit |
eace71 |
unsigned long number;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X'))
|
|
Packit |
eace71 |
number = strtoul(text + 2, &end, 16);
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
number = strtoul(text, &end, 10);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (*text != '\0' && *end == '\0') {
|
|
Packit |
eace71 |
*num = number;
|
|
Packit |
eace71 |
return 0; /* No error */
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
return 1; /* Error */
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_chk_string(const char *s, unsigned int max_len, unsigned int *out_len)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int len;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!s)
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (len = 0; len < max_len; len++)
|
|
Packit |
eace71 |
if (*s++ == '\0') {
|
|
Packit |
eace71 |
if (out_len)
|
|
Packit |
eace71 |
*out_len = len;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_str_index(const char *s, int c)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
char *str = strchr(s, c);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (str)
|
|
Packit |
eace71 |
return (str - s);
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
return -1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_chk_auth_mthd_optn(int val)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (val == AUTH_OPTION_NONE || val == AUTH_METHOD_CHAP)
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static const char *
|
|
Packit |
eace71 |
acl_authmethod_optn_to_text(int value)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
const char *s;
|
|
Packit |
eace71 |
switch (value) {
|
|
Packit |
eace71 |
case AUTH_OPTION_REJECT:
|
|
Packit |
eace71 |
s = acl_reject_option_name;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_OPTION_NONE:
|
|
Packit |
eace71 |
s = acl_none_option_name;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_METHOD_CHAP:
|
|
Packit |
eace71 |
s = acl_authmethod_set_chap_alg_list;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
s = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return s;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_chk_chap_alg_optn(int chap_algorithm)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (chap_algorithm == AUTH_OPTION_NONE ||
|
|
Packit |
eace71 |
chap_algorithm == AUTH_CHAP_ALG_SHA3_256 ||
|
|
Packit |
eace71 |
chap_algorithm == AUTH_CHAP_ALG_SHA256 ||
|
|
Packit |
eace71 |
chap_algorithm == AUTH_CHAP_ALG_SHA1 ||
|
|
Packit |
eace71 |
chap_algorithm == AUTH_CHAP_ALG_MD5)
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_data_to_text(unsigned char *data, unsigned int data_length, char *text,
|
|
Packit |
eace71 |
unsigned int text_length)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned long n;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!text || text_length == 0)
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!data || data_length == 0) {
|
|
Packit |
eace71 |
*text = '\0';
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (text_length < 3) {
|
|
Packit |
eace71 |
*text = '\0';
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*text++ = '0';
|
|
Packit |
eace71 |
*text++ = 'x';
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
text_length -= 2;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (data_length > 0) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (text_length < 3) {
|
|
Packit |
eace71 |
*text = '\0';
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
n = *data++;
|
|
Packit |
eace71 |
data_length--;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*text++ = acl_hexstring[(n >> 4) & 0xf];
|
|
Packit |
eace71 |
*text++ = acl_hexstring[n & 0xf];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
text_length -= 2;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*text = '\0';
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_hex_to_data(const char *text, unsigned int text_length, unsigned char *data,
|
|
Packit |
eace71 |
unsigned int *data_lenp)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i;
|
|
Packit |
eace71 |
unsigned int n1;
|
|
Packit |
eace71 |
unsigned int n2;
|
|
Packit |
eace71 |
unsigned int data_length = *data_lenp;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((text_length % 2) == 1) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
i = acl_str_index(acl_hexstring, *text++);
|
|
Packit |
eace71 |
if (i < 0)
|
|
Packit |
eace71 |
return 1; /* error, bad character */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (i > 15)
|
|
Packit |
eace71 |
i -= 6;
|
|
Packit |
eace71 |
n2 = i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (data_length < 1)
|
|
Packit |
eace71 |
return 1; /* error, too much data */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*data++ = n2;
|
|
Packit |
eace71 |
data_length--;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (*text != '\0') {
|
|
Packit |
eace71 |
i = acl_str_index(acl_hexstring, *text++);
|
|
Packit |
eace71 |
if (i < 0)
|
|
Packit |
eace71 |
return 1; /* error, bad character */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (i > 15)
|
|
Packit |
eace71 |
i -= 6;
|
|
Packit |
eace71 |
n1 = i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (*text == '\0')
|
|
Packit |
eace71 |
return 1; /* error, odd string length */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
i = acl_str_index(acl_hexstring, *text++);
|
|
Packit |
eace71 |
if (i < 0)
|
|
Packit |
eace71 |
return 1; /* error, bad character */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (i > 15)
|
|
Packit |
eace71 |
i -= 6;
|
|
Packit |
eace71 |
n2 = i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (data_length < 1)
|
|
Packit |
eace71 |
return 1; /* error, too much data */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*data++ = (n1 << 4) | n2;
|
|
Packit |
eace71 |
data_length--;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (data_length >= *data_lenp)
|
|
Packit |
eace71 |
return 1; /* error, no data */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*data_lenp = *data_lenp - data_length;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0; /* no error */
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_base64_to_data(const char *text, unsigned char *data,
|
|
Packit |
eace71 |
unsigned int *data_lenp)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i;
|
|
Packit |
eace71 |
unsigned int n;
|
|
Packit |
eace71 |
unsigned int count;
|
|
Packit |
eace71 |
unsigned int data_length = *data_lenp;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
n = 0;
|
|
Packit |
eace71 |
count = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (*text != '\0' && *text != '=') {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
i = acl_str_index(acl_base64_string, *text++);
|
|
Packit |
eace71 |
if (i < 0)
|
|
Packit |
eace71 |
return 1; /* error, bad character */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
n = (n << 6 | (unsigned int)i);
|
|
Packit |
eace71 |
count++;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (count >= 4) {
|
|
Packit |
eace71 |
if (data_length < 3)
|
|
Packit |
eace71 |
return 1; /* error, too much data */
|
|
Packit |
eace71 |
*data++ = n >> 16;
|
|
Packit |
eace71 |
*data++ = n >> 8;
|
|
Packit |
eace71 |
*data++ = n;
|
|
Packit |
eace71 |
data_length -= 3;
|
|
Packit |
eace71 |
n = 0;
|
|
Packit |
eace71 |
count = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (*text != '\0')
|
|
Packit |
eace71 |
if (*text++ != '=')
|
|
Packit |
eace71 |
return 1; /* error, bad pad */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (count == 0) {
|
|
Packit |
eace71 |
/* do nothing */
|
|
Packit |
eace71 |
} else if (count == 2) {
|
|
Packit |
eace71 |
if (data_length < 1)
|
|
Packit |
eace71 |
return 1; /* error, too much data */
|
|
Packit |
eace71 |
n = n >> 4;
|
|
Packit |
eace71 |
*data++ = n;
|
|
Packit |
eace71 |
data_length--;
|
|
Packit |
eace71 |
} else if (count == 3) {
|
|
Packit |
eace71 |
if (data_length < 2)
|
|
Packit |
eace71 |
return 1; /* error, too much data */
|
|
Packit |
eace71 |
n = n >> 2;
|
|
Packit |
eace71 |
*data++ = n >> 8;
|
|
Packit |
eace71 |
*data++ = n;
|
|
Packit |
eace71 |
data_length -= 2;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
return 1; /* bad encoding */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (data_length >= *data_lenp)
|
|
Packit |
eace71 |
return 1; /* error, no data */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*data_lenp = *data_lenp - data_length;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0; /* no error */
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_text_to_data(const char *text, unsigned char *data,
|
|
Packit |
eace71 |
unsigned int *data_length)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int status;
|
|
Packit |
eace71 |
unsigned int text_length;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = acl_chk_string(text, 2 + 2 * AUTH_LARGE_BINARY_MAX_LEN + 1,
|
|
Packit |
eace71 |
&text_length);
|
|
Packit |
eace71 |
if (status)
|
|
Packit |
eace71 |
return status;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) {
|
|
Packit |
eace71 |
/* skip prefix */
|
|
Packit |
eace71 |
text += 2;
|
|
Packit |
eace71 |
text_length -= 2;
|
|
Packit |
eace71 |
status = acl_hex_to_data(text, text_length, data, data_length);
|
|
Packit |
eace71 |
} else if (text[0] == '0' && (text[1] == 'b' || text[1] == 'B')) {
|
|
Packit |
eace71 |
/* skip prefix */
|
|
Packit |
eace71 |
text += 2;
|
|
Packit |
eace71 |
text_length -= 2;
|
|
Packit |
eace71 |
status = acl_base64_to_data(text, data, data_length);
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
status = 1; /* prefix not recognized. */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return status;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_init_key_blk(struct auth_key_block *key_blk)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
char *str_block = key_blk->str_block;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(key_blk, 0, sizeof(*key_blk));
|
|
Packit |
eace71 |
key_blk->str_block = str_block;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_set_key_value(struct auth_key_block *key_blk, int key_type,
|
|
Packit |
eace71 |
const char *key_val)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int length;
|
|
Packit |
eace71 |
char *string;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (key_blk->key[key_type].value_set) {
|
|
Packit |
eace71 |
key_blk->dup_set = 1;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
key_blk->key[key_type].value_set = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!key_val)
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (acl_chk_string(key_val, AUTH_STR_MAX_LEN, &length)) {
|
|
Packit |
eace71 |
key_blk->str_too_long = 1;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
length += 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((key_blk->blk_length + length) > AUTH_STR_BLOCK_MAX_LEN) {
|
|
Packit |
eace71 |
key_blk->too_much_data = 1;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
string = &key_blk->str_block[key_blk->blk_length];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strlcpy(string, key_val, length) >= length) {
|
|
Packit |
eace71 |
key_blk->too_much_data = 1;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
key_blk->blk_length += length;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
key_blk->key[key_type].string = string;
|
|
Packit |
eace71 |
key_blk->key[key_type].present = 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static const char *
|
|
Packit |
eace71 |
acl_get_key_val(struct auth_key_block *key_blk, int key_type)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
key_blk->key[key_type].processed = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!key_blk->key[key_type].present)
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return key_blk->key[key_type].string;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_chk_key(struct iscsi_acl *client, int key_type, int *negotiated_option,
|
|
Packit |
eace71 |
unsigned int option_count, int *option_list,
|
|
Packit |
eace71 |
const char *(*value_to_text) (int))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
const char *key_val;
|
|
Packit |
eace71 |
int length;
|
|
Packit |
eace71 |
unsigned int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
key_val = acl_get_key_val(&client->recv_key_block, key_type);
|
|
Packit |
eace71 |
if (!key_val) {
|
|
Packit |
eace71 |
*negotiated_option = AUTH_OPTION_NOT_PRESENT;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (*key_val != '\0') {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
length = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (*key_val != '\0' && *key_val != ',')
|
|
Packit |
eace71 |
client->scratch_key_value[length++] = *key_val++;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (*key_val == ',')
|
|
Packit |
eace71 |
key_val++;
|
|
Packit |
eace71 |
client->scratch_key_value[length++] = '\0';
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < option_count; i++) {
|
|
Packit |
eace71 |
const char *s = (*value_to_text)(option_list[i]);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!s)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strcmp(client->scratch_key_value, s) == 0) {
|
|
Packit |
eace71 |
*negotiated_option = option_list[i];
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*negotiated_option = AUTH_OPTION_REJECT;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_set_key(struct iscsi_acl *client, int key_type, unsigned int option_count,
|
|
Packit |
eace71 |
int *option_list, const char *(*value_to_text)(int))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (option_count == 0) {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* No valid options to send, but we always want to
|
|
Packit |
eace71 |
* send something.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block, key_type,
|
|
Packit |
eace71 |
acl_none_option_name);
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (option_count == 1 && option_list[0] == AUTH_OPTION_NOT_PRESENT) {
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block, key_type, NULL);
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < option_count; i++) {
|
|
Packit |
eace71 |
const char *s = (*value_to_text)(option_list[i]);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!s)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (i == 0)
|
|
Packit |
eace71 |
strlcpy(client->scratch_key_value, s,
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
strlcat(client->scratch_key_value, ",",
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
strlcat(client->scratch_key_value, s,
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block, key_type,
|
|
Packit |
eace71 |
client->scratch_key_value);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_chk_auth_method_key(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
acl_chk_key(client, AUTH_KEY_TYPE_AUTH_METHOD,
|
|
Packit |
eace71 |
&client->negotiated_auth_method,
|
|
Packit |
eace71 |
client->auth_method_valid_count,
|
|
Packit |
eace71 |
client->auth_method_valid_list,
|
|
Packit |
eace71 |
acl_authmethod_optn_to_text);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_set_auth_method_key(struct iscsi_acl *client,
|
|
Packit |
eace71 |
unsigned int auth_method_count, int *auth_method_list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
acl_set_key(client, AUTH_KEY_TYPE_AUTH_METHOD, auth_method_count,
|
|
Packit |
eace71 |
auth_method_list, acl_authmethod_optn_to_text);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_chk_chap_alg_key(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
const char *key_val;
|
|
Packit |
eace71 |
int length;
|
|
Packit |
eace71 |
unsigned long number;
|
|
Packit |
eace71 |
unsigned int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
key_val = acl_get_key_val(&client->recv_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_ALG);
|
|
Packit |
eace71 |
if (!key_val) {
|
|
Packit |
eace71 |
client->negotiated_chap_alg = AUTH_OPTION_NOT_PRESENT;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (*key_val != '\0') {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
length = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while (*key_val != '\0' && *key_val != ',')
|
|
Packit |
eace71 |
client->scratch_key_value[length++] = *key_val++;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (*key_val == ',')
|
|
Packit |
eace71 |
key_val++;
|
|
Packit |
eace71 |
client->scratch_key_value[length++] = '\0';
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (acl_text_to_number(client->scratch_key_value, &number))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < client->chap_alg_count; i++)
|
|
Packit |
eace71 |
if (number == (unsigned long)client->chap_alg_list[i])
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
client->negotiated_chap_alg = number;
|
|
Packit |
eace71 |
switch (number) {
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_MD5:
|
|
Packit |
eace71 |
client->chap_challenge_len = AUTH_CHAP_MD5_RSP_LEN;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_SHA1:
|
|
Packit |
eace71 |
client->chap_challenge_len = AUTH_CHAP_SHA1_RSP_LEN;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_SHA256:
|
|
Packit |
eace71 |
client->chap_challenge_len = AUTH_CHAP_SHA256_RSP_LEN;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_CHAP_ALG_SHA3_256:
|
|
Packit |
eace71 |
client->chap_challenge_len = AUTH_CHAP_SHA3_256_RSP_LEN;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->negotiated_chap_alg = AUTH_OPTION_REJECT;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_set_chap_alg_key(struct iscsi_acl *client, unsigned int chap_alg_count,
|
|
Packit |
eace71 |
int *chap_alg_list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (chap_alg_count == 0) {
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_ALG, NULL);
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (chap_alg_count == 1 &&
|
|
Packit |
eace71 |
chap_alg_list[0] == AUTH_OPTION_NOT_PRESENT) {
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_ALG, NULL);
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (chap_alg_count == 1 && chap_alg_list[0] == AUTH_OPTION_REJECT) {
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_ALG,
|
|
Packit |
eace71 |
acl_reject_option_name);
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < chap_alg_count; i++) {
|
|
Packit |
eace71 |
char s[20];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
snprintf(s, sizeof(s), "%lu",(unsigned long)chap_alg_list[i]);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (i == 0)
|
|
Packit |
eace71 |
strlcpy(client->scratch_key_value, s,
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
strlcat(client->scratch_key_value, ",",
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
strlcat(client->scratch_key_value, s,
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block, AUTH_KEY_TYPE_CHAP_ALG,
|
|
Packit |
eace71 |
client->scratch_key_value);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_next_phase(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
switch (client->phase) {
|
|
Packit |
eace71 |
case AUTH_PHASE_CONFIGURE:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_NEGOTIATE;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_PHASE_NEGOTIATE:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_AUTHENTICATE;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->negotiated_auth_method == AUTH_OPTION_REJECT ||
|
|
Packit |
eace71 |
client->negotiated_auth_method == AUTH_OPTION_NOT_PRESENT ||
|
|
Packit |
eace71 |
client->negotiated_auth_method == AUTH_OPTION_NONE) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_DONE;
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_DONE;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->auth_rmt) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_PASS;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (client->negotiated_auth_method) {
|
|
Packit |
eace71 |
case AUTH_OPTION_REJECT:
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_AUTH_METHOD_REJECT;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_OPTION_NOT_PRESENT:
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_AUTH_METHOD_NOT_PRESENT;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_OPTION_NONE:
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_AUTH_METHOD_NONE;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
} else if (client->negotiated_auth_method == AUTH_METHOD_CHAP) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_SEND_ALG;
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_SEND_ALG;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_DONE;
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_DONE;
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_AUTH_METHOD_BAD;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_PHASE_AUTHENTICATE:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_PHASE_DONE:
|
|
Packit |
eace71 |
case AUTH_PHASE_ERROR:
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_local_auth(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int chap_identifier;
|
|
Packit |
eace71 |
unsigned char response_data[AUTH_CHAP_RSP_MAX];
|
|
Packit |
eace71 |
unsigned long number;
|
|
Packit |
eace71 |
int status;
|
|
Packit |
eace71 |
enum auth_dbg_status dbg_status;
|
|
Packit |
eace71 |
const char *chap_identifier_key_val;
|
|
Packit |
eace71 |
const char *chap_challenge_key_val;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (client->local_state) {
|
|
Packit |
eace71 |
case AUTH_LOCAL_STATE_SEND_ALG:
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR) {
|
|
Packit |
eace71 |
acl_set_chap_alg_key(client, client->chap_alg_count,
|
|
Packit |
eace71 |
client->chap_alg_list);
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_RECV_ALG;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
/* Fall through */
|
|
Packit |
eace71 |
case AUTH_LOCAL_STATE_RECV_ALG:
|
|
Packit |
eace71 |
acl_chk_chap_alg_key(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_TARGET)
|
|
Packit |
eace71 |
acl_set_chap_alg_key(client, 1,
|
|
Packit |
eace71 |
&client->negotiated_chap_alg);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Make sure only supported CHAP algorithm is used. */
|
|
Packit |
eace71 |
if (client->negotiated_chap_alg == AUTH_OPTION_NOT_PRESENT) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_EXPECTED;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
} else if (client->negotiated_chap_alg == AUTH_OPTION_REJECT) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_REJECT;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
} else if ((client->negotiated_chap_alg != AUTH_CHAP_ALG_SHA3_256) &&
|
|
Packit |
eace71 |
(client->negotiated_chap_alg != AUTH_CHAP_ALG_SHA256) &&
|
|
Packit |
eace71 |
(client->negotiated_chap_alg != AUTH_CHAP_ALG_SHA1) &&
|
|
Packit |
eace71 |
(client->negotiated_chap_alg != AUTH_CHAP_ALG_MD5)) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHAP_ALG_BAD;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (client->node_type == TYPE_TARGET) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_RECV_CHALLENGE;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
/* Fall through */
|
|
Packit |
eace71 |
case AUTH_LOCAL_STATE_RECV_CHALLENGE:
|
|
Packit |
eace71 |
chap_identifier_key_val = acl_get_key_val(&client->recv_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_IDENTIFIER);
|
|
Packit |
eace71 |
chap_challenge_key_val = acl_get_key_val(&client->recv_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_CHALLENGE);
|
|
Packit |
eace71 |
if (client->node_type == TYPE_TARGET) {
|
|
Packit |
eace71 |
if (!chap_identifier_key_val &&
|
|
Packit |
eace71 |
!chap_challenge_key_val) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_DONE;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!chap_identifier_key_val) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_CHAP_IDENTIFIER_EXPECTED;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!chap_challenge_key_val) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_CHAP_CHALLENGE_EXPECTED;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = acl_text_to_number(chap_identifier_key_val, &number);
|
|
Packit |
eace71 |
if (status || (255 < number)) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHAP_IDENTIFIER_BAD;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
chap_identifier = number;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->recv_chap_challenge_status) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHALLENGE_BAD;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_TARGET &&
|
|
Packit |
eace71 |
client->recv_chap_challenge.length ==
|
|
Packit |
eace71 |
client->send_chap_challenge.length &&
|
|
Packit |
eace71 |
memcmp(client->recv_chap_challenge.large_binary,
|
|
Packit |
eace71 |
client->send_chap_challenge.large_binary,
|
|
Packit |
eace71 |
client->send_chap_challenge.length) == 0) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_CHAP_CHALLENGE_REFLECTED;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
dbg_status = acl_chap_compute_rsp(client, 0,
|
|
Packit |
eace71 |
chap_identifier,
|
|
Packit |
eace71 |
client->recv_chap_challenge.large_binary,
|
|
Packit |
eace71 |
client->recv_chap_challenge.length,
|
|
Packit |
eace71 |
response_data);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (dbg_status != AUTH_DBG_STATUS_NOT_SET) {
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = dbg_status;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_data_to_text(response_data, client->chap_challenge_len,
|
|
Packit |
eace71 |
client->scratch_key_value,
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_RSP,
|
|
Packit |
eace71 |
client->scratch_key_value);
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_USERNAME,
|
|
Packit |
eace71 |
client->username);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->local_state = AUTH_LOCAL_STATE_DONE;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_LOCAL_STATE_DONE:
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_LOCAL_STATE_ERROR:
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_rmt_auth(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned char id_data[1];
|
|
Packit |
eace71 |
unsigned char response_data[AUTH_STR_MAX_LEN];
|
|
Packit |
eace71 |
unsigned int rsp_len = AUTH_STR_MAX_LEN;
|
|
Packit |
eace71 |
unsigned char my_rsp_data[AUTH_CHAP_RSP_MAX];
|
|
Packit |
eace71 |
int status;
|
|
Packit |
eace71 |
enum auth_dbg_status dbg_status;
|
|
Packit |
eace71 |
const char *chap_rsp_key_val;
|
|
Packit |
eace71 |
const char *chap_username_key_val;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (client->rmt_state) {
|
|
Packit |
eace71 |
case AUTH_RMT_STATE_SEND_ALG:
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR) {
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_SEND_CHALLENGE;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
/* Fall through */
|
|
Packit |
eace71 |
case AUTH_RMT_STATE_SEND_CHALLENGE:
|
|
Packit |
eace71 |
if (!client->auth_rmt) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_PASS;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_AUTH_RMT_FALSE;
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_DONE;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
get_random_bytes(id_data, 1);
|
|
Packit |
eace71 |
client->send_chap_identifier = id_data[0];
|
|
Packit |
eace71 |
snprintf(client->scratch_key_value, AUTH_STR_MAX_LEN, "%lu",
|
|
Packit |
eace71 |
(unsigned long)client->send_chap_identifier);
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_IDENTIFIER,
|
|
Packit |
eace71 |
client->scratch_key_value);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->send_chap_challenge.length = client->chap_challenge_len;
|
|
Packit |
eace71 |
get_random_bytes(client->send_chap_challenge.large_binary,
|
|
Packit |
eace71 |
client->send_chap_challenge.length);
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_CHALLENGE, "");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_RECV_RSP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_RMT_STATE_RECV_RSP:
|
|
Packit |
eace71 |
chap_rsp_key_val = acl_get_key_val(&client->recv_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_RSP);
|
|
Packit |
eace71 |
chap_username_key_val = acl_get_key_val(&client->recv_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_USERNAME);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!chap_rsp_key_val) {
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHAP_RSP_EXPECTED;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!chap_username_key_val) {
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHAP_USERNAME_EXPECTED;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = acl_text_to_data(chap_rsp_key_val, response_data,
|
|
Packit |
eace71 |
&rsp_len);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (status) {
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_CHAP_RSP_BAD;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rsp_len == client->chap_challenge_len) {
|
|
Packit |
eace71 |
dbg_status = acl_chap_compute_rsp(client, 1,
|
|
Packit |
eace71 |
client->send_chap_identifier,
|
|
Packit |
eace71 |
client->send_chap_challenge.large_binary,
|
|
Packit |
eace71 |
client->send_chap_challenge.length,
|
|
Packit |
eace71 |
my_rsp_data);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (dbg_status == AUTH_DBG_STATUS_NOT_SET &&
|
|
Packit |
eace71 |
memcmp(my_rsp_data, response_data,
|
|
Packit |
eace71 |
client->chap_challenge_len) == 0) {
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_ERROR;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_PASSWD_IDENTICAL;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(client->chap_username, chap_username_key_val,
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = acl_chap_auth_request(client, client->chap_username,
|
|
Packit |
eace71 |
client->send_chap_identifier,
|
|
Packit |
eace71 |
client->send_chap_challenge.
|
|
Packit |
eace71 |
large_binary,
|
|
Packit |
eace71 |
client->send_chap_challenge.
|
|
Packit |
eace71 |
length, response_data,
|
|
Packit |
eace71 |
rsp_len);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->rmt_auth_status = (enum auth_status) status;
|
|
Packit |
eace71 |
client->auth_rsp_flag = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->auth_server_error_flag) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_AUTH_SERVER_ERROR;
|
|
Packit |
eace71 |
} else if (client->rmt_auth_status == AUTH_STATUS_PASS)
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_AUTH_PASS;
|
|
Packit |
eace71 |
else if (client->rmt_auth_status == AUTH_STATUS_FAIL)
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_AUTH_FAIL;
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_AUTH_STATUS_BAD;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
client->rmt_state = AUTH_RMT_STATE_DONE;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Fall through */
|
|
Packit |
eace71 |
case AUTH_RMT_STATE_DONE:
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_RMT_STATE_ERROR:
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_hand_shake(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_DONE)
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Should only happen if authentication
|
|
Packit |
eace71 |
* protocol error occurred.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR)
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Target should only have set T bit on response if
|
|
Packit |
eace71 |
* initiator set it on previous message.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (client->recv_key_block.transit_bit &&
|
|
Packit |
eace71 |
!client->transit_bit_sent_flag) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_T_BIT_SET_ILLEGAL;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_NEGOTIATE) {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Should only happen if waiting for peer
|
|
Packit |
eace71 |
* to send AuthMethod key or set Transit Bit.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR)
|
|
Packit |
eace71 |
client->send_key_block.transit_bit = 1;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->rmt_state == AUTH_RMT_STATE_RECV_RSP ||
|
|
Packit |
eace71 |
client->rmt_state == AUTH_RMT_STATE_DONE) {
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR) {
|
|
Packit |
eace71 |
if (client->recv_key_block.transit_bit) {
|
|
Packit |
eace71 |
if (client->rmt_state !=
|
|
Packit |
eace71 |
AUTH_RMT_STATE_DONE)
|
|
Packit |
eace71 |
goto recv_transit_bit_err;
|
|
Packit |
eace71 |
acl_next_phase(client);
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
client->send_key_block.transit_bit = 1;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
if (client->rmt_state == AUTH_RMT_STATE_DONE &&
|
|
Packit |
eace71 |
client->rmt_auth_status != AUTH_STATUS_PASS)
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Authentication failed, don't do T bit
|
|
Packit |
eace71 |
* handshake.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
acl_next_phase(client);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Target can only set T bit on response if
|
|
Packit |
eace71 |
* initiator set it on current message.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (client->recv_key_block.transit_bit) {
|
|
Packit |
eace71 |
client->send_key_block.transit_bit = 1;
|
|
Packit |
eace71 |
acl_next_phase(client);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR)
|
|
Packit |
eace71 |
if (client->recv_key_block.transit_bit)
|
|
Packit |
eace71 |
goto recv_transit_bit_err;
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
recv_transit_bit_err:
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Target set T bit on response but
|
|
Packit |
eace71 |
* initiator was not done with authentication.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_T_BIT_SET_PREMATURE;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_rcv_end_status(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int auth_status;
|
|
Packit |
eace71 |
int key_type;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_ERROR)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_DONE) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Perform sanity check against configured parameters. */
|
|
Packit |
eace71 |
if (client->auth_rmt && !client->auth_rsp_flag &&
|
|
Packit |
eace71 |
client->rmt_auth_status == AUTH_STATUS_PASS) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_AUTHPASS_NOT_VALID;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
auth_status = client->rmt_auth_status;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
auth_status = AUTH_STATUS_CONTINUE;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (auth_status == AUTH_STATUS_CONTINUE ||
|
|
Packit |
eace71 |
auth_status == AUTH_STATUS_PASS) {
|
|
Packit |
eace71 |
if (client->send_key_block.dup_set) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_SEND_DUP_SET_KEY_VALUE;
|
|
Packit |
eace71 |
auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
} else if (client->send_key_block.str_too_long) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_SEND_STR_TOO_LONG;
|
|
Packit |
eace71 |
auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
} else if (client->send_key_block.too_much_data) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_SEND_TOO_MUCH_DATA;
|
|
Packit |
eace71 |
auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
/* Check that all incoming keys have been processed. */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (key_type = AUTH_KEY_TYPE_FIRST;
|
|
Packit |
eace71 |
key_type < AUTH_KEY_TYPE_MAX_COUNT; key_type++)
|
|
Packit |
eace71 |
if (client->recv_key_block.key[key_type].present &&
|
|
Packit |
eace71 |
!client->recv_key_block.key[key_type].
|
|
Packit |
eace71 |
processed)
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (key_type < AUTH_KEY_TYPE_MAX_COUNT) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_UNEXPECTED_KEY_PRESENT;
|
|
Packit |
eace71 |
auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (auth_status != AUTH_STATUS_PASS &&
|
|
Packit |
eace71 |
auth_status != AUTH_STATUS_CONTINUE) {
|
|
Packit |
eace71 |
int auth_method_key_present = 0;
|
|
Packit |
eace71 |
int chap_alg_key_present = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Suppress send keys on error,
|
|
Packit |
eace71 |
* except for AuthMethod and CHAP_A.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (client->node_type == TYPE_TARGET) {
|
|
Packit |
eace71 |
if (acl_get_key_val(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_AUTH_METHOD))
|
|
Packit |
eace71 |
auth_method_key_present = 1;
|
|
Packit |
eace71 |
else if (acl_get_key_val(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_ALG))
|
|
Packit |
eace71 |
chap_alg_key_present = 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_init_key_blk(&client->send_key_block);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_TARGET) {
|
|
Packit |
eace71 |
if (auth_method_key_present &&
|
|
Packit |
eace71 |
client->negotiated_auth_method ==
|
|
Packit |
eace71 |
AUTH_OPTION_REJECT)
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_AUTH_METHOD,
|
|
Packit |
eace71 |
acl_reject_option_name);
|
|
Packit |
eace71 |
else if (chap_alg_key_present &&
|
|
Packit |
eace71 |
client->negotiated_chap_alg ==
|
|
Packit |
eace71 |
AUTH_OPTION_REJECT)
|
|
Packit |
eace71 |
acl_set_key_value(&client->send_key_block,
|
|
Packit |
eace71 |
AUTH_KEY_TYPE_CHAP_ALG,
|
|
Packit |
eace71 |
acl_reject_option_name);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
client->recv_in_progress_flag = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return auth_status;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_recv_begin(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_ERROR)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_DONE) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->recv_in_progress_flag) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->recv_in_progress_flag = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_CONFIGURE)
|
|
Packit |
eace71 |
acl_next_phase(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->transit_bit_sent_flag = client->send_key_block.transit_bit;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_init_key_blk(&client->recv_key_block);
|
|
Packit |
eace71 |
acl_init_key_blk(&client->send_key_block);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_recv_end(struct iscsi_acl *client, iscsi_session_t *session_handle)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int next_phase_flag = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase == AUTH_PHASE_ERROR)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!client->recv_in_progress_flag) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->recv_end_count > AUTH_RECV_END_MAX_COUNT) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_RECV_MSG_COUNT_LIMIT;
|
|
Packit |
eace71 |
} else if (client->recv_key_block.dup_set) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_RECV_DUP_SET_KEY_VALUE;
|
|
Packit |
eace71 |
} else if (client->recv_key_block.str_too_long) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_RECV_STR_TOO_LONG;
|
|
Packit |
eace71 |
} else if (client->recv_key_block.too_much_data) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status = AUTH_DBG_STATUS_RECV_TOO_MUCH_DATA;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->recv_end_count++;
|
|
Packit |
eace71 |
client->session_handle = session_handle;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (client->phase) {
|
|
Packit |
eace71 |
case AUTH_PHASE_NEGOTIATE:
|
|
Packit |
eace71 |
acl_chk_auth_method_key(client);
|
|
Packit |
eace71 |
if (client->auth_method_valid_neg_role ==
|
|
Packit |
eace71 |
AUTH_NEG_ROLE_RESPONDER) {
|
|
Packit |
eace71 |
if (client->negotiated_auth_method ==
|
|
Packit |
eace71 |
AUTH_OPTION_NOT_PRESENT) {
|
|
Packit |
eace71 |
if (client->auth_rmt ||
|
|
Packit |
eace71 |
!client->recv_key_block.transit_bit) {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* No AuthMethod key from peer on
|
|
Packit |
eace71 |
* first message, try moving the
|
|
Packit |
eace71 |
* process along by sending the
|
|
Packit |
eace71 |
* AuthMethod key.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->auth_method_valid_neg_role =
|
|
Packit |
eace71 |
AUTH_NEG_ROLE_ORIGINATOR;
|
|
Packit |
eace71 |
acl_set_auth_method_key(client,
|
|
Packit |
eace71 |
client->auth_method_valid_count,
|
|
Packit |
eace71 |
client->auth_method_valid_list);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Special case if peer sent no AuthMethod key,
|
|
Packit |
eace71 |
* but did set Transit Bit, allowing this side
|
|
Packit |
eace71 |
* to do a null authentication, and compelete
|
|
Packit |
eace71 |
* the iSCSI security phase without either side
|
|
Packit |
eace71 |
* sending the AuthMethod key.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
/* Send response to AuthMethod key. */
|
|
Packit |
eace71 |
acl_set_auth_method_key(client, 1,
|
|
Packit |
eace71 |
&client->negotiated_auth_method);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR)
|
|
Packit |
eace71 |
acl_next_phase(client);
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
next_phase_flag = 1;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->negotiated_auth_method ==
|
|
Packit |
eace71 |
AUTH_OPTION_NOT_PRESENT) {
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
client->dbg_status =
|
|
Packit |
eace71 |
AUTH_DBG_STATUS_AUTH_METHOD_EXPECTED;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_next_phase(client);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_PHASE_AUTHENTICATE:
|
|
Packit |
eace71 |
case AUTH_PHASE_DONE:
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
switch (client->phase) {
|
|
Packit |
eace71 |
case AUTH_PHASE_NEGOTIATE:
|
|
Packit |
eace71 |
if (next_phase_flag)
|
|
Packit |
eace71 |
acl_next_phase(client);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_PHASE_AUTHENTICATE:
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Must call acl_local_auth()
|
|
Packit |
eace71 |
* before acl_rmt_auth()
|
|
Packit |
eace71 |
* to insure processing of the CHAP algorithm key,
|
|
Packit |
eace71 |
* and to avoid leaving an in progress request to the
|
|
Packit |
eace71 |
* authentication service.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
acl_local_auth(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->local_state != AUTH_LOCAL_STATE_ERROR)
|
|
Packit |
eace71 |
acl_rmt_auth(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->local_state == AUTH_LOCAL_STATE_ERROR ||
|
|
Packit |
eace71 |
client->rmt_state == AUTH_RMT_STATE_ERROR) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->rmt_auth_status = AUTH_STATUS_FAIL;
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_DONE;
|
|
Packit |
eace71 |
/* client->dbg_status should already be set. */
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
case AUTH_PHASE_DONE:
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
default:
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_hand_shake(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return acl_rcv_end_status(client);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
const char *
|
|
Packit |
eace71 |
acl_get_key_name(int key_type)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Note: The ordering of this table must match the order
|
|
Packit |
eace71 |
* defined by enum auth_key_type in iscsi-auth-client.h.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static char *const key_names[AUTH_KEY_TYPE_MAX_COUNT] = {
|
|
Packit |
eace71 |
"AuthMethod",
|
|
Packit |
eace71 |
"CHAP_A",
|
|
Packit |
eace71 |
"CHAP_N",
|
|
Packit |
eace71 |
"CHAP_R",
|
|
Packit |
eace71 |
"CHAP_I",
|
|
Packit |
eace71 |
"CHAP_C"
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST)
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return key_names[key_type];
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_get_next_key_type(int *key_type)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (*key_type >= AUTH_KEY_TYPE_LAST)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (*key_type < AUTH_KEY_TYPE_FIRST)
|
|
Packit |
eace71 |
*key_type = AUTH_KEY_TYPE_FIRST;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
(*key_type)++;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_recv_key_value(struct iscsi_acl *client, int key_type,
|
|
Packit |
eace71 |
const char *user_key_val)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_NEGOTIATE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_AUTHENTICATE) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (key_type == AUTH_KEY_TYPE_CHAP_CHALLENGE) {
|
|
Packit |
eace71 |
client->recv_chap_challenge.length =
|
|
Packit |
eace71 |
AUTH_LARGE_BINARY_MAX_LEN;
|
|
Packit |
eace71 |
client->recv_chap_challenge_status =
|
|
Packit |
eace71 |
acl_text_to_data(user_key_val,
|
|
Packit |
eace71 |
client->recv_chap_challenge.large_binary,
|
|
Packit |
eace71 |
&client->recv_chap_challenge.length);
|
|
Packit |
eace71 |
user_key_val = "";
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_set_key_value(&client->recv_key_block, key_type, user_key_val);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_send_key_val(struct iscsi_acl *client, int key_type, int *key_present,
|
|
Packit |
eace71 |
char *user_key_val, unsigned int max_length)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
const char *key_val;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_CONFIGURE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_NEGOTIATE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_AUTHENTICATE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_DONE) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (key_type < AUTH_KEY_TYPE_FIRST || key_type > AUTH_KEY_TYPE_LAST) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
key_val = acl_get_key_val(&client->send_key_block, key_type);
|
|
Packit |
eace71 |
if (key_val) {
|
|
Packit |
eace71 |
if (key_type == AUTH_KEY_TYPE_CHAP_CHALLENGE) {
|
|
Packit |
eace71 |
if (acl_data_to_text(client->send_chap_challenge.large_binary,
|
|
Packit |
eace71 |
client->send_chap_challenge.length, user_key_val,
|
|
Packit |
eace71 |
max_length)) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else if (strlcpy(user_key_val, key_val, max_length) >=
|
|
Packit |
eace71 |
max_length) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
*key_present = 1;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
*key_present = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_recv_transit_bit(struct iscsi_acl *client, int value)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_NEGOTIATE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_AUTHENTICATE) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (value)
|
|
Packit |
eace71 |
client->recv_key_block.transit_bit = 1;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
client->recv_key_block.transit_bit = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_send_transit_bit(struct iscsi_acl *client, int *value)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_CONFIGURE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_NEGOTIATE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_AUTHENTICATE &&
|
|
Packit |
eace71 |
client->phase != AUTH_PHASE_DONE) {
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*value = client->send_key_block.transit_bit;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_set_option_list(struct iscsi_acl *client, unsigned int opt_count,
|
|
Packit |
eace71 |
const int *opt_list, unsigned int *clnt_optn_count,
|
|
Packit |
eace71 |
int *clnt_optn_list, unsigned int optn_max_count,
|
|
Packit |
eace71 |
int (*chk_option)(int),
|
|
Packit |
eace71 |
int (*chk_list)(unsigned int opt_count, const int *opt_list))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int i, j;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_CONFIGURE ||
|
|
Packit |
eace71 |
opt_count > optn_max_count) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < opt_count; i++)
|
|
Packit |
eace71 |
if (chk_option(opt_list[i])) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Check for duplicate entries. */
|
|
Packit |
eace71 |
for (i = 0; i < opt_count; i++)
|
|
Packit |
eace71 |
for (j = 0; j < opt_count; j++) {
|
|
Packit |
eace71 |
if (j == i)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
if (opt_list[i] == opt_list[j]) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Check for key specific constraints. */
|
|
Packit |
eace71 |
if (chk_list)
|
|
Packit |
eace71 |
if (chk_list(opt_count, opt_list)) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < opt_count; i++)
|
|
Packit |
eace71 |
clnt_optn_list[i] = opt_list[i];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*clnt_optn_count = opt_count;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_chk_auth_method_list(unsigned int option_count, const int *option_list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!option_list || option_count < 2)
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (option_list[option_count - 1] != AUTH_OPTION_NONE)
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < (option_count - 1); i++)
|
|
Packit |
eace71 |
if (option_list[i] != AUTH_OPTION_NONE)
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void
|
|
Packit |
eace71 |
acl_set_auth_method_valid(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
unsigned int i, j = 0;
|
|
Packit |
eace71 |
int option = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Following checks may need to be revised if
|
|
Packit |
eace71 |
* authentication options other than CHAP and none
|
|
Packit |
eace71 |
* are supported.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR) {
|
|
Packit |
eace71 |
if (client->auth_rmt)
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* If initiator doing authentication,
|
|
Packit |
eace71 |
* don't offer authentication option none.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
option = 1;
|
|
Packit |
eace71 |
else if (!client->passwd_present)
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* If initiator password not set,
|
|
Packit |
eace71 |
* only offer authentication option none.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
option = 2;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_TARGET) {
|
|
Packit |
eace71 |
if (client->auth_rmt)
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* If target doing authentication,
|
|
Packit |
eace71 |
* don't accept authentication option none.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
option = 1;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* If target not doing authentication,
|
|
Packit |
eace71 |
* only accept authentication option none.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
option = 2;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < client->auth_method_count; i++) {
|
|
Packit |
eace71 |
if (option == 1) {
|
|
Packit |
eace71 |
if (client->auth_method_list[i] == AUTH_OPTION_NONE)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
} else if (option == 2)
|
|
Packit |
eace71 |
if (client->auth_method_list[i] != AUTH_OPTION_NONE)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
client->auth_method_valid_list[j++] = client->auth_method_list[i];
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->auth_method_valid_count = j;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
acl_init_key_blk(&client->send_key_block);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR) {
|
|
Packit |
eace71 |
if (client->auth_rmt) {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Initiator wants to authenticate target,
|
|
Packit |
eace71 |
* always send AuthMethod key.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
client->send_key_block.transit_bit = 0;
|
|
Packit |
eace71 |
client->auth_method_valid_neg_role =
|
|
Packit |
eace71 |
AUTH_NEG_ROLE_ORIGINATOR;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
client->send_key_block.transit_bit = 1;
|
|
Packit |
eace71 |
client->auth_method_valid_neg_role =
|
|
Packit |
eace71 |
client->auth_method_neg_role;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
client->send_key_block.transit_bit = 0;
|
|
Packit |
eace71 |
client->auth_method_valid_neg_role = AUTH_NEG_ROLE_RESPONDER;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->auth_method_valid_neg_role == AUTH_NEG_ROLE_ORIGINATOR)
|
|
Packit |
eace71 |
acl_set_auth_method_key(client, client->auth_method_valid_count,
|
|
Packit |
eace71 |
client->auth_method_valid_list);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
int value = AUTH_OPTION_NOT_PRESENT;
|
|
Packit |
eace71 |
acl_set_auth_method_key(client, 1, &value);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_set_auth_method_list(struct iscsi_acl *client, unsigned int option_count,
|
|
Packit |
eace71 |
const int *option_list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int status;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
status = acl_set_option_list(client, option_count, option_list,
|
|
Packit |
eace71 |
&client->auth_method_count,
|
|
Packit |
eace71 |
client->auth_method_list,
|
|
Packit |
eace71 |
AUTH_METHOD_MAX_COUNT,
|
|
Packit |
eace71 |
acl_chk_auth_mthd_optn,
|
|
Packit |
eace71 |
acl_chk_auth_method_list);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (status != AUTH_STATUS_NO_ERROR)
|
|
Packit |
eace71 |
return status;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Setting authMethod affects auth_method_valid. */
|
|
Packit |
eace71 |
acl_set_auth_method_valid(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_chk_chap_alg_list(unsigned int option_count, const int *option_list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!option_list || option_count < 1)
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
acl_set_chap_alg_list(struct iscsi_acl *client, unsigned int option_count,
|
|
Packit |
eace71 |
const int *option_list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
return acl_set_option_list(client, option_count, option_list,
|
|
Packit |
eace71 |
&client->chap_alg_count,
|
|
Packit |
eace71 |
client->chap_alg_list,
|
|
Packit |
eace71 |
AUTH_CHAP_ALG_MAX_COUNT,
|
|
Packit |
eace71 |
acl_chk_chap_alg_optn,
|
|
Packit |
eace71 |
acl_chk_chap_alg_list);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_init_chap_digests(int *value_list) {
|
|
Packit |
eace71 |
EVP_MD_CTX *context = EVP_MD_CTX_new();
|
|
Packit |
eace71 |
int i = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (EVP_DigestInit_ex(context, EVP_sha3_256(), NULL)) {
|
|
Packit |
eace71 |
value_list[i++] = AUTH_CHAP_ALG_SHA3_256;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (EVP_DigestInit_ex(context, EVP_sha256(), NULL)) {
|
|
Packit |
eace71 |
value_list[i++] = AUTH_CHAP_ALG_SHA256;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (EVP_DigestInit_ex(context, EVP_sha1(), NULL)) {
|
|
Packit |
eace71 |
value_list[i++] = AUTH_CHAP_ALG_SHA1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (EVP_DigestInit_ex(context, EVP_md5(), NULL)) {
|
|
Packit |
eace71 |
value_list[i++] = AUTH_CHAP_ALG_MD5;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return i;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_init(int node_type, int buf_desc_count, struct auth_buffer_desc *buff_desc)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_acl *client;
|
|
Packit |
eace71 |
struct auth_str_block *recv_str_blk;
|
|
Packit |
eace71 |
struct auth_str_block *send_str_blk;
|
|
Packit |
eace71 |
struct auth_large_binary *recv_chap_challenge;
|
|
Packit |
eace71 |
struct auth_large_binary *send_chap_challenge;
|
|
Packit |
eace71 |
int value_list[MAX(AUTH_METHOD_MAX_COUNT, AUTH_CHAP_ALG_MAX_COUNT)];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (buf_desc_count != 5 || !buff_desc)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!buff_desc[0].address ||
|
|
Packit |
eace71 |
buff_desc[0].length != sizeof(*client))
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
client = (struct iscsi_acl *)buff_desc[0].address;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!buff_desc[1].address ||
|
|
Packit |
eace71 |
buff_desc[1].length != sizeof(*recv_str_blk))
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
recv_str_blk = (struct auth_str_block *)buff_desc[1].address;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!buff_desc[2].address ||
|
|
Packit |
eace71 |
buff_desc[2].length != sizeof(*send_str_blk))
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
send_str_blk = (struct auth_str_block *)buff_desc[2].address;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!buff_desc[3].address ||
|
|
Packit |
eace71 |
buff_desc[3].length != sizeof(*recv_chap_challenge))
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
recv_chap_challenge = (struct auth_large_binary *)
|
|
Packit |
eace71 |
buff_desc[3].address;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!buff_desc[4].address ||
|
|
Packit |
eace71 |
buff_desc[4].length != sizeof(*send_chap_challenge))
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
send_chap_challenge = (struct auth_large_binary *)
|
|
Packit |
eace71 |
buff_desc[4].address;
|
|
Packit |
eace71 |
memset(client, 0, sizeof(*client));
|
|
Packit |
eace71 |
memset(recv_str_blk, 0, sizeof(*recv_str_blk));
|
|
Packit |
eace71 |
memset(send_str_blk, 0, sizeof(*send_str_blk));
|
|
Packit |
eace71 |
memset(recv_chap_challenge, 0, sizeof(*recv_chap_challenge));
|
|
Packit |
eace71 |
memset(send_chap_challenge, 0, sizeof(*send_chap_challenge));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->recv_key_block.str_block = recv_str_blk->str_block;
|
|
Packit |
eace71 |
client->send_key_block.str_block = send_str_blk->str_block;
|
|
Packit |
eace71 |
client->recv_chap_challenge.large_binary = recv_chap_challenge->large_binary;
|
|
Packit |
eace71 |
client->send_chap_challenge.large_binary = send_chap_challenge->large_binary;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (node_type != TYPE_INITIATOR && node_type != TYPE_TARGET) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->signature = ACL_SIGNATURE;
|
|
Packit |
eace71 |
client->node_type = (enum auth_node_type) node_type;
|
|
Packit |
eace71 |
client->auth_rmt = 1;
|
|
Packit |
eace71 |
client->passwd_present = 0;
|
|
Packit |
eace71 |
client->ip_sec = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_CONFIGURE;
|
|
Packit |
eace71 |
client->negotiated_auth_method = AUTH_OPTION_NOT_PRESENT;
|
|
Packit |
eace71 |
client->negotiated_chap_alg = AUTH_OPTION_NOT_PRESENT;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->node_type == TYPE_INITIATOR)
|
|
Packit |
eace71 |
client->auth_method_neg_role = AUTH_NEG_ROLE_ORIGINATOR;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
/* Initial value ignored for Target. */
|
|
Packit |
eace71 |
client->auth_method_neg_role = AUTH_NEG_ROLE_RESPONDER;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
value_list[0] = AUTH_METHOD_CHAP;
|
|
Packit |
eace71 |
value_list[1] = AUTH_OPTION_NONE;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Must call after setting auth_rmt, password,
|
|
Packit |
eace71 |
* and auth_method_neg_role
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (acl_set_auth_method_list(client, 2, value_list) !=
|
|
Packit |
eace71 |
AUTH_STATUS_NO_ERROR) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (acl_set_chap_alg_list(client, acl_init_chap_digests(value_list),
|
|
Packit |
eace71 |
value_list) != AUTH_STATUS_NO_ERROR) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_finish(struct iscsi_acl *client)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(client, 0, sizeof(*client));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_set_user_name(struct iscsi_acl *client, const char *username)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_CONFIGURE ||
|
|
Packit |
eace71 |
acl_chk_string(username, AUTH_STR_MAX_LEN, NULL)) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!username)
|
|
Packit |
eace71 |
client->username[0] = '\0';
|
|
Packit |
eace71 |
else if (strlcpy(client->username, username, AUTH_STR_MAX_LEN) >=
|
|
Packit |
eace71 |
AUTH_STR_MAX_LEN) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_set_passwd(struct iscsi_acl *client, const unsigned char *passwd_data,
|
|
Packit |
eace71 |
unsigned int passwd_length)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_CONFIGURE ||
|
|
Packit |
eace71 |
passwd_length > AUTH_STR_MAX_LEN) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memcpy(client->passwd_data, passwd_data, passwd_length);
|
|
Packit |
eace71 |
client->passwd_length = passwd_length;
|
|
Packit |
eace71 |
client->passwd_present = 1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Setting password may affect auth_method_valid. */
|
|
Packit |
eace71 |
acl_set_auth_method_valid(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_set_auth_rmt(struct iscsi_acl *client, int auth_rmt)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_CONFIGURE) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->auth_rmt = auth_rmt;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Setting auth_rmt may affect auth_method_valid. */
|
|
Packit |
eace71 |
acl_set_auth_method_valid(client);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_set_ip_sec(struct iscsi_acl *client, int ip_sec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_CONFIGURE) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
client->ip_sec = ip_sec;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_get_dbg_status(struct iscsi_acl *client, int *value)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!client || client->signature != ACL_SIGNATURE)
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (client->phase != AUTH_PHASE_DONE) {
|
|
Packit |
eace71 |
client->phase = AUTH_PHASE_ERROR;
|
|
Packit |
eace71 |
return AUTH_STATUS_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*value = client->dbg_status;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return AUTH_STATUS_NO_ERROR;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
const char *
|
|
Packit |
eace71 |
acl_dbg_status_to_text(int dbg_status)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Note: The ordering of this table must match the order
|
|
Packit |
eace71 |
* defined by enum auth_dbg_status in iscsi-auth-client.h.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static char *const dbg_text[AUTH_DBG_STATUS_MAX_COUNT] = {
|
|
Packit |
eace71 |
"Debug status not set",
|
|
Packit |
eace71 |
"Authentication request passed",
|
|
Packit |
eace71 |
"Authentication not enabled",
|
|
Packit |
eace71 |
"Authentication request failed",
|
|
Packit |
eace71 |
"AuthMethod bad",
|
|
Packit |
eace71 |
"CHAP algorithm bad",
|
|
Packit |
eace71 |
"Decrypt password failed",
|
|
Packit |
eace71 |
"Local password too short with no IPSec",
|
|
Packit |
eace71 |
"Unexpected error from authentication server",
|
|
Packit |
eace71 |
"Authentication request status bad",
|
|
Packit |
eace71 |
"Authentication pass status not valid",
|
|
Packit |
eace71 |
"Same key set more than once on send",
|
|
Packit |
eace71 |
"Key value too long on send",
|
|
Packit |
eace71 |
"Too much data on send",
|
|
Packit |
eace71 |
"AuthMethod key expected",
|
|
Packit |
eace71 |
"CHAP algorithm key expected",
|
|
Packit |
eace71 |
"CHAP identifier expected",
|
|
Packit |
eace71 |
"CHAP challenge expected",
|
|
Packit |
eace71 |
"CHAP response expected",
|
|
Packit |
eace71 |
"CHAP username expected",
|
|
Packit |
eace71 |
"AuthMethod key not present",
|
|
Packit |
eace71 |
"AuthMethod negotiation failed",
|
|
Packit |
eace71 |
"AuthMethod negotiated to none",
|
|
Packit |
eace71 |
"CHAP algorithm negotiation failed",
|
|
Packit |
eace71 |
"CHAP challenge reflected",
|
|
Packit |
eace71 |
"Local password same as remote",
|
|
Packit |
eace71 |
"Local password not set",
|
|
Packit |
eace71 |
"CHAP identifier bad",
|
|
Packit |
eace71 |
"CHAP challenge bad",
|
|
Packit |
eace71 |
"CHAP response bad",
|
|
Packit |
eace71 |
"Unexpected key present",
|
|
Packit |
eace71 |
"T bit set on response, but not on previous message",
|
|
Packit |
eace71 |
"T bit set on response, but authenticaton not complete",
|
|
Packit |
eace71 |
"Message count limit reached on receive",
|
|
Packit |
eace71 |
"Same key set more than once on receive",
|
|
Packit |
eace71 |
"Key value too long on receive",
|
|
Packit |
eace71 |
"Too much data on receive"
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (dbg_status < 0 || dbg_status >= AUTH_DBG_STATUS_MAX_COUNT)
|
|
Packit |
eace71 |
return "Unknown error";
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return dbg_text[dbg_status];
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int
|
|
Packit |
eace71 |
acl_data(unsigned char *out_data, unsigned int *out_length,
|
|
Packit |
eace71 |
unsigned char *in_data, unsigned int in_length)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (*out_length < in_length)
|
|
Packit |
eace71 |
return 1; /* error */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memcpy(out_data, in_data, in_length);
|
|
Packit |
eace71 |
*out_length = in_length;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0; /* no error */
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|