Merge pull request #460 from plieven/feat/verify_sn
feat: read and validate unit serial number after login
This commit is contained in:
@@ -48,10 +48,11 @@ target_password=<password>
|
|||||||
header_digest=<crc32c|none>
|
header_digest=<crc32c|none>
|
||||||
data_digest=<crc32c|none>
|
data_digest=<crc32c|none>
|
||||||
auth=<md5|sha1|sha-256|sha3-256>
|
auth=<md5|sha1|sha-256|sha3-256>
|
||||||
|
force_usn=<unit_serial_number>
|
||||||
|
|
||||||
Transport:
|
Transport:
|
||||||
iser
|
iser
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
iscsi://server/iqn.ronnie.test/1
|
iscsi://server/iqn.ronnie.test/1
|
||||||
|
|
||||||
@@ -193,7 +194,7 @@ To run those tests you would specify
|
|||||||
|
|
||||||
Test discovery
|
Test discovery
|
||||||
--------------
|
--------------
|
||||||
To discover which tests exist you can use the command
|
To discover which tests exist you can use the command
|
||||||
iscsi-test-cu --list
|
iscsi-test-cu --list
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ struct iscsi_context {
|
|||||||
char portal[MAX_STRING_SIZE+1];
|
char portal[MAX_STRING_SIZE+1];
|
||||||
char alias[MAX_STRING_SIZE+1];
|
char alias[MAX_STRING_SIZE+1];
|
||||||
char bind_interfaces[MAX_STRING_SIZE+1];
|
char bind_interfaces[MAX_STRING_SIZE+1];
|
||||||
|
char unit_serial_number[MAX_STRING_SIZE+1];
|
||||||
|
|
||||||
enum iscsi_chap_auth chap_auth;
|
enum iscsi_chap_auth chap_auth;
|
||||||
char user[MAX_STRING_SIZE+1];
|
char user[MAX_STRING_SIZE+1];
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ iscsi_get_auth(struct iscsi_context *iscsi);
|
|||||||
|
|
||||||
EXTERN void
|
EXTERN void
|
||||||
iscsi_set_auth(struct iscsi_context *iscsi, enum iscsi_chap_auth auth);
|
iscsi_set_auth(struct iscsi_context *iscsi, enum iscsi_chap_auth auth);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is used to parse an iSCSI URL into a iscsi_url structure.
|
* This function is used to parse an iSCSI URL into a iscsi_url structure.
|
||||||
* iSCSI URL format :
|
* iSCSI URL format :
|
||||||
@@ -301,6 +301,24 @@ EXTERN int iscsi_set_alias(struct iscsi_context *iscsi, const char *alias);
|
|||||||
*/
|
*/
|
||||||
EXTERN int iscsi_set_targetname(struct iscsi_context *iscsi, const char *targetname);
|
EXTERN int iscsi_set_targetname(struct iscsi_context *iscsi, const char *targetname);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the unit serial number (usn) as reported by VPD page 0x80.
|
||||||
|
* If set the usn is validated after logging in and especially after reconnecting
|
||||||
|
* to a target to avoid accidently mismatch between LUN ids on the same target.
|
||||||
|
* If not set explicitely the usn is learned at the first successful login to the target.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0: success
|
||||||
|
* <0: error
|
||||||
|
*/
|
||||||
|
EXTERN int iscsi_set_unit_serial_number(struct iscsi_context *iscsi, const char *usn);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function returns a pointer to the unit serial number that is valid if explicitely
|
||||||
|
* set or after the first successful login to the target.
|
||||||
|
*/
|
||||||
|
EXTERN const char *iscsi_get_unit_serial_number(struct iscsi_context *iscsi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function returns any target address supplied in a login response when
|
* This function returns any target address supplied in a login response when
|
||||||
* the target has moved.
|
* the target has moved.
|
||||||
@@ -685,7 +703,7 @@ EXTERN void iscsi_free_discovery_data(struct iscsi_context *iscsi,
|
|||||||
* structure containing the data returned from
|
* structure containing the data returned from
|
||||||
* the server.
|
* the server.
|
||||||
* SCSI_STATUS_CANCELLED : Discovery was aborted. Command_data is NULL.
|
* SCSI_STATUS_CANCELLED : Discovery was aborted. Command_data is NULL.
|
||||||
*
|
*
|
||||||
* The callback may be NULL if you only want to let libiscsi count the in-flight
|
* The callback may be NULL if you only want to let libiscsi count the in-flight
|
||||||
* NOPs.
|
* NOPs.
|
||||||
*/
|
*/
|
||||||
@@ -1684,7 +1702,7 @@ iscsi_set_noautoreconnect(struct iscsi_context *iscsi, int state);
|
|||||||
|
|
||||||
|
|
||||||
/* This function is to set if we should retry a failed reconnect
|
/* This function is to set if we should retry a failed reconnect
|
||||||
|
|
||||||
count is defined as follows:
|
count is defined as follows:
|
||||||
-1 -> retry forever (default)
|
-1 -> retry forever (default)
|
||||||
0 -> never retry
|
0 -> never retry
|
||||||
@@ -1707,7 +1725,7 @@ iscsi_set_fd_dup_cb(struct iscsi_context *iscsi,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* MULTITHREADING
|
* MULTITHREADING
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* This function starts a separate service thread for multithreading support.
|
* This function starts a separate service thread for multithreading support.
|
||||||
*/
|
*/
|
||||||
@@ -1716,7 +1734,7 @@ EXTERN int iscsi_mt_service_thread_start(struct iscsi_context *iscsi);
|
|||||||
* Shutdown multithreading support.
|
* Shutdown multithreading support.
|
||||||
*/
|
*/
|
||||||
EXTERN void iscsi_mt_service_thread_stop(struct iscsi_context *iscsi);
|
EXTERN void iscsi_mt_service_thread_stop(struct iscsi_context *iscsi);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -76,6 +76,55 @@ iscsi_testunitready_connect(struct iscsi_context *iscsi, int lun,
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct scsi_task *
|
||||||
|
iscsi_inquiry_page_0x80_connect(struct iscsi_context *iscsi, int lun,
|
||||||
|
iscsi_command_cb cb, void *private_data)
|
||||||
|
{
|
||||||
|
struct scsi_task *task;
|
||||||
|
struct iscsi_context *old_iscsi = iscsi->old_iscsi;
|
||||||
|
|
||||||
|
iscsi->old_iscsi = NULL;
|
||||||
|
task = iscsi_inquiry_task(iscsi, lun, 1, 0x80, MAX_STRING_SIZE + 64,
|
||||||
|
cb, private_data);
|
||||||
|
iscsi->old_iscsi = old_iscsi;
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iscsi_inquiry_page_0x80_cb(struct iscsi_context *iscsi, int status,
|
||||||
|
void *command_data, void *private_data)
|
||||||
|
{
|
||||||
|
struct connect_task *ct = private_data;
|
||||||
|
struct scsi_task *task = command_data;
|
||||||
|
struct scsi_inquiry_unit_serial_number *inq;
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
inq = scsi_datain_unmarshall(task);
|
||||||
|
if (inq != NULL) {
|
||||||
|
if (!iscsi->unit_serial_number[0]) {
|
||||||
|
ISCSI_LOG(iscsi, 2, "unit serial number is [%s]", inq->usn);
|
||||||
|
strncpy(iscsi->unit_serial_number, inq->usn, MAX_STRING_SIZE);
|
||||||
|
} else if (strncmp(iscsi->unit_serial_number, inq->usn, MAX_STRING_SIZE)) {
|
||||||
|
iscsi_set_error(iscsi, "unit serial number mismatch. got [%s] expected [%s]",
|
||||||
|
inq->usn, iscsi->unit_serial_number);
|
||||||
|
status = 1;
|
||||||
|
} else {
|
||||||
|
ISCSI_LOG(iscsi, 2, "successfully validated unit serial number [%s]", inq->usn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iscsi_set_error(iscsi, "iscsi_inquiry_task datain_unmarshall failed. could not read vpd page 0x80.");
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iscsi_set_error(iscsi, "iscsi_inquiry_task failed. could not read vpd page 0x80.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ct->cb(iscsi, status?SCSI_STATUS_ERROR:SCSI_STATUS_GOOD, NULL, ct->private_data);
|
||||||
|
scsi_free_scsi_task(task);
|
||||||
|
iscsi_free(iscsi, ct);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
|
iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
|
||||||
void *command_data, void *private_data)
|
void *command_data, void *private_data)
|
||||||
@@ -137,10 +186,21 @@ iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
|
|||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ct->cb(iscsi, status?SCSI_STATUS_ERROR:SCSI_STATUS_GOOD, NULL,
|
if (status != 0) {
|
||||||
ct->private_data);
|
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||||
scsi_free_scsi_task(task);
|
ct->private_data);
|
||||||
iscsi_free(iscsi, ct);
|
scsi_free_scsi_task(task);
|
||||||
|
iscsi_free(iscsi, ct);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscsi_inquiry_page_0x80_connect(iscsi, ct->lun,
|
||||||
|
iscsi_inquiry_page_0x80_cb,
|
||||||
|
ct) == NULL) {
|
||||||
|
iscsi_set_error(iscsi, "iscsi_inquiry_task failed.");
|
||||||
|
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data);
|
||||||
|
iscsi_free(iscsi, ct);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -178,8 +238,13 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
|||||||
iscsi_free(iscsi, ct);
|
iscsi_free(iscsi, ct);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ct->cb(iscsi, SCSI_STATUS_GOOD, NULL, ct->private_data);
|
if (iscsi_inquiry_page_0x80_connect(iscsi, ct->lun,
|
||||||
iscsi_free(iscsi, ct);
|
iscsi_inquiry_page_0x80_cb,
|
||||||
|
ct) == NULL) {
|
||||||
|
iscsi_set_error(iscsi, "iscsi_inquiry_task failed.");
|
||||||
|
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data);
|
||||||
|
iscsi_free(iscsi, ct);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +436,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
|
|||||||
iscsi->frees += old_iscsi->frees;
|
iscsi->frees += old_iscsi->frees;
|
||||||
|
|
||||||
free(old_iscsi);
|
free(old_iscsi);
|
||||||
|
|
||||||
/* avoid a reconnect faster than 3 seconds */
|
/* avoid a reconnect faster than 3 seconds */
|
||||||
iscsi->next_reconnect = time(NULL) + 3;
|
iscsi->next_reconnect = time(NULL) + 3;
|
||||||
|
|
||||||
@@ -443,10 +508,12 @@ static int reconnect(struct iscsi_context *iscsi, int force)
|
|||||||
tmp_iscsi->lun = iscsi->lun;
|
tmp_iscsi->lun = iscsi->lun;
|
||||||
|
|
||||||
strncpy(tmp_iscsi->portal, iscsi->portal, MAX_STRING_SIZE);
|
strncpy(tmp_iscsi->portal, iscsi->portal, MAX_STRING_SIZE);
|
||||||
|
|
||||||
strncpy(tmp_iscsi->bind_interfaces, iscsi->bind_interfaces, MAX_STRING_SIZE);
|
strncpy(tmp_iscsi->bind_interfaces, iscsi->bind_interfaces, MAX_STRING_SIZE);
|
||||||
tmp_iscsi->bind_interfaces_cnt = iscsi->bind_interfaces_cnt;
|
tmp_iscsi->bind_interfaces_cnt = iscsi->bind_interfaces_cnt;
|
||||||
|
|
||||||
|
strncpy(tmp_iscsi->unit_serial_number, iscsi->unit_serial_number, MAX_STRING_SIZE);
|
||||||
|
|
||||||
tmp_iscsi->log_level = iscsi->log_level;
|
tmp_iscsi->log_level = iscsi->log_level;
|
||||||
tmp_iscsi->log_fn = iscsi->log_fn;
|
tmp_iscsi->log_fn = iscsi->log_fn;
|
||||||
tmp_iscsi->tcp_user_timeout = iscsi->tcp_user_timeout;
|
tmp_iscsi->tcp_user_timeout = iscsi->tcp_user_timeout;
|
||||||
|
|||||||
34
lib/init.c
34
lib/init.c
@@ -215,7 +215,7 @@ iscsi_create_context(const char *initiator_name)
|
|||||||
iscsi->tcp_keepcnt=3;
|
iscsi->tcp_keepcnt=3;
|
||||||
iscsi->tcp_keepintvl=30;
|
iscsi->tcp_keepintvl=30;
|
||||||
iscsi->tcp_keepidle=30;
|
iscsi->tcp_keepidle=30;
|
||||||
|
|
||||||
iscsi->reconnect_max_retries = -1;
|
iscsi->reconnect_max_retries = -1;
|
||||||
iscsi->chap_auth = ISCSI_CHAP_MD5;
|
iscsi->chap_auth = ISCSI_CHAP_MD5;
|
||||||
|
|
||||||
@@ -345,6 +345,26 @@ iscsi_set_targetname(struct iscsi_context *iscsi, const char *target_name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
iscsi_set_unit_serial_number(struct iscsi_context *iscsi, const char *usn)
|
||||||
|
{
|
||||||
|
if (iscsi->is_loggedin != 0) {
|
||||||
|
iscsi_set_error(iscsi, "Already logged in when adding "
|
||||||
|
"unit_serial_number");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(iscsi->unit_serial_number,usn,MAX_STRING_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
iscsi_get_unit_serial_number(struct iscsi_context *iscsi)
|
||||||
|
{
|
||||||
|
return iscsi ? iscsi->unit_serial_number : "";
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
iscsi_destroy_context(struct iscsi_context *iscsi)
|
iscsi_destroy_context(struct iscsi_context *iscsi)
|
||||||
{
|
{
|
||||||
@@ -383,7 +403,7 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
|
|||||||
|
|
||||||
iscsi_mt_spin_destroy(&iscsi->iscsi_lock);
|
iscsi_mt_spin_destroy(&iscsi->iscsi_lock);
|
||||||
iscsi_mt_mutex_destroy(&iscsi->iscsi_mutex);
|
iscsi_mt_mutex_destroy(&iscsi->iscsi_mutex);
|
||||||
|
|
||||||
memset(iscsi, 0, sizeof(struct iscsi_context));
|
memset(iscsi, 0, sizeof(struct iscsi_context));
|
||||||
free(iscsi);
|
free(iscsi);
|
||||||
|
|
||||||
@@ -521,6 +541,7 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
|||||||
char *passwd = NULL;
|
char *passwd = NULL;
|
||||||
char *target_user = NULL;
|
char *target_user = NULL;
|
||||||
char *target_passwd = NULL;
|
char *target_passwd = NULL;
|
||||||
|
char *usn = NULL;
|
||||||
char *target = NULL;
|
char *target = NULL;
|
||||||
char *lun;
|
char *lun;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
@@ -628,6 +649,9 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
|||||||
iscsi->rdma_ack_timeout = atoi(value);
|
iscsi->rdma_ack_timeout = atoi(value);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (!strcmp(key, "force_usn")) {
|
||||||
|
usn = value;
|
||||||
|
}
|
||||||
tmp = next;
|
tmp = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -691,7 +715,7 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
|||||||
*tmp=0;
|
*tmp=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscsi != NULL) {
|
if (iscsi != NULL) {
|
||||||
iscsi_url = iscsi_malloc(iscsi, sizeof(struct iscsi_url));
|
iscsi_url = iscsi_malloc(iscsi, sizeof(struct iscsi_url));
|
||||||
} else {
|
} else {
|
||||||
@@ -743,6 +767,9 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
|||||||
iscsi_set_targetname(iscsi, iscsi_url->target);
|
iscsi_set_targetname(iscsi, iscsi_url->target);
|
||||||
iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd);
|
iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd);
|
||||||
iscsi_set_target_username_pwd(iscsi, iscsi_url->target_user, iscsi_url->target_passwd);
|
iscsi_set_target_username_pwd(iscsi, iscsi_url->target_user, iscsi_url->target_passwd);
|
||||||
|
if (usn) {
|
||||||
|
iscsi_set_unit_serial_number(iscsi, usn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return iscsi_url;
|
return iscsi_url;
|
||||||
@@ -854,4 +881,3 @@ iscsi_set_auth(struct iscsi_context *iscsi, enum iscsi_chap_auth auth)
|
|||||||
{
|
{
|
||||||
iscsi->chap_auth = auth;
|
iscsi->chap_auth = auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user