Add unidirectional chap support so we can authenticate to the target.

Make the login phase more "intelligent" so we can iterate over login
pdus until we have reached full feature phase

Add a new helper functions to parse a iscsi url and break it down
into elements in a structure

Update iscsi-inq to allow CHAP authentication
This commit is contained in:
Ronnie Sahlberg
2010-12-22 22:23:55 +11:00
parent d53b882682
commit 40abe849b0
5 changed files with 703 additions and 123 deletions

View File

@@ -44,6 +44,10 @@ struct iscsi_context {
const char *initiator_name; const char *initiator_name;
const char *target_name; const char *target_name;
const char *alias; const char *alias;
const char *user;
const char *passwd;
enum iscsi_session_type session_type; enum iscsi_session_type session_type;
unsigned char isid[6]; unsigned char isid[6];
uint32_t itt; uint32_t itt;
@@ -56,8 +60,20 @@ struct iscsi_context {
int fd; int fd;
int is_connected; int is_connected;
int current_phase;
int next_phase;
#define ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP 0
#define ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM 1
#define ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE 2
int secneg_phase;
int login_attempts;
int is_loggedin; int is_loggedin;
int chap_a;
int chap_i;
char *chap_c;
iscsi_command_cb socket_status_cb; iscsi_command_cb socket_status_cb;
void *connect_data; void *connect_data;

View File

@@ -21,6 +21,8 @@ struct sockaddr;
struct iscsi_url { struct iscsi_url {
const char *portal; const char *portal;
const char *target; const char *target;
const char *user;
const char *passwd;
int lun; int lun;
}; };
@@ -134,6 +136,12 @@ enum iscsi_header_digest {
int iscsi_set_header_digest(struct iscsi_context *iscsi, int iscsi_set_header_digest(struct iscsi_context *iscsi,
enum iscsi_header_digest header_digest); enum iscsi_header_digest header_digest);
/*
* Specify the username and password to use for chap authentication
*/
int iscsi_set_initiator_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

View File

@@ -53,6 +53,11 @@ iscsi_create_context(const char *initiator_name)
/* initialize to a "random" isid */ /* initialize to a "random" isid */
iscsi_set_isid_random(iscsi, getpid() ^ time(NULL)); iscsi_set_isid_random(iscsi, getpid() ^ time(NULL));
/* assume we start in security negotiation phase */
iscsi->current_phase = ISCSI_PDU_LOGIN_CSG_SECNEG;
iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_OPNEG;
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP;
return iscsi; return iscsi;
} }
@@ -153,6 +158,16 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
free(iscsi->error_string); free(iscsi->error_string);
iscsi->error_string = NULL; iscsi->error_string = NULL;
free(discard_const(iscsi->user));
iscsi->user = NULL;
free(discard_const(iscsi->passwd));
iscsi->passwd = NULL;
free(discard_const(iscsi->chap_c));
iscsi->chap_c = NULL;
free(iscsi); free(iscsi);
return 0; return 0;
@@ -210,25 +225,43 @@ struct iscsi_url *
iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url) iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
{ {
struct iscsi_url *iscsi_url; struct iscsi_url *iscsi_url;
char *str;
char *portal; char *portal;
char *user = NULL;
char *passwd = NULL;
char *target; char *target;
char *lun; char *lun;
char *tmp;
if (strncmp(url, "iscsi://", 8)) { if (strncmp(url, "iscsi://", 8)) {
iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of the form \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", url); iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of the form \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", url);
return NULL; return NULL;
} }
portal = strdup(url + 8); str = strdup(url + 8);
if (portal == NULL) { if (str == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup url %s\n", url); iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup url %s\n", url);
return NULL; return NULL;
} }
portal = str;
tmp = index(portal, '@');
if (tmp != NULL) {
user = portal;
*tmp++ = 0;
portal = tmp;
tmp = index(user, '%');
if (tmp != NULL) {
*tmp++ = 0;
passwd = tmp;
}
}
target = index(portal, '/'); target = index(portal, '/');
if (target == NULL) { if (target == NULL) {
iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of the form \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", url); iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of the form \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", url);
free(portal); free(str);
return NULL; return NULL;
} }
*target++ = 0; *target++ = 0;
@@ -236,7 +269,7 @@ iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
lun = index(target, '/'); lun = index(target, '/');
if (lun == NULL) { if (lun == NULL) {
iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of the form \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", url); iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of the form \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", url);
free(portal); free(str);
return NULL; return NULL;
} }
*lun++ = 0; *lun++ = 0;
@@ -245,7 +278,7 @@ iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
iscsi_url = malloc(sizeof(struct iscsi_url)); iscsi_url = malloc(sizeof(struct iscsi_url));
if (iscsi_url == NULL) { if (iscsi_url == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate iscsi_url structure\n"); iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate iscsi_url structure\n");
free(portal); free(str);
return NULL; return NULL;
} }
memset(iscsi_url, 0, sizeof(struct iscsi_url)); memset(iscsi_url, 0, sizeof(struct iscsi_url));
@@ -254,7 +287,7 @@ iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
if (iscsi_url->portal == NULL) { if (iscsi_url->portal == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup portal string\n"); iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup portal string\n");
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
free(portal); free(str);
return NULL; return NULL;
} }
@@ -262,12 +295,32 @@ iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
if (iscsi_url->target == NULL) { if (iscsi_url->target == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup target string\n"); iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup target string\n");
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
free(portal); free(str);
return NULL; return NULL;
} }
if (user != NULL) {
iscsi_url->user = strdup(user);
if (iscsi_url->user == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup username string\n");
iscsi_destroy_url(iscsi_url);
free(str);
return NULL;
}
}
if (passwd != NULL) {
iscsi_url->passwd = strdup(passwd);
if (iscsi_url->passwd == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup password string\n");
iscsi_destroy_url(iscsi_url);
free(str);
return NULL;
}
}
iscsi_url->lun = atoi(lun); iscsi_url->lun = atoi(lun);
free(portal); free(str);
return iscsi_url; return iscsi_url;
} }
@@ -280,5 +333,30 @@ iscsi_destroy_url(struct iscsi_url *iscsi_url)
free(discard_const(iscsi_url->portal)); free(discard_const(iscsi_url->portal));
free(discard_const(iscsi_url->target)); free(discard_const(iscsi_url->target));
free(discard_const(iscsi_url->user));
free(discard_const(iscsi_url->passwd));
free(iscsi_url); free(iscsi_url);
} }
int
iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
const char *user,
const char *passwd)
{
free(discard_const(iscsi->user));
iscsi->user = strdup(user);
if (iscsi->user == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to strdup username\n");
return -1;
}
free(discard_const(iscsi->passwd));
iscsi->passwd = strdup(passwd);
if (iscsi->passwd == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to strdup password\n");
return -1;
}
return 0;
}

View File

@@ -25,13 +25,477 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "iscsi.h" #include "iscsi.h"
#include "iscsi-private.h" #include "iscsi-private.h"
#include "md5.h"
static int
iscsi_login_add_initiatorname(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
/* We only send InitiatorName during opneg or the first leg of secneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG
&& iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
return 0;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)"InitiatorName=",
14) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed for InitiatorName.");
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)iscsi->initiator_name,
strlen(iscsi->initiator_name) +1) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed for InitiatorName.");
return -1;
}
return 0;
}
static int
iscsi_login_add_alias(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
/* We only send InitiatorAlias during opneg or the first leg of secneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG
&& iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
return 0;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)"InitiatorAlias=",
15) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)iscsi->alias,
strlen(iscsi->alias) +1) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
return -1;
}
return 0;
}
static int
iscsi_login_add_targetname(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
/* We only send TargetName during opneg or the first leg of secneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG
&& iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
return 0;
}
if (iscsi->target_name == NULL) {
iscsi_set_error(iscsi, "Trying normal connect but "
"target name not set.");
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)"TargetName=",
11) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)iscsi->target_name,
strlen(iscsi->target_name) +1) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
return -1;
}
return 0;
}
static int
iscsi_login_add_sessiontype(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send TargetName during opneg or the first leg of secneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG
&& iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
return 0;
}
switch (iscsi->session_type) {
case ISCSI_SESSION_DISCOVERY:
str = (char *)"SessionType=Discovery";
break;
case ISCSI_SESSION_NORMAL:
str = (char *)"SessionType=Normal";
break;
default:
iscsi_set_error(iscsi, "Can not handle sessions %d yet.",
iscsi->session_type);
return -1;
}
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;
}
return 0;
}
static int
iscsi_login_add_headerdigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send HeaderDigest during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
switch (iscsi->want_header_digest) {
case ISCSI_HEADER_DIGEST_NONE:
str = (char *)"HeaderDigest=None";
break;
case ISCSI_HEADER_DIGEST_NONE_CRC32C:
str = (char *)"HeaderDigest=None,CRC32C";
break;
case ISCSI_HEADER_DIGEST_CRC32C_NONE:
str = (char *)"HeaderDigest=CRC32C,None";
break;
case ISCSI_HEADER_DIGEST_CRC32C:
str = (char *)"HeaderDigest=CRC32C";
break;
}
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;
}
return 0;
}
static int
iscsi_login_add_datadigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send DataDigest during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"DataDigest=None";
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;
}
return 0;
}
static int
iscsi_login_add_initialr2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send InitialR2T during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"InitialR2T=Yes";
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;
}
return 0;
}
static int
iscsi_login_add_immediatedata(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send ImmediateData during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"ImmediateData=Yes";
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;
}
return 0;
}
static int
iscsi_login_add_maxburstlength(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send MaxBurstLength during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"MaxBurstLength=262144";
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;
}
return 0;
}
static int
iscsi_login_add_firstburstlength(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send FirstBurstLength during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"FirstBurstLength=262144";
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;
}
return 0;
}
static int
iscsi_login_add_maxrecvdatasegmentlength(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send MaxRecvDataSegmentLength during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"MaxRecvDataSegmentLength=262144";
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;
}
return 0;
}
static int
iscsi_login_add_datapduinorder(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send DataPduInOrder during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"DataPDUInOrder=Yes";
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;
}
return 0;
}
static int
iscsi_login_add_datasequenceinorder(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
/* We only send DataSequenceInOrder during opneg */
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
return 0;
}
str = (char *)"DataSequenceInOrder=Yes";
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;
}
return 0;
}
static int
iscsi_login_add_authmethod(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
return 0;
}
str = (char *)"AuthMethod=CHAP,None";
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;
}
return 0;
}
static int
iscsi_login_add_authalgorithm(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM) {
return 0;
}
str = (char *)"CHAP_A=5";
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;
}
return 0;
}
static int
iscsi_login_add_chap_username(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) {
return 0;
}
str = (char *)"CHAP_N=";
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;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)iscsi->user,
strlen(iscsi->user) +1) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
return -1;
}
return 0;
}
static int
h2i(int h)
{
if (h >= 'a' && h <= 'f') {
return h - 'a' + 10;
}
if (h >= 'A' && h <= 'F') {
return h - 'A' + 10;
}
return h - '0';
}
static int
i2h(int i)
{
if (i >= 10) {
return i - 10 + 'A';
}
return i + '0';
}
static int
iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
char *str;
unsigned char c, cc[2];
unsigned char digest[16];
struct MD5Context ctx;
int i;
if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) {
return 0;
}
if (iscsi->chap_c == NULL) {
iscsi_set_error(iscsi, "No CHAP challenge found");
return -1;
}
MD5Init(&ctx);
c = iscsi->chap_i;
MD5Update(&ctx, &c, 1);
MD5Update(&ctx, (unsigned char *)iscsi->passwd, strlen(iscsi->passwd));
str = iscsi->chap_c;
while (*str != 0) {
c = (h2i(str[0]) << 4) | h2i(str[1]);
str += 2;
MD5Update(&ctx, &c, 1);
}
MD5Final(digest, &ctx);
str = (char *)"CHAP_R=0x";
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<16; i++) {
c = digest[i];
cc[0] = i2h((c >> 4)&0x0f);
cc[1] = i2h((c )&0x0f);
if (iscsi_pdu_add_data(iscsi, pdu, &cc, 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;
}
return 0;
}
int int
iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
void *private_data) void *private_data)
{ {
struct iscsi_pdu *pdu; struct iscsi_pdu *pdu;
char *str; int transit;
if (iscsi->login_attempts++ > 10) {
iscsi_set_error(iscsi, "login took too many tries."
" giving up.");
return -1;
}
if (iscsi->is_loggedin != 0) { if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Trying to login while already logged " iscsi_set_error(iscsi, "Trying to login while already logged "
@@ -60,45 +524,45 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
/* login request */ /* login request */
iscsi_pdu_set_immediate(pdu); iscsi_pdu_set_immediate(pdu);
if (iscsi->user == NULL) {
iscsi->current_phase = ISCSI_PDU_LOGIN_CSG_OPNEG;
}
if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_SECNEG) {
iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_OPNEG;
}
if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_OPNEG) {
iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_FF;
}
transit = 0;
if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_OPNEG) {
transit = ISCSI_PDU_LOGIN_TRANSIT;
}
if (iscsi->current_phase == ISCSI_PDU_LOGIN_CSG_SECNEG) {
if (iscsi->secneg_phase == ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
transit = ISCSI_PDU_LOGIN_TRANSIT;
}
if (iscsi->secneg_phase == ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) {
transit = ISCSI_PDU_LOGIN_TRANSIT;
}
}
/* flags */ /* flags */
iscsi_pdu_set_pduflags(pdu, ISCSI_PDU_LOGIN_TRANSIT iscsi_pdu_set_pduflags(pdu, transit
| ISCSI_PDU_LOGIN_CSG_OPNEG | iscsi->current_phase
| ISCSI_PDU_LOGIN_NSG_FF); | iscsi->next_phase);
/* initiator name */ /* initiator name */
if (iscsi_pdu_add_data(iscsi, pdu, if (iscsi_login_add_initiatorname(iscsi, pdu) != 0) {
(unsigned char *)"InitiatorName=",
14) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
iscsi_free_pdu(iscsi, pdu);
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)iscsi->initiator_name,
strlen(iscsi->initiator_name) +1) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
/* optional alias */ /* optional alias */
if (iscsi->alias) { if (iscsi->alias) {
if (iscsi_pdu_add_data(iscsi, pdu, if (iscsi_login_add_alias(iscsi, pdu) != 0) {
(unsigned char *)"InitiatorAlias=",
15) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
iscsi_free_pdu(iscsi, pdu);
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)iscsi->alias,
strlen(iscsi->alias) +1) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
@@ -106,125 +570,92 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
/* target name */ /* target name */
if (iscsi->session_type == ISCSI_SESSION_NORMAL) { if (iscsi->session_type == ISCSI_SESSION_NORMAL) {
if (iscsi->target_name == NULL) { if (iscsi_login_add_targetname(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Trying normal connect but "
"target name not set.");
iscsi_free_pdu(iscsi, pdu);
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)"TargetName=",
11) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
iscsi_free_pdu(iscsi, pdu);
return -1;
}
if (iscsi_pdu_add_data(iscsi, pdu,
(unsigned char *)iscsi->target_name,
strlen(iscsi->target_name) +1) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
"failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
} }
/* session type */ /* session type */
switch (iscsi->session_type) { if (iscsi_login_add_sessiontype(iscsi, pdu) != 0) {
case ISCSI_SESSION_DISCOVERY:
str = (char *)"SessionType=Discovery";
break;
case ISCSI_SESSION_NORMAL:
str = (char *)"SessionType=Normal";
break;
default:
iscsi_set_error(iscsi, "Can not handle sessions %d yet.",
iscsi->session_type);
return -1;
}
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.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
switch (iscsi->want_header_digest) { /* header digest */
case ISCSI_HEADER_DIGEST_NONE: if (iscsi_login_add_headerdigest(iscsi, pdu) != 0) {
str = (char *)"HeaderDigest=None"; iscsi_free_pdu(iscsi, pdu);
break; return -1;
case ISCSI_HEADER_DIGEST_NONE_CRC32C:
str = (char *)"HeaderDigest=None,CRC32C";
break;
case ISCSI_HEADER_DIGEST_CRC32C_NONE:
str = (char *)"HeaderDigest=CRC32C,None";
break;
case ISCSI_HEADER_DIGEST_CRC32C:
str = (char *)"HeaderDigest=CRC32C";
break;
} }
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* auth method */
!= 0) { if (iscsi_login_add_authmethod(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"DataDigest=None";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* auth algorithm */
!= 0) { if (iscsi_login_add_authalgorithm(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"InitialR2T=Yes";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* chap username */
!= 0) { if (iscsi_login_add_chap_username(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"ImmediateData=Yes";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* chap response */
!= 0) { if (iscsi_login_add_chap_response(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"MaxBurstLength=262144";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* data digest */
!= 0) { if (iscsi_login_add_datadigest(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"FirstBurstLength=262144";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* initial r2t */
!= 0) { if (iscsi_login_add_initialr2t(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"MaxRecvDataSegmentLength=262144";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* immediate data */
!= 0) { if (iscsi_login_add_immediatedata(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"DataPDUInOrder=Yes";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* max burst length */
!= 0) { if (iscsi_login_add_maxburstlength(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
str = (char *)"DataSequenceInOrder=Yes";
if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) /* first burst length */
!= 0) { if (iscsi_login_add_firstburstlength(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); iscsi_free_pdu(iscsi, pdu);
return -1;
}
/* max recv data segment length */
if (iscsi_login_add_maxrecvdatasegmentlength(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
/* data pdu in order */
if (iscsi_login_add_datapduinorder(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
/* data sequence in order */
if (iscsi_login_add_datasequenceinorder(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu); iscsi_free_pdu(iscsi, pdu);
return -1; return -1;
} }
@@ -321,13 +752,51 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
} }
} }
if (!strncmp((char *)ptr, "AuthMethod=", 11)) {
if (!strcmp((char *)ptr + 11, "CHAP")) {
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM;
}
}
if (!strncmp((char *)ptr, "CHAP_A=", 7)) {
iscsi->chap_a = atoi((char *)ptr+7);
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
}
if (!strncmp((char *)ptr, "CHAP_I=", 7)) {
iscsi->chap_i = atoi((char *)ptr+7);
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
}
if (!strncmp((char *)ptr, "CHAP_C=0x", 9)) {
free(iscsi->chap_c);
iscsi->chap_c = strdup((char *)ptr+9);
if (iscsi->chap_c == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup CHAP challenge\n");
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data);
return -1;
}
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
}
ptr += len + 1; ptr += len + 1;
size -= len + 1; size -= len + 1;
} }
if (in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) {
iscsi->current_phase = (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) << 2;
}
iscsi->is_loggedin = 1; if ((in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT)
pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data); && (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) == ISCSI_PDU_LOGIN_NSG_FF) {
iscsi->is_loggedin = 1;
pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data);
} else {
if (iscsi_login_async(iscsi, pdu->callback, pdu->private_data) != 0) {
iscsi_set_error(iscsi, "Failed to send continuation login pdu");
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data);
}
}
return 0; return 0;
} }
@@ -339,6 +808,8 @@ iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
{ {
struct iscsi_pdu *pdu; struct iscsi_pdu *pdu;
iscsi->login_attempts = 0;
if (iscsi->is_loggedin == 0) { if (iscsi->is_loggedin == 0) {
iscsi_set_error(iscsi, "Trying to logout while not logged in."); iscsi_set_error(iscsi, "Trying to logout while not logged in.");
return -1; return -1;

View File

@@ -202,6 +202,13 @@ int main(int argc, const char *argv[])
iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL);
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
if (iscsi_url->user != NULL) {
if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
fprintf(stderr, "Failed to set initiator username and password\n");
exit(10);
}
}
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
fprintf(stderr, "Failed to log in to target %s\n", iscsi_get_error(iscsi)); fprintf(stderr, "Failed to log in to target %s\n", iscsi_get_error(iscsi));
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);