From 04041fa3f1b6afef9eedd4a114e32d89279446f1 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 29 Jan 2009 12:12:42 +0000 Subject: [PATCH] Merge with IET r160-168: add iscsi-scst-adm support to display list of CHAP accounts and their data git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@646 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/doc/manpages/iscsi-scst-adm.8 | 13 +- iscsi-scst/usr/config.h | 1 + iscsi-scst/usr/iscsi_adm.c | 253 ++++++++++++++++++----- iscsi-scst/usr/iscsi_adm.h | 15 +- iscsi-scst/usr/message.c | 44 +++- iscsi-scst/usr/plain.c | 25 +++ 6 files changed, 291 insertions(+), 60 deletions(-) diff --git a/iscsi-scst/doc/manpages/iscsi-scst-adm.8 b/iscsi-scst/doc/manpages/iscsi-scst-adm.8 index 4d30f8598..ffea6b3fd 100644 --- a/iscsi-scst/doc/manpages/iscsi-scst-adm.8 +++ b/iscsi-scst/doc/manpages/iscsi-scst-adm.8 @@ -153,7 +153,7 @@ display status of target 1 (see /proc/scsi_tgt/iscsi to get the matching target create dynamically a new target, numbered 2. \s-1CAUTION\s0 : the target will disappear if you restart iscsi-scstd, you'll have to edit /etc/iscsi-scstd.conf to make it permanent! .SH "ERROR MESSAGES" .IX Header "ERROR MESSAGES" -iscsi-scst-adm misses error messages. Look carefully the \s-1STDERR\s0 output : in case of error +iscsi-scst-adm misses error messages. Look carefully at the \s-1STDERR\s0 output : in case of error it will send a 3 number error code, ending with \-1, for instance : .PP iscsi-scstd_request 203 3 \-1 @@ -203,6 +203,17 @@ add a new account with [pass] for specific target. If you don't specify a target (omit \-\-tid option), you add a new account for discovery sessions. .PP +\&\fB\-\-op show \-\-tid=[id] \-\-user\fR +.PP +show a list of CHAP accounts. +If \-\-tid is omitted or [id] is \*(L"0\*(R" (zero), discovery accounts are displayed. +.PP +\&\fB\-\-op show \-\-tid=[id] \-\-user \-\-params=[user]=[name]\fR +.PP +show CHAP account information for the account specified by [name]. +[user] can be [IncomingUser] or [OutgoingUser]. +If \-\-tid is omitted or [id] is \*(L"0\*(R" (zero), [name] is supposed to be a discovery account name. +.PP \&\fB\-\-op delete \-\-tid=[id] \-\-user \-\-params=[user]=[name]\fR .PP delete specific account having [name] of specific diff --git a/iscsi-scst/usr/config.h b/iscsi-scst/usr/config.h index 9ad66b9a2..33cf495f6 100644 --- a/iscsi-scst/usr/config.h +++ b/iscsi-scst/usr/config.h @@ -26,6 +26,7 @@ struct config_operations { int (*account_add) (u32, int, char *, char *); int (*account_del) (u32, int, char *); int (*account_query) (u32, int, char *, char *); + int (*account_list) (u32, int, u32 *, u32 *, char *, size_t); int (*initiator_access) (u32, int); }; diff --git a/iscsi-scst/usr/iscsi_adm.c b/iscsi-scst/usr/iscsi_adm.c index d1a96ae91..a300f70fd 100644 --- a/iscsi-scst/usr/iscsi_adm.c +++ b/iscsi-scst/usr/iscsi_adm.c @@ -37,6 +37,8 @@ #define SET_CONNECTION (1 << 2) #define SET_USER (1 << 4) +typedef int (user_handle_fn_t)(struct iscsi_adm_req *req, char *user, char *pass); + enum iscsi_adm_op { OP_NEW, OP_DELETE, @@ -79,6 +81,14 @@ iSCSI-SCST Target Administration Utility.\n\ show iSCSI parameters in effect for session [sid]. If\n\ [sid] is \"0\" (zero), the configured parameters\n\ will be displayed.\n\ + --op show --tid=[id] --user\n\ + show list of Discovery (--tid omitted / id=0 (zero))\n\ + or target CHAP accounts.\n\ + --op show --tid=[id] --user --params=[user]=[name]\n\ + show CHAP account information. [user] can be\n\ + \"IncomingUser\" or \"OutgoingUser\". If --tid is\n\ + omitted / id=0 (zero), [user] is treated as Discovery\n\ + user.\n\ --op delete --tid=[id] --sid=[sid] --cid=[cid]\n\ delete specific connection with [cid] in a session\n\ with [sid] that the target with [id] has.\n\ @@ -145,7 +155,8 @@ static int iscsid_request_send(int fd, struct iscsi_adm_req *req) return err; } -static int iscsid_response_recv(int fd, struct iscsi_adm_req *req) +static int iscsid_response_recv(int fd, struct iscsi_adm_req *req, void *rsp_data, + size_t rsp_data_sz) { int err, ret; struct iovec iov[2]; @@ -167,6 +178,15 @@ static int iscsid_response_recv(int fd, struct iscsi_adm_req *req) } else err = rsp.err; + if (!err && rsp_data_sz && rsp_data) { + ret = read(fd, rsp_data, rsp_data_sz); + if (ret != rsp_data_sz) { + err = (ret < 0) ? -errno : -EIO; + fprintf(stderr, "%s %d %d %d\n", __FUNCTION__, + __LINE__, ret, err); + } + } + return err; } @@ -189,7 +209,8 @@ static int iscsid_connect(void) return fd; } -static int iscsid_request(struct iscsi_adm_req *req) +static int iscsid_request(struct iscsi_adm_req *req, void *rsp_data, + size_t rsp_data_sz) { int fd = -1, err = -EIO; @@ -201,7 +222,7 @@ static int iscsid_request(struct iscsi_adm_req *req) if ((err = iscsid_request_send(fd, req)) < 0) goto out; - err = iscsid_response_recv(fd, req); + err = iscsid_response_recv(fd, req, rsp_data, rsp_data_sz); out: if (fd > 0) @@ -324,7 +345,7 @@ static int trgt_handle(int op, u32 set, u32 tid, char *params) break; } - err = iscsid_request(&req); + err = iscsid_request(&req, NULL, 0); if (!err && req.rcmnd == C_TRGT_SHOW) show_iscsi_param(key_target, req.u.trgt.target_param); @@ -355,7 +376,7 @@ static int sess_handle(int op, u32 set, u32 tid, u64 sid, char *params) break; case OP_SHOW: req.rcmnd = C_SESS_SHOW; - err = iscsid_request(&req); + err = iscsid_request(&req, NULL, 0); if (!err) show_iscsi_param(key_session, req.u.trgt.session_param); break; @@ -365,30 +386,10 @@ out: return err; } -static int user_handle(int op, u32 set, u32 tid, char *params) +static int parse_user_params(char *params, u32 *auth_dir, char **user, + char **pass) { - int err = -EINVAL; - char *p, *q, *user = NULL, *pass = NULL; - struct iscsi_adm_req req; - - if (set & ~(SET_TARGET | SET_USER)) - goto out; - - memset(&req, 0, sizeof(req)); - req.tid = tid; - - switch (op) { - case OP_NEW: - req.rcmnd = C_ACCT_NEW; - break; - case OP_DELETE: - req.rcmnd = C_ACCT_DEL; - break; - case OP_UPDATE: - case OP_SHOW: - fprintf(stderr, "Unsupported.\n"); - goto out; - } + char *p, *q; while ((p = strsep(¶ms, ",")) != NULL) { if (!*p) @@ -401,37 +402,189 @@ static int user_handle(int op, u32 set, u32 tid, char *params) q++; if (!strcasecmp(p, "IncomingUser")) { - if (user) - fprintf(stderr, "Already specified user %s\n", q); - user = q; - req.u.acnt.auth_dir = AUTH_DIR_INCOMING; + if (*user) + fprintf(stderr, + "Already specified IncomingUser %s\n", + q); + *user = q; + *auth_dir = AUTH_DIR_INCOMING; } else if (!strcasecmp(p, "OutgoingUser")) { - if (user) - fprintf(stderr, "Already specified user %s\n", q); - user = q; - req.u.acnt.auth_dir = AUTH_DIR_OUTGOING; + if (*user) + fprintf(stderr, + "Already specified OutgoingUser %s\n", + q); + *user = q; + *auth_dir = AUTH_DIR_OUTGOING; } else if (!strcasecmp(p, "Password")) { - if (pass) - fprintf(stderr, "Already specified pass %s\n", q); - pass = q; + if (*pass) + fprintf(stderr, + "Already specified Password %s\n", q); + *pass = q; } else { fprintf(stderr, "Unknown parameter %p\n", q); - goto out; + return -EINVAL; } } + return 0; +} - if ((op == OP_NEW && ((user && !pass) || (!user && pass) || (!user && !pass))) || - (op == OP_DELETE && ((!user && pass) || (!user && !pass)))) { - fprintf(stderr, - "You need to specify a user and its password %s %s\n", pass, user); +static void show_account(int auth_dir, char *user, char *pass) +{ + char buf[(ISCSI_NAME_LEN + 1) * 2] = {0}; + + snprintf(buf, ISCSI_NAME_LEN, "%s", user); + if (pass) + snprintf(buf + strlen(buf), ISCSI_NAME_LEN, " %s", pass); + + printf("%sUser %s\n", (auth_dir == AUTH_DIR_INCOMING) ? + "Incoming" : "Outgoing", buf); +} + +static int user_handle_show_user(struct iscsi_adm_req *req, char *user) +{ + int err; + + req->rcmnd = C_ACCT_SHOW; + strncpy(req->u.acnt.u.user.name, user, + sizeof(req->u.acnt.u.user.name) - 1); + + err = iscsid_request(req, NULL, 0); + if (!err) + show_account(req->u.acnt.auth_dir, req->u.acnt.u.user.name, + req->u.acnt.u.user.pass); + + return err; +} + +static int user_handle_show_list(struct iscsi_adm_req *req) +{ + int i, err, retry; + size_t buf_sz = 0; + char *buf; + + req->u.acnt.auth_dir = AUTH_DIR_INCOMING; + req->rcmnd = C_ACCT_LIST; + + do { + retry = 0; + + buf_sz = buf_sz ? buf_sz : ISCSI_NAME_LEN; + + buf = calloc(buf_sz, sizeof(char *)); + if (!buf) { + fprintf(stderr, "Memory allocation failed\n"); + return -ENOMEM; + } + + req->u.acnt.u.list.alloc_len = buf_sz; + + err = iscsid_request(req, buf, buf_sz); + if (err) { + free(buf); + break; + } + + if (req->u.acnt.u.list.overflow) { + buf_sz = ISCSI_NAME_LEN * (req->u.acnt.u.list.count + + req->u.acnt.u.list.overflow); + retry = 1; + free(buf); + continue; + } + + for (i = 0; i < req->u.acnt.u.list.count; i++) + show_account(req->u.acnt.auth_dir, + &buf[i * ISCSI_NAME_LEN], NULL); + + if (req->u.acnt.auth_dir == AUTH_DIR_INCOMING) { + req->u.acnt.auth_dir = AUTH_DIR_OUTGOING; + buf_sz = 0; + retry = 1; + } + + free(buf); + + } while (retry); + + return err; +} + +static int user_handle_show(struct iscsi_adm_req *req, char *user, char *pass) +{ + if (pass) + fprintf(stderr, "Ignoring specified password\n"); + + if (user) + return user_handle_show_user(req, user); + else + return user_handle_show_list(req); +} + +static int user_handle_new(struct iscsi_adm_req *req, char *user, char *pass) +{ + if (!user || !pass) { + fprintf(stderr, "Username and password must be specified\n"); + return -EINVAL; + } + + req->rcmnd = C_ACCT_NEW; + + strncpy(req->u.acnt.u.user.name, user, + sizeof(req->u.acnt.u.user.name) - 1); + strncpy(req->u.acnt.u.user.pass, pass, + sizeof(req->u.acnt.u.user.pass) - 1); + + return iscsid_request(req, NULL, 0); +} + +static int user_handle_del(struct iscsi_adm_req *req, char *user, char *pass) +{ + if (!user) { + fprintf(stderr, "Username must be specified\n"); + return -EINVAL; + } + + if (pass) + fprintf(stderr, "Ignoring specified password\n"); + + req->rcmnd = C_ACCT_DEL; + + strncpy(req->u.acnt.u.user.name, user, + sizeof(req->u.acnt.u.user.name) - 1); + + return iscsid_request(req, NULL, 0); +} + +static int user_handle(int op, u32 set, u32 tid, char *params) +{ + int err = -EINVAL; + char *user = NULL, *pass = NULL; + struct iscsi_adm_req req; + static user_handle_fn_t *user_handle_fn[] = { + user_handle_new, + user_handle_del, + NULL, + user_handle_show, + }, *fn; + + if (set & ~(SET_TARGET | SET_USER)) + goto out; + + memset(&req, 0, sizeof(req)); + req.tid = tid; + + err = parse_user_params(params, &req.u.acnt.auth_dir, &user, &pass); + if (err) + goto out; + + if ((op >= sizeof(user_handle_fn)/sizeof(user_handle_fn[0])) || + ((fn = user_handle_fn[op]) == NULL)) { + fprintf(stderr, "Unsupported\n"); goto out; } - strncpy(req.u.acnt.user, user, sizeof(req.u.acnt.user) - 1); - if (pass) - strncpy(req.u.acnt.pass, pass, sizeof(req.u.acnt.pass) - 1); + err = fn(&req, user, pass); - err = iscsid_request(&req); out: return err; } @@ -464,7 +617,7 @@ static int conn_handle(int op, u32 set, u32 tid, u64 sid, u32 cid, char *params) break; } - err = iscsid_request(&req); + err = iscsid_request(&req, NULL, 0); out: return err; } @@ -488,7 +641,7 @@ static int sys_handle(int op, u32 set, char *params) break; } - err = iscsid_request(&req); + err = iscsid_request(&req, NULL, 0); return err; } diff --git a/iscsi-scst/usr/iscsi_adm.h b/iscsi-scst/usr/iscsi_adm.h index 3758e0408..2dd651d37 100644 --- a/iscsi-scst/usr/iscsi_adm.h +++ b/iscsi-scst/usr/iscsi_adm.h @@ -31,8 +31,17 @@ struct msg_trgt { struct msg_acnt { u32 auth_dir; - char user[ISCSI_NAME_LEN]; - char pass[ISCSI_NAME_LEN]; + union { + struct { + char name[ISCSI_NAME_LEN]; + char pass[ISCSI_NAME_LEN]; + } user; + struct { + u32 alloc_len; + u32 count; + u32 overflow; + } list; + } u; }; enum iscsi_adm_cmnd { @@ -60,6 +69,8 @@ enum iscsi_adm_cmnd { C_SYS_DEL, C_SYS_UPDATE, C_SYS_SHOW, + + C_ACCT_LIST, }; struct iscsi_adm_req { diff --git a/iscsi-scst/usr/message.c b/iscsi-scst/usr/message.c index 88f1eef0e..01f5abbb3 100644 --- a/iscsi-scst/usr/message.c +++ b/iscsi-scst/usr/message.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -47,7 +48,8 @@ int iscsi_adm_request_listen(void) return fd; } -static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_rsp *rsp) +static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_rsp *rsp, + void **rsp_data, size_t *rsp_data_sz) { int err = 0; @@ -102,14 +104,35 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r break; case C_ACCT_NEW: - err = cops->account_add(req->tid, req->u.acnt.auth_dir, req->u.acnt.user, - req->u.acnt.pass); + err = cops->account_add(req->tid, req->u.acnt.auth_dir, + req->u.acnt.u.user.name, + req->u.acnt.u.user.pass); break; case C_ACCT_DEL: - err = cops->account_del(req->tid, req->u.acnt.auth_dir, req->u.acnt.user); + err = cops->account_del(req->tid, req->u.acnt.auth_dir, + req->u.acnt.u.user.name); + break; + case C_ACCT_LIST: + *rsp_data = malloc(req->u.acnt.u.list.alloc_len); + if (!*rsp_data) { + err = -ENOMEM; + break; + } + + *rsp_data_sz = req->u.acnt.u.list.alloc_len; + memset(*rsp_data, 0x0, *rsp_data_sz); + + err = cops->account_list(req->tid, req->u.acnt.auth_dir, + &req->u.acnt.u.list.count, + &req->u.acnt.u.list.overflow, + *rsp_data, *rsp_data_sz); break; case C_ACCT_UPDATE: + break; case C_ACCT_SHOW: + err = cops->account_query(req->tid, req->u.acnt.auth_dir, + req->u.acnt.u.user.name, + req->u.acnt.u.user.pass); break; case C_SYS_NEW: break; @@ -135,7 +158,9 @@ int iscsi_adm_request_handle(int accept_fd) socklen_t len; struct iscsi_adm_req req; struct iscsi_adm_rsp rsp; - struct iovec iov[2]; + struct iovec iov[3]; + void *rsp_data = NULL; + size_t rsp_data_sz; memset(&rsp, 0, sizeof(rsp)); len = sizeof(addr); @@ -165,17 +190,22 @@ int iscsi_adm_request_handle(int accept_fd) goto out; } - iscsi_adm_request_exec(&req, &rsp); + iscsi_adm_request_exec(&req, &rsp, &rsp_data, &rsp_data_sz); send: iov[0].iov_base = &req; iov[0].iov_len = sizeof(req); iov[1].iov_base = &rsp; iov[1].iov_len = sizeof(rsp); + iov[2].iov_base = rsp.err ? NULL : rsp_data; + iov[2].iov_len = iov[2].iov_base ? rsp_data_sz : 0; - err = writev(fd, iov, 2); + err = writev(fd, iov, 2 + !!iov[2].iov_len); out: if (fd > 0) close(fd); + if (rsp_data) + free(rsp_data); + return err; } diff --git a/iscsi-scst/usr/plain.c b/iscsi-scst/usr/plain.c index d23e15145..97bf51e43 100644 --- a/iscsi-scst/usr/plain.c +++ b/iscsi-scst/usr/plain.c @@ -170,6 +170,30 @@ static int plain_account_query(u32 tid, int dir, char *name, char *pass) return 0; } +static int plain_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow, + char *buf, size_t buf_sz) +{ + struct __qelem *list = account_list_get(tid, dir); + struct user *user; + + *cnt = *overflow = 0; + + if (!list) + return -ENOENT; + + list_for_each_entry(user, list, ulist) { + if (buf_sz >= ISCSI_NAME_LEN) { + strncpy(buf, user->name, ISCSI_NAME_LEN); + buf_sz -= ISCSI_NAME_LEN; + buf += ISCSI_NAME_LEN; + *cnt += 1; + } else + *overflow += 1; + } + + return 0; +} + static void account_destroy(struct user *user) { if (!user) @@ -631,5 +655,6 @@ struct config_operations plain_ops = { .account_add = plain_account_add, .account_del = plain_account_del, .account_query = plain_account_query, + .account_list = plain_account_list, .initiator_access = plain_initiator_access, };