Add support for bidirectional CHAP
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
This commit is contained in:
63
README
63
README
@@ -33,21 +33,68 @@ To build RPMs run the following script from the libiscsi root directory
|
|||||||
iSCSI URL Format
|
iSCSI URL Format
|
||||||
================
|
================
|
||||||
iSCSI devices are specified by a URL format of the following form :
|
iSCSI devices are specified by a URL format of the following form :
|
||||||
iscsi://[<username>[%<password>]@]<host>[:<port>]/<target-iqn>/<lun>
|
iscsi://[<username>[%<password>]@]<host>[:<port>]/<target-iqn>/<lun>[?<argument>[&<argument>]*]
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
Username and password for bidirectional CHAP authentication:
|
||||||
|
target_user=<account>
|
||||||
|
target_password=<password>
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
iscsi://server/iqn.ronnie.test/1
|
iscsi://server/iqn.ronnie.test/1
|
||||||
When using CHAP authentication, username and password can be specified as part of the URL
|
|
||||||
|
|
||||||
|
CHAP Authentication
|
||||||
|
===================
|
||||||
|
CHAP authentication can be specified two ways. Either via the URL itself
|
||||||
|
or through environment variables.
|
||||||
|
|
||||||
|
Note that when setting it via the URL, be careful so that username/password
|
||||||
|
will not be visible in logfiles or the process list.
|
||||||
|
|
||||||
|
URL
|
||||||
|
---
|
||||||
|
CHAP authentication via URL is specified by providing <username>%<password>@
|
||||||
|
in the server part of the URL:
|
||||||
|
|
||||||
|
Example:
|
||||||
iscsi://ronnie%password@server/iqn.ronnie.test/1
|
iscsi://ronnie%password@server/iqn.ronnie.test/1
|
||||||
but this may make the user and password visible in log files as well as in ps aux output.
|
|
||||||
So it is also possible to provide either just the password or both the password and username
|
Environment variables
|
||||||
via environment variables.
|
---------------------
|
||||||
The username and/or password can be set via
|
Setting the CHAP authentication via environment variables:
|
||||||
LIBISCSI_CHAP_USERNAME=ronnie
|
LIBISCSI_CHAP_USERNAME=ronnie
|
||||||
LIBISCSI_CHAP_PASSWORD=password
|
LIBISCSI_CHAP_PASSWORD=password
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
LIBISCSI_CHAP_PASSWORD=password iscsi-inq iscsi://ronnie@10.1.1.27/iqn.ronnie.test/1
|
LIBISCSI_CHAP_PASSWORD=password iscsi-inq iscsi://ronnie@10.1.1.27/iqn.ronnie.test/1
|
||||||
|
|
||||||
|
Bidirectional CHAP Authentication
|
||||||
|
=================================
|
||||||
|
Bidirectional CHAP is when you not only authenticate the initiator to the target
|
||||||
|
but also authenticate the target back to the initiator.
|
||||||
|
This is only available if you also first specify normal authentication as per
|
||||||
|
the previous section.
|
||||||
|
|
||||||
|
Bidirectional CHAP can be set either via URL arguments or via environment
|
||||||
|
variables. If specifying it via URL arguments, be careful so that you do
|
||||||
|
not leak the username/password via logfiles or the process list or similar.
|
||||||
|
|
||||||
|
URL
|
||||||
|
---
|
||||||
|
URL arguments contain the '&' character so make sure to escape them properly
|
||||||
|
if you pass them in via a commandline.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
iscsi://127.0.0.1/iqn.ronnie.test/1?target_user=target\&target_password=target
|
||||||
|
|
||||||
|
Environment variables
|
||||||
|
---------------------
|
||||||
|
Setting the CHAP authentication via environment variables:
|
||||||
|
LIBISCSI_CHAP_TARGET_USERNAME=target
|
||||||
|
LIBISCSI_CHAP_TARGET_PASSWORD=password
|
||||||
|
|
||||||
|
|
||||||
IPv6 support
|
IPv6 support
|
||||||
============
|
============
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ struct iscsi_in_pdu {
|
|||||||
void iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in);
|
void iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in);
|
||||||
void iscsi_free_iscsi_inqueue(struct iscsi_context *iscsi, struct iscsi_in_pdu *inqueue);
|
void iscsi_free_iscsi_inqueue(struct iscsi_context *iscsi, struct iscsi_in_pdu *inqueue);
|
||||||
|
|
||||||
|
/* size of chap response field */
|
||||||
|
#define CHAP_R_SIZE 16
|
||||||
|
|
||||||
struct iscsi_context {
|
struct iscsi_context {
|
||||||
char initiator_name[MAX_STRING_SIZE+1];
|
char initiator_name[MAX_STRING_SIZE+1];
|
||||||
char target_name[MAX_STRING_SIZE+1];
|
char target_name[MAX_STRING_SIZE+1];
|
||||||
@@ -73,6 +76,11 @@ struct iscsi_context {
|
|||||||
char passwd[MAX_STRING_SIZE+1];
|
char passwd[MAX_STRING_SIZE+1];
|
||||||
char chap_c[MAX_STRING_SIZE+1];
|
char chap_c[MAX_STRING_SIZE+1];
|
||||||
|
|
||||||
|
char target_user[MAX_STRING_SIZE+1];
|
||||||
|
char target_passwd[MAX_STRING_SIZE+1];
|
||||||
|
uint32_t target_chap_i;
|
||||||
|
unsigned char target_chap_r[CHAP_R_SIZE];
|
||||||
|
|
||||||
char error_string[MAX_STRING_SIZE+1];
|
char error_string[MAX_STRING_SIZE+1];
|
||||||
|
|
||||||
enum iscsi_session_type session_type;
|
enum iscsi_session_type session_type;
|
||||||
|
|||||||
@@ -268,6 +268,16 @@ EXTERN int iscsi_set_header_digest(struct iscsi_context *iscsi,
|
|||||||
EXTERN int iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
|
EXTERN int iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
|
||||||
const char *user,
|
const char *user,
|
||||||
const char *passwd);
|
const char *passwd);
|
||||||
|
/*
|
||||||
|
* Specify the username and password to use for target chap authentication.
|
||||||
|
* Target/bidirectional CHAP is only supported if you also have normal
|
||||||
|
* CHAP authentication.
|
||||||
|
* You must configure CHAP first using iscsi_set_initiator_username_pwd()
|
||||||
|
`* before you can set up target authentication.
|
||||||
|
*/
|
||||||
|
EXTERN int iscsi_set_target_username_pwd(struct iscsi_context *iscsi,
|
||||||
|
const char *user,
|
||||||
|
const char *passwd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check if the context is logged in or not
|
* check if the context is logged in or not
|
||||||
|
|||||||
@@ -285,6 +285,9 @@ try_again:
|
|||||||
if (old_iscsi->user[0]) {
|
if (old_iscsi->user[0]) {
|
||||||
iscsi_set_initiator_username_pwd(iscsi, old_iscsi->user, old_iscsi->passwd);
|
iscsi_set_initiator_username_pwd(iscsi, old_iscsi->user, old_iscsi->passwd);
|
||||||
}
|
}
|
||||||
|
if (old_iscsi->target_user[0]) {
|
||||||
|
iscsi_set_target_username_pwd(iscsi, old_iscsi->target_user, old_iscsi->target_passwd);
|
||||||
|
}
|
||||||
|
|
||||||
iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL);
|
iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL);
|
||||||
|
|
||||||
|
|||||||
60
lib/init.c
60
lib/init.c
@@ -474,9 +474,43 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
|||||||
strncpy(str,url + 8, MAX_STRING_SIZE);
|
strncpy(str,url + 8, MAX_STRING_SIZE);
|
||||||
portal = str;
|
portal = str;
|
||||||
|
|
||||||
|
iscsi_set_target_username_pwd(iscsi,
|
||||||
|
getenv("LIBISCSI_CHAP_TARGET_USERNAME"),
|
||||||
|
getenv("LIBISCSI_CHAP_TARGET_PASSWORD"));
|
||||||
|
|
||||||
user = getenv("LIBISCSI_CHAP_USERNAME");
|
user = getenv("LIBISCSI_CHAP_USERNAME");
|
||||||
passwd = getenv("LIBISCSI_CHAP_PASSWORD");
|
passwd = getenv("LIBISCSI_CHAP_PASSWORD");
|
||||||
|
|
||||||
|
tmp = strchr(portal, '?');
|
||||||
|
if (tmp) {
|
||||||
|
*tmp++ = 0;
|
||||||
|
while (tmp && *tmp) {
|
||||||
|
char *next = strchr(tmp, '&');
|
||||||
|
char *key, *value;
|
||||||
|
|
||||||
|
if (next != NULL) {
|
||||||
|
*next++ = 0;
|
||||||
|
}
|
||||||
|
key = tmp;
|
||||||
|
value = strchr(key, '=');
|
||||||
|
if (value != NULL) {
|
||||||
|
*value++ = 0;
|
||||||
|
}
|
||||||
|
if (!strcmp(key, "target_user")) {
|
||||||
|
if (value) {
|
||||||
|
strncpy(iscsi->target_user,
|
||||||
|
value, MAX_STRING_SIZE);
|
||||||
|
}
|
||||||
|
} else if (!strcmp(key, "target_password")) {
|
||||||
|
if (value) {
|
||||||
|
strncpy(iscsi->target_passwd,
|
||||||
|
value, MAX_STRING_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tmp = strchr(portal, '@');
|
tmp = strchr(portal, '@');
|
||||||
if (tmp != NULL) {
|
if (tmp != NULL) {
|
||||||
user = portal;
|
user = portal;
|
||||||
@@ -553,9 +587,19 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
|||||||
|
|
||||||
strncpy(iscsi_url->portal,portal,MAX_STRING_SIZE);
|
strncpy(iscsi_url->portal,portal,MAX_STRING_SIZE);
|
||||||
|
|
||||||
|
if (!iscsi->target_user[0] || !iscsi->target_passwd[0]) {
|
||||||
|
iscsi->target_user[0] = 0;
|
||||||
|
iscsi->target_passwd[0] = 0;
|
||||||
|
}
|
||||||
if (user != NULL && passwd != NULL) {
|
if (user != NULL && passwd != NULL) {
|
||||||
strncpy(iscsi_url->user, user, MAX_STRING_SIZE);
|
strncpy(iscsi_url->user, user, MAX_STRING_SIZE);
|
||||||
strncpy(iscsi_url->passwd, passwd, MAX_STRING_SIZE);
|
strncpy(iscsi_url->passwd, passwd, MAX_STRING_SIZE);
|
||||||
|
} else {
|
||||||
|
/* if we do not have normal CHAP, that means we do not have
|
||||||
|
* bidirectional either.
|
||||||
|
*/
|
||||||
|
iscsi->target_user[0] = 0;
|
||||||
|
iscsi->target_passwd[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (full) {
|
if (full) {
|
||||||
@@ -601,6 +645,22 @@ iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iscsi_set_target_username_pwd(struct iscsi_context *iscsi,
|
||||||
|
const char *user, const char *passwd)
|
||||||
|
{
|
||||||
|
if (!user || !passwd) {
|
||||||
|
iscsi->target_user[0] = 0;
|
||||||
|
iscsi->target_passwd[0] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strncpy(iscsi->target_user, user, MAX_STRING_SIZE);
|
||||||
|
strncpy(iscsi->target_passwd, passwd, MAX_STRING_SIZE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
iscsi_set_immediate_data(struct iscsi_context *iscsi, enum iscsi_immediate_data immediate_data)
|
iscsi_set_immediate_data(struct iscsi_context *iscsi, enum iscsi_immediate_data immediate_data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ iscsi_set_isid_oui
|
|||||||
iscsi_set_isid_random
|
iscsi_set_isid_random
|
||||||
iscsi_set_isid_reserved
|
iscsi_set_isid_reserved
|
||||||
iscsi_set_session_type
|
iscsi_set_session_type
|
||||||
|
iscsi_set_target_username_pwd
|
||||||
iscsi_set_targetname
|
iscsi_set_targetname
|
||||||
iscsi_set_tcp_keepalive
|
iscsi_set_tcp_keepalive
|
||||||
iscsi_set_tcp_user_timeout
|
iscsi_set_tcp_user_timeout
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ iscsi_set_isid_oui
|
|||||||
iscsi_set_isid_random
|
iscsi_set_isid_random
|
||||||
iscsi_set_isid_reserved
|
iscsi_set_isid_reserved
|
||||||
iscsi_set_session_type
|
iscsi_set_session_type
|
||||||
|
iscsi_set_target_username_pwd
|
||||||
iscsi_set_targetname
|
iscsi_set_targetname
|
||||||
iscsi_set_tcp_keepalive
|
iscsi_set_tcp_keepalive
|
||||||
iscsi_set_tcp_user_timeout
|
iscsi_set_tcp_user_timeout
|
||||||
|
|||||||
139
lib/login.c
139
lib/login.c
@@ -637,13 +637,16 @@ static void gcry_md_close(gcry_md_hd_t h)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* size of the challenge used for bidirectional chap */
|
||||||
|
#define TARGET_CHAP_C_SIZE 32
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
|
iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
|
||||||
{
|
{
|
||||||
char str[MAX_STRING_SIZE+1];
|
char str[MAX_STRING_SIZE+1];
|
||||||
char * strp;
|
char * strp;
|
||||||
unsigned char c, cc[2];
|
unsigned char c, cc[2];
|
||||||
unsigned char digest[16];
|
unsigned char digest[CHAP_R_SIZE];
|
||||||
gcry_md_hd_t ctx;
|
gcry_md_hd_t ctx;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -652,14 +655,14 @@ iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_md_open(&ctx, GCRY_MD_MD5, 0);
|
if (!iscsi->chap_c[0]) {
|
||||||
if (!ctx) {
|
iscsi_set_error(iscsi, "No CHAP challenge found");
|
||||||
iscsi_set_error(iscsi, "Cannot create MD5 algorithm");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iscsi->chap_c[0]) {
|
gcry_md_open(&ctx, GCRY_MD_MD5, 0);
|
||||||
iscsi_set_error(iscsi, "No CHAP challenge found");
|
if (ctx == NULL) {
|
||||||
|
iscsi_set_error(iscsi, "Cannot create MD5 algorithm");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
gcry_md_putc(ctx, iscsi->chap_i);
|
gcry_md_putc(ctx, iscsi->chap_i);
|
||||||
@@ -681,7 +684,7 @@ iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<16; i++) {
|
for (i = 0; i < CHAP_R_SIZE; i++) {
|
||||||
c = digest[i];
|
c = digest[i];
|
||||||
cc[0] = i2h((c >> 4)&0x0f);
|
cc[0] = i2h((c >> 4)&0x0f);
|
||||||
cc[1] = i2h((c )&0x0f);
|
cc[1] = i2h((c )&0x0f);
|
||||||
@@ -698,6 +701,63 @@ iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* bidirectional chap */
|
||||||
|
if (iscsi->target_user[0]) {
|
||||||
|
unsigned char target_chap_c[TARGET_CHAP_C_SIZE];
|
||||||
|
|
||||||
|
iscsi->target_chap_i++;
|
||||||
|
snprintf(str, MAX_STRING_SIZE, "CHAP_I=%d",
|
||||||
|
iscsi->target_chap_i);
|
||||||
|
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str,
|
||||||
|
strlen(str) + 1) != 0) {
|
||||||
|
iscsi_set_error(iscsi, "Out-of-memory: pdu add "
|
||||||
|
"data failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < TARGET_CHAP_C_SIZE; i++) {
|
||||||
|
target_chap_c[i] = rand()&0xff;
|
||||||
|
}
|
||||||
|
strncpy(str, "CHAP_C=0x", MAX_STRING_SIZE);
|
||||||
|
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str,
|
||||||
|
strlen(str)) != 0) {
|
||||||
|
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
|
||||||
|
"failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < TARGET_CHAP_C_SIZE; i++) {
|
||||||
|
c = target_chap_c[i];
|
||||||
|
cc[0] = i2h((c >> 4)&0x0f);
|
||||||
|
cc[1] = i2h((c )&0x0f);
|
||||||
|
if (iscsi_pdu_add_data(iscsi, pdu, &cc[0], 2) != 0) {
|
||||||
|
iscsi_set_error(iscsi, "Out-of-memory: pdu add "
|
||||||
|
"data failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = 0;
|
||||||
|
if (iscsi_pdu_add_data(iscsi, pdu, &c, 1) != 0) {
|
||||||
|
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
|
||||||
|
"failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcry_md_open(&ctx, GCRY_MD_MD5, 0);
|
||||||
|
if (ctx == NULL) {
|
||||||
|
iscsi_set_error(iscsi, "Cannot create MD5 algorithm");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gcry_md_putc(ctx, iscsi->target_chap_i);
|
||||||
|
gcry_md_write(ctx, (unsigned char *)iscsi->target_passwd,
|
||||||
|
strlen(iscsi->target_passwd));
|
||||||
|
gcry_md_write(ctx, (unsigned char *)target_chap_c,
|
||||||
|
TARGET_CHAP_C_SIZE);
|
||||||
|
|
||||||
|
memcpy(iscsi->target_chap_r, gcry_md_read(ctx, 0),
|
||||||
|
sizeof(iscsi->target_chap_r));
|
||||||
|
gcry_md_close(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -969,12 +1029,24 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
uint32_t status;
|
uint32_t status;
|
||||||
char *ptr = (char *)in->data;
|
char *ptr = (char *)in->data;
|
||||||
int size = in->data_pos;
|
int size = in->data_pos;
|
||||||
|
int must_have_chap_n = 0;
|
||||||
|
int must_have_chap_r = 0;
|
||||||
|
|
||||||
status = scsi_get_uint16(&in->hdr[36]);
|
status = scsi_get_uint16(&in->hdr[36]);
|
||||||
|
|
||||||
iscsi_adjust_statsn(iscsi, in);
|
iscsi_adjust_statsn(iscsi, in);
|
||||||
iscsi_adjust_maxexpcmdsn(iscsi, in);
|
iscsi_adjust_maxexpcmdsn(iscsi, in);
|
||||||
|
|
||||||
|
/* Using bidirectional CHAP? Then we must see a chap_n and chap_r
|
||||||
|
* field in this PDU
|
||||||
|
*/
|
||||||
|
if ((in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT)
|
||||||
|
&& (in->hdr[1] & ISCSI_PDU_LOGIN_CSG_FF) == ISCSI_PDU_LOGIN_CSG_SECNEG
|
||||||
|
&& iscsi->target_user[0]) {
|
||||||
|
must_have_chap_n = 1;
|
||||||
|
must_have_chap_r = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX here we should parse the data returned in case the target
|
/* XXX here we should parse the data returned in case the target
|
||||||
* renegotiated some some parameters.
|
* renegotiated some some parameters.
|
||||||
* we should also do proper handshaking if the target is not yet
|
* we should also do proper handshaking if the target is not yet
|
||||||
@@ -1070,6 +1142,43 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
|
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strncmp(ptr, "CHAP_N=", 7)) {
|
||||||
|
if (strcmp(iscsi->target_user, ptr + 7)) {
|
||||||
|
iscsi_set_error(iscsi, "Failed to log in to"
|
||||||
|
" target. Wrong CHAP targetname"
|
||||||
|
" received: %s", ptr + 7);
|
||||||
|
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||||
|
pdu->private_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
must_have_chap_n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(ptr, "CHAP_R=0x", 9)) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len != 9 + 2 * CHAP_R_SIZE) {
|
||||||
|
iscsi_set_error(iscsi, "Wrong size of CHAP_R"
|
||||||
|
" received from target.");
|
||||||
|
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||||
|
pdu->private_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < CHAP_R_SIZE; i++) {
|
||||||
|
unsigned char c;
|
||||||
|
c = ((h2i(ptr[9 + 2 * i]) << 4) | h2i(ptr[9 + 2 * i + 1]));
|
||||||
|
if (c != iscsi->target_chap_r[i]) {
|
||||||
|
iscsi_set_error(iscsi, "Authentication "
|
||||||
|
"failed. Invalid CHAP_R "
|
||||||
|
"response from the target");
|
||||||
|
pdu->callback(iscsi, SCSI_STATUS_ERROR,
|
||||||
|
NULL, pdu->private_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
must_have_chap_r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ptr += len + 1;
|
ptr += len + 1;
|
||||||
size -= len + 1;
|
size -= len + 1;
|
||||||
}
|
}
|
||||||
@@ -1089,6 +1198,22 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (must_have_chap_n) {
|
||||||
|
iscsi_set_error(iscsi, "Failed to log in to target. "
|
||||||
|
"It did not return CHAP_N during SECNEG.");
|
||||||
|
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||||
|
pdu->private_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (must_have_chap_r) {
|
||||||
|
iscsi_set_error(iscsi, "Failed to log in to target. "
|
||||||
|
"It did not return CHAP_R during SECNEG.");
|
||||||
|
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||||
|
pdu->private_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) {
|
if (in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) {
|
||||||
iscsi->current_phase = (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) << 2;
|
iscsi->current_phase = (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) << 2;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user