summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/iscsi_if.h19
-rw-r--r--usr/host.c110
-rw-r--r--usr/host.h1
-rw-r--r--usr/idbm.c8
-rw-r--r--usr/idbm.h1
-rw-r--r--usr/iscsi_ipc.h3
-rw-r--r--usr/iscsiadm.c207
-rw-r--r--usr/netlink.c25
8 files changed, 360 insertions, 14 deletions
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
index 01d38e7..0284662 100644
--- a/include/iscsi_if.h
+++ b/include/iscsi_if.h
@@ -74,8 +74,9 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_LOGIN_FLASHNODE = UEVENT_BASE + 28,
ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29,
ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30,
+ ISCSI_UEVENT_SET_CHAP = UEVENT_BASE + 31,
- ISCSI_UEVENT_MAX = ISCSI_UEVENT_LOGOUT_FLASHNODE_SID,
+ ISCSI_UEVENT_MAX = ISCSI_UEVENT_SET_CHAP,
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -318,8 +319,16 @@ enum iscsi_param_type {
ISCSI_HOST_PARAM, /* iscsi_host_param */
ISCSI_NET_PARAM, /* iscsi_net_param */
ISCSI_FLASHNODE_PARAM, /* iscsi_flashnode_param */
+ ISCSI_CHAP_PARAM, /* iscsi_chap_param */
};
+/* structure for minimalist usecase */
+struct iscsi_param_info {
+ uint32_t len; /* Actual length of the param value */
+ uint16_t param; /* iscsi param */
+ uint8_t value[0]; /* length sized value follows */
+} __attribute__((__packed__));
+
struct iscsi_iface_param_info {
uint32_t iface_num; /* iface number, 0 - n */
uint32_t len; /* Actual length of the param */
@@ -748,6 +757,14 @@ enum chap_type_e {
CHAP_TYPE_IN,
};
+enum iscsi_chap_param {
+ ISCSI_CHAP_PARAM_INDEX,
+ ISCSI_CHAP_PARAM_CHAP_TYPE,
+ ISCSI_CHAP_PARAM_USERNAME,
+ ISCSI_CHAP_PARAM_PASSWORD,
+ ISCSI_CHAP_PARAM_PASSWORD_LEN
+};
+
#define ISCSI_CHAP_AUTH_NAME_MAX_LEN 256
#define ISCSI_CHAP_AUTH_SECRET_MAX_LEN 256
struct iscsi_chap_rec {
diff --git a/usr/host.c b/usr/host.c
index 1fcb350..f2052d3 100644
--- a/usr/host.c
+++ b/usr/host.c
@@ -34,6 +34,7 @@
#include "initiator.h"
#include "iface.h"
#include "iscsi_err.h"
+#include "iscsi_netlink.h"
static int match_host_to_session(void *data, struct session_info *info)
{
@@ -314,3 +315,112 @@ int host_info_print(int info_level, uint32_t host_no)
}
return 0;
}
+
+static int chap_fill_param_uint(struct iovec *iov, int param,
+ uint32_t param_val, int param_len)
+{
+ struct iscsi_param_info *param_info;
+ struct nlattr *attr;
+ int len;
+ uint8_t val8 = 0;
+ uint16_t val16 = 0;
+ uint32_t val32 = 0;
+ char *val = NULL;
+
+ len = sizeof(struct iscsi_param_info) + param_len;
+ iov->iov_base = iscsi_nla_alloc(param, len);
+ if (!iov->iov_base)
+ return 1;
+
+ attr = iov->iov_base;
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
+
+ param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr);
+ param_info->param = param;
+ param_info->len = param_len;
+
+ switch (param_len) {
+ case 1:
+ val8 = (uint8_t)param_val;
+ val = (char *)&val8;
+ break;
+
+ case 2:
+ val16 = (uint16_t)param_val;
+ val = (char *)&val16;
+ break;
+
+ case 4:
+ val32 = (uint32_t)param_val;
+ val = (char *)&val32;
+ break;
+
+ default:
+ goto free;
+ }
+ memcpy(param_info->value, val, param_len);
+
+ return 0;
+
+free:
+ free(iov->iov_base);
+ iov->iov_base = NULL;
+ iov->iov_len = 0;
+ return 1;
+}
+
+static int chap_fill_param_str(struct iovec *iov, int param, char *param_val,
+ int param_len)
+{
+ struct iscsi_param_info *param_info;
+ struct nlattr *attr;
+ int len;
+
+ len = sizeof(struct iscsi_param_info) + param_len;
+ iov->iov_base = iscsi_nla_alloc(param, len);
+ if (!iov->iov_base)
+ return 1;
+
+ attr = iov->iov_base;
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
+
+ param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr);
+ param_info->param = param;
+ param_info->len = param_len;
+ memcpy(param_info->value, param_val, param_len);
+ return 0;
+}
+
+int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs)
+{
+ struct iovec *iov = NULL;
+ int count = 0;
+
+ /* start at 2, because 0 is for nlmsghdr and 1 for event */
+ iov = iovs + 2;
+
+ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_INDEX,
+ crec->chap_tbl_idx,
+ sizeof(crec->chap_tbl_idx)))
+ count++;
+
+ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_CHAP_TYPE,
+ crec->chap_type, sizeof(crec->chap_type)))
+ count++;
+
+ if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_USERNAME,
+ crec->username, strlen(crec->username)))
+ count++;
+
+ if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_PASSWORD,
+ (char *)crec->password,
+ strlen((char *)crec->password)))
+ count++;
+
+ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_PASSWORD_LEN,
+ crec->password_length,
+ sizeof(crec->password_length)))
+ count++;
+
+ return count;
+}
diff --git a/usr/host.h b/usr/host.h
index 52e5b9e..149aa0d 100644
--- a/usr/host.h
+++ b/usr/host.h
@@ -17,5 +17,6 @@ struct host_info {
};
extern int host_info_print(int info_level, uint32_t host_no);
+extern int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs);
#endif
diff --git a/usr/idbm.c b/usr/idbm.c
index 1e4f8c8..6b6f57c 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -456,7 +456,7 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
__recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1);
}
-static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
+void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
{
int num = 0;
@@ -465,14 +465,14 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
if (r->chap_type == CHAP_TYPE_OUT) {
__recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW,
- num, 0);
+ num, 1);
__recinfo_str(HOST_AUTH_PASSWORD, ri, r, password, IDBM_MASKED,
num, 1);
__recinfo_int(HOST_AUTH_PASSWORD_LEN, ri, r, password_length,
IDBM_HIDE, num, 1);
} else {
__recinfo_str(HOST_AUTH_USERNAME_IN, ri, r, username, IDBM_SHOW,
- num, 0);
+ num, 1);
__recinfo_str(HOST_AUTH_PASSWORD_IN, ri, r, password,
IDBM_MASKED, num, 1);
__recinfo_int(HOST_AUTH_PASSWORD_IN_LEN, ri, r, password_length,
@@ -852,6 +852,8 @@ updated:
check_password_param(discovery.sendtargets.auth.password_in);
check_password_param(discovery.slp.auth.password);
check_password_param(discovery.slp.auth.password_in);
+ check_password_param(host.auth.password);
+ check_password_param(host.auth.password_in);
return 0;
}
diff --git a/usr/idbm.h b/usr/idbm.h
index 5e4038d..b9020fe 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -185,6 +185,7 @@ extern struct node_rec *
idbm_create_rec_from_boot_context(struct boot_context *context);
extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap);
+extern void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri);
extern int idbm_print_flashnode_info(struct flashnode_rec *target);
extern void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri);
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
index b6665cb..a32da1c 100644
--- a/usr/iscsi_ipc.h
+++ b/usr/iscsi_ipc.h
@@ -143,6 +143,9 @@ struct iscsi_ipc {
uint16_t chap_tbl_idx, uint32_t num_entries,
char *chap_buf, uint32_t *valid_chap_entries);
+ int (*set_chap) (uint64_t transport_handle, uint32_t host_no,
+ struct iovec *iovs, uint32_t param_count);
+
int (*delete_chap) (uint64_t transport_handle, uint32_t host_no,
uint16_t chap_tbl_idx);
int (*set_flash_node_params) (uint64_t transport_handle,
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index beabdf0..045259b 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -115,7 +115,7 @@ static struct option const long_options[] =
{"packetsize", required_argument, NULL, 'b'},
{"count", required_argument, NULL, 'c'},
{"interval", required_argument, NULL, 'i'},
- {"index", optional_argument, NULL, 'x'},
+ {"index", required_argument, NULL, 'x'},
{"portal_type", optional_argument, NULL, 'A'},
{NULL, 0, NULL, 0},
};
@@ -1426,11 +1426,193 @@ exit_chap_info:
return rc;
}
+static int fill_host_chap_rec(struct list_head *params,
+ struct iscsi_chap_rec *crec, recinfo_t *cinfo,
+ uint16_t chap_tbl_idx, int type, int *param_count)
+{
+ struct user_param *param;
+ int rc = 0;
+
+ crec->chap_tbl_idx = chap_tbl_idx;
+ crec->chap_type = type;
+
+ idbm_recinfo_host_chap(crec, cinfo);
+
+ list_for_each_entry(param, params, list) {
+ rc = idbm_rec_update_param(cinfo, param->name, param->value, 0);
+ if (rc)
+ break;
+ }
+
+ if (!rc)
+ *param_count += 3; /* index, type and password_length */
+
+ return rc;
+}
+
+static int verify_host_chap_params(struct list_head *params, int *type,
+ int *param_count)
+{
+ struct user_param *param;
+ int username = -1;
+ int password = -1;
+ int rc = 0;
+
+ list_for_each_entry(param, params, list) {
+ *param_count += 1;
+
+ if (!strcmp(param->name, HOST_AUTH_USERNAME))
+ username = CHAP_TYPE_OUT;
+ else if (!strcmp(param->name, HOST_AUTH_PASSWORD))
+ password = CHAP_TYPE_OUT;
+ else if (!strcmp(param->name, HOST_AUTH_USERNAME_IN))
+ username = CHAP_TYPE_IN;
+ else if (!strcmp(param->name, HOST_AUTH_PASSWORD_IN))
+ password = CHAP_TYPE_IN;
+ else
+ continue;
+ }
+
+ if ((username == CHAP_TYPE_OUT) && (password == CHAP_TYPE_OUT)) {
+ if (type)
+ *type = CHAP_TYPE_OUT;
+
+ rc = ISCSI_SUCCESS;
+ } else if ((username == CHAP_TYPE_IN) && (password == CHAP_TYPE_IN)) {
+ if (type)
+ *type = CHAP_TYPE_IN;
+
+ rc = ISCSI_SUCCESS;
+ } else {
+ rc = ISCSI_ERR;
+ }
+
+ return rc;
+}
+
+static int set_host_chap_info(uint32_t host_no, uint64_t chap_index,
+ struct list_head *params)
+{
+ struct iscsi_transport *t = NULL;
+ struct iscsi_chap_rec crec;
+ recinfo_t *chap_info = NULL;
+ struct iovec *iovs = NULL;
+ struct iovec *iov = NULL;
+ int type;
+ int param_count;
+ int param_used;
+ int rc = 0;
+ int fd, i = 0;
+
+ if (list_empty(params)) {
+ log_error("Chap username/password not provided.");
+ goto exit_set_chap;
+ }
+
+ chap_info = idbm_recinfo_alloc(MAX_KEYS);
+ if (!chap_info) {
+ log_error("Out of Memory.");
+ rc = ISCSI_ERR_NOMEM;
+ goto exit_set_chap;
+ }
+
+ t = iscsi_sysfs_get_transport_by_hba(host_no);
+ if (!t) {
+ log_error("Could not match hostno %d to transport.", host_no);
+ rc = ISCSI_ERR_TRANS_NOT_FOUND;
+ goto free_info_rec;
+ }
+
+ rc = verify_host_chap_params(params, &type, &param_count);
+ if (rc) {
+ log_error("Invalid username/password pair passed. Unable to determine the type of chap entry");
+ rc = ISCSI_ERR_INVAL;
+ goto free_info_rec;
+ }
+
+ if (param_count > 2) {
+ log_error("Only one pair of username/password can be passed.");
+ rc = ISCSI_ERR;
+ goto free_info_rec;
+ }
+
+ memset(&crec, 0, sizeof(crec));
+ rc = fill_host_chap_rec(params, &crec, chap_info, chap_index, type,
+ &param_count);
+ if (rc) {
+ log_error("Unable to fill CHAP record");
+ goto free_info_rec;
+ }
+
+ /* +2 for event and nlmsghdr */
+ param_count += 2;
+ iovs = calloc((param_count * sizeof(struct iovec)),
+ sizeof(char));
+ if (!iovs) {
+ log_error("Out of Memory.");
+ rc = ISCSI_ERR_NOMEM;
+ goto free_info_rec;
+ }
+
+ /* param_used gives actual number of iovecs used for chap */
+ param_used = chap_build_config(&crec, iovs);
+ if (!param_used) {
+ log_error("Build chap config failed.");
+ rc = ISCSI_ERR;
+ goto free_iovec;
+ }
+
+ fd = ipc->ctldev_open();
+ if (fd < 0) {
+ rc = ISCSI_ERR_INTERNAL;
+ log_error("Netlink open failed.");
+ goto free_iovec;
+ }
+
+ rc = ipc->set_chap(t->handle, host_no, iovs, param_count);
+ if (rc < 0) {
+ log_error("CHAP setting failed");
+ if (rc == -EBUSY) {
+ rc = ISCSI_ERR_BUSY;
+ log_error("CHAP index %d is in use.",
+ crec.chap_tbl_idx);
+ } else {
+ rc = ISCSI_ERR;
+ }
+
+ goto exit_set_chap;
+ }
+
+ ipc->ctldev_close();
+
+free_iovec:
+ /* start at 2, because 0 is for nlmsghdr and 1 for event */
+ iov = iovs + 2;
+ for (i = 0; i < param_used; i++, iov++) {
+ if (iov->iov_base)
+ free(iov->iov_base);
+ }
+
+ free(iovs);
+
+free_info_rec:
+ if (chap_info)
+ free(chap_info);
+
+exit_set_chap:
+ return rc;
+}
+
static int delete_host_chap_info(uint32_t host_no, uint16_t chap_tbl_idx)
{
struct iscsi_transport *t = NULL;
int fd, rc = 0;
+ if (chap_tbl_idx > MAX_CHAP_ENTRIES) {
+ log_error("Invalid chap table index.");
+ goto exit_delete_chap;
+ }
+
t = iscsi_sysfs_get_transport_by_hba(host_no);
if (!t) {
log_error("Could not match hostno %d to "
@@ -1464,19 +1646,18 @@ exit_delete_chap:
}
static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
- uint64_t chap_index)
+ uint64_t chap_index, struct list_head *params)
{
int rc = ISCSI_ERR_INVAL;
- if (op != OP_SHOW && (chap_index > (uint64_t)MAX_CHAP_ENTRIES)) {
- log_error("Invalid chap table index.");
- goto exit_chap_op;
- }
-
switch (op) {
case OP_SHOW:
rc = get_host_chap_info(host_no);
break;
+ case OP_NEW:
+ case OP_UPDATE:
+ rc = set_host_chap_info(host_no, chap_index, params);
+ break;
case OP_DELETE:
rc = delete_host_chap_info(host_no, chap_index);
break;
@@ -1485,7 +1666,6 @@ static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
break;
}
-exit_chap_op:
return rc;
}
@@ -2816,7 +2996,7 @@ main(int argc, char **argv)
struct iface_rec *iface = NULL, *tmp;
struct node_rec *rec = NULL;
uint64_t host_no = (uint64_t)MAX_HOST_NO + 1;
- uint64_t index = (uint64_t)MAX_FLASHNODE_IDX + 1;
+ uint64_t index = ULLONG_MAX;
struct user_param *param;
struct list_head params;
@@ -3038,8 +3218,12 @@ main(int argc, char **argv)
rc = ISCSI_ERR_INVAL;
break;
}
+
+ if (index == ULLONG_MAX)
+ index = (uint64_t)MAX_CHAP_ENTRIES + 1;
+
rc = exec_host_chap_op(op, info_level, host_no,
- index);
+ index, &params);
break;
case MODE_FLASHNODE:
if (host_no > MAX_HOST_NO) {
@@ -3048,6 +3232,9 @@ main(int argc, char **argv)
break;
}
+ if (index == ULLONG_MAX)
+ index = (uint64_t)MAX_FLASHNODE_IDX + 1;
+
rc = exec_flashnode_op(op, info_level, host_no,
index, portal_type,
&params);
diff --git a/usr/netlink.c b/usr/netlink.c
index c07fe3c..151b56d 100644
--- a/usr/netlink.c
+++ b/usr/netlink.c
@@ -1228,6 +1228,30 @@ static int kget_chap(uint64_t transport_handle, uint32_t host_no,
return rc;
}
+static int kset_chap(uint64_t transport_handle, uint32_t host_no,
+ struct iovec *iovs, uint32_t param_count)
+{
+ int rc, ev_len;
+ struct iscsi_uevent ev;
+ struct iovec *iov = iovs + 1;
+
+ log_debug(8, "in %s", __func__);
+
+ ev_len = sizeof(ev);
+ ev.type = ISCSI_UEVENT_SET_CHAP;
+ ev.transport_handle = transport_handle;
+ ev.u.set_path.host_no = host_no;
+
+ iov->iov_base = &ev;
+ iov->iov_len = sizeof(ev);
+
+ rc = __kipc_call(iovs, param_count);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
static int kdelete_chap(uint64_t transport_handle, uint32_t host_no,
uint16_t chap_tbl_idx)
{
@@ -1705,6 +1729,7 @@ struct iscsi_ipc nl_ipc = {
.recv_conn_state = krecv_conn_state,
.exec_ping = kexec_ping,
.get_chap = kget_chap,
+ .set_chap = kset_chap,
.delete_chap = kdelete_chap,
.set_flash_node_params = kset_flashnode_params,
.new_flash_node = knew_flashnode,