diff options
-rw-r--r-- | include/iscsi_if.h | 19 | ||||
-rw-r--r-- | usr/host.c | 110 | ||||
-rw-r--r-- | usr/host.h | 1 | ||||
-rw-r--r-- | usr/idbm.c | 8 | ||||
-rw-r--r-- | usr/idbm.h | 1 | ||||
-rw-r--r-- | usr/iscsi_ipc.h | 3 | ||||
-rw-r--r-- | usr/iscsiadm.c | 207 | ||||
-rw-r--r-- | usr/netlink.c | 25 |
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 { @@ -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; +} @@ -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 @@ -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; } @@ -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, ¶m_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, + ¶m_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, ¶ms); 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, ¶ms); 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, |