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 *target_name;
const char *alias;
const char *user;
const char *passwd;
enum iscsi_session_type session_type;
unsigned char isid[6];
uint32_t itt;
@@ -56,8 +60,20 @@ struct iscsi_context {
int fd;
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 chap_a;
int chap_i;
char *chap_c;
iscsi_command_cb socket_status_cb;
void *connect_data;

View File

@@ -21,6 +21,8 @@ struct sockaddr;
struct iscsi_url {
const char *portal;
const char *target;
const char *user;
const char *passwd;
int lun;
};
@@ -134,6 +136,12 @@ enum iscsi_header_digest {
int iscsi_set_header_digest(struct iscsi_context *iscsi,
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

View File

@@ -53,6 +53,11 @@ iscsi_create_context(const char *initiator_name)
/* initialize to a "random" isid */
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;
}
@@ -153,6 +158,16 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
free(iscsi->error_string);
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);
return 0;
@@ -210,25 +225,43 @@ struct iscsi_url *
iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
{
struct iscsi_url *iscsi_url;
char *str;
char *portal;
char *user = NULL;
char *passwd = NULL;
char *target;
char *lun;
char *tmp;
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);
return NULL;
}
portal = strdup(url + 8);
if (portal == NULL) {
str = strdup(url + 8);
if (str == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup url %s\n", url);
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, '/');
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);
free(portal);
free(str);
return NULL;
}
*target++ = 0;
@@ -236,7 +269,7 @@ iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
lun = index(target, '/');
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);
free(portal);
free(str);
return NULL;
}
*lun++ = 0;
@@ -245,7 +278,7 @@ iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
iscsi_url = malloc(sizeof(struct iscsi_url));
if (iscsi_url == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate iscsi_url structure\n");
free(portal);
free(str);
return NULL;
}
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) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup portal string\n");
iscsi_destroy_url(iscsi_url);
free(portal);
free(str);
return NULL;
}
@@ -262,12 +295,32 @@ iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
if (iscsi_url->target == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup target string\n");
iscsi_destroy_url(iscsi_url);
free(portal);
free(str);
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);
free(portal);
free(str);
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->target));
free(discard_const(iscsi_url->user));
free(discard_const(iscsi_url->passwd));
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,14 +25,478 @@
#include <arpa/inet.h>
#include "iscsi.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
iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
void *private_data)
{
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) {
iscsi_set_error(iscsi, "Trying to login while already logged "
"in.");
@@ -60,45 +524,45 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
/* login request */
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 */
iscsi_pdu_set_pduflags(pdu, ISCSI_PDU_LOGIN_TRANSIT
| ISCSI_PDU_LOGIN_CSG_OPNEG
| ISCSI_PDU_LOGIN_NSG_FF);
iscsi_pdu_set_pduflags(pdu, transit
| iscsi->current_phase
| iscsi->next_phase);
/* initiator name */
if (iscsi_pdu_add_data(iscsi, pdu,
(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.");
if (iscsi_login_add_initiatorname(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
/* optional alias */
if (iscsi->alias) {
if (iscsi_pdu_add_data(iscsi, pdu,
(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.");
if (iscsi_login_add_alias(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
@@ -106,125 +570,92 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
/* target name */
if (iscsi->session_type == ISCSI_SESSION_NORMAL) {
if (iscsi->target_name == NULL) {
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.");
if (iscsi_login_add_targetname(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
}
/* session type */
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.");
if (iscsi_login_add_sessiontype(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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;
/* header digest */
if (iscsi_login_add_headerdigest(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
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.");
/* auth method */
if (iscsi_login_add_authmethod(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* auth algorithm */
if (iscsi_login_add_authalgorithm(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* chap username */
if (iscsi_login_add_chap_username(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* chap response */
if (iscsi_login_add_chap_response(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* data digest */
if (iscsi_login_add_datadigest(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* initial r2t */
if (iscsi_login_add_initialr2t(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* immediate data */
if (iscsi_login_add_immediatedata(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* max burst length */
if (iscsi_login_add_maxburstlength(iscsi, pdu) != 0) {
iscsi_free_pdu(iscsi, pdu);
return -1;
}
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.");
/* first burst length */
if (iscsi_login_add_firstburstlength(iscsi, pdu) != 0) {
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);
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;
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;
pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data);
if ((in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT)
&& (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;
}
@@ -339,6 +808,8 @@ iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
{
struct iscsi_pdu *pdu;
iscsi->login_attempts = 0;
if (iscsi->is_loggedin == 0) {
iscsi_set_error(iscsi, "Trying to logout while not logged in.");
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_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) {
fprintf(stderr, "Failed to log in to target %s\n", iscsi_get_error(iscsi));
iscsi_destroy_url(iscsi_url);