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>
|
||||
data_digest=<crc32c|none>
|
||||
auth=<md5|sha1|sha-256|sha3-256>
|
||||
force_usn=<unit_serial_number>
|
||||
|
||||
Transport:
|
||||
iser
|
||||
|
||||
|
||||
Example:
|
||||
iscsi://server/iqn.ronnie.test/1
|
||||
|
||||
@@ -193,7 +194,7 @@ To run those tests you would specify
|
||||
|
||||
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
|
||||
|
||||
Examples
|
||||
|
||||
@@ -116,6 +116,7 @@ struct iscsi_context {
|
||||
char portal[MAX_STRING_SIZE+1];
|
||||
char alias[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;
|
||||
char user[MAX_STRING_SIZE+1];
|
||||
|
||||
@@ -198,7 +198,7 @@ iscsi_get_auth(struct iscsi_context *iscsi);
|
||||
|
||||
EXTERN void
|
||||
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.
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* the target has moved.
|
||||
@@ -685,7 +703,7 @@ EXTERN void iscsi_free_discovery_data(struct iscsi_context *iscsi,
|
||||
* structure containing the data returned from
|
||||
* the server.
|
||||
* 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
|
||||
* 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
|
||||
|
||||
|
||||
count is defined as follows:
|
||||
-1 -> retry forever (default)
|
||||
0 -> never retry
|
||||
@@ -1707,7 +1725,7 @@ iscsi_set_fd_dup_cb(struct iscsi_context *iscsi,
|
||||
|
||||
/*
|
||||
* MULTITHREADING
|
||||
*/
|
||||
*/
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
EXTERN void iscsi_mt_service_thread_stop(struct iscsi_context *iscsi);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -76,6 +76,55 @@ iscsi_testunitready_connect(struct iscsi_context *iscsi, int lun,
|
||||
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
|
||||
iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *private_data)
|
||||
@@ -137,10 +186,21 @@ iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
|
||||
status = 0;
|
||||
}
|
||||
|
||||
ct->cb(iscsi, status?SCSI_STATUS_ERROR:SCSI_STATUS_GOOD, NULL,
|
||||
ct->private_data);
|
||||
scsi_free_scsi_task(task);
|
||||
iscsi_free(iscsi, ct);
|
||||
if (status != 0) {
|
||||
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||
ct->private_data);
|
||||
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
|
||||
@@ -178,8 +238,13 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
iscsi_free(iscsi, ct);
|
||||
}
|
||||
} else {
|
||||
ct->cb(iscsi, SCSI_STATUS_GOOD, NULL, ct->private_data);
|
||||
iscsi_free(iscsi, ct);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +436,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
|
||||
iscsi->frees += old_iscsi->frees;
|
||||
|
||||
free(old_iscsi);
|
||||
|
||||
|
||||
/* avoid a reconnect faster than 3 seconds */
|
||||
iscsi->next_reconnect = time(NULL) + 3;
|
||||
|
||||
@@ -443,10 +508,12 @@ static int reconnect(struct iscsi_context *iscsi, int force)
|
||||
tmp_iscsi->lun = iscsi->lun;
|
||||
|
||||
strncpy(tmp_iscsi->portal, iscsi->portal, MAX_STRING_SIZE);
|
||||
|
||||
|
||||
strncpy(tmp_iscsi->bind_interfaces, iscsi->bind_interfaces, MAX_STRING_SIZE);
|
||||
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_fn = iscsi->log_fn;
|
||||
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_keepintvl=30;
|
||||
iscsi->tcp_keepidle=30;
|
||||
|
||||
|
||||
iscsi->reconnect_max_retries = -1;
|
||||
iscsi->chap_auth = ISCSI_CHAP_MD5;
|
||||
|
||||
@@ -345,6 +345,26 @@ iscsi_set_targetname(struct iscsi_context *iscsi, const char *target_name)
|
||||
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
|
||||
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_mutex_destroy(&iscsi->iscsi_mutex);
|
||||
|
||||
|
||||
memset(iscsi, 0, sizeof(struct iscsi_context));
|
||||
free(iscsi);
|
||||
|
||||
@@ -521,6 +541,7 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
||||
char *passwd = NULL;
|
||||
char *target_user = NULL;
|
||||
char *target_passwd = NULL;
|
||||
char *usn = NULL;
|
||||
char *target = NULL;
|
||||
char *lun;
|
||||
char *tmp;
|
||||
@@ -628,6 +649,9 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
||||
iscsi->rdma_ack_timeout = atoi(value);
|
||||
#endif
|
||||
}
|
||||
if (!strcmp(key, "force_usn")) {
|
||||
usn = value;
|
||||
}
|
||||
tmp = next;
|
||||
}
|
||||
}
|
||||
@@ -691,7 +715,7 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
||||
*tmp=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (iscsi != NULL) {
|
||||
iscsi_url = iscsi_malloc(iscsi, sizeof(struct iscsi_url));
|
||||
} 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_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->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;
|
||||
@@ -854,4 +881,3 @@ iscsi_set_auth(struct iscsi_context *iscsi, enum iscsi_chap_auth auth)
|
||||
{
|
||||
iscsi->chap_auth = auth;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user