Merge with IET r160-168: add iscsi-scst-adm support to display list of CHAP accounts...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 29 Jan 2009 12:12:42 +0000 (12:12 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 29 Jan 2009 12:12:42 +0000 (12:12 +0000)
git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@646 d57e44dd-8a1f-0410-8b47-8ef2f437770f

iscsi-scst/doc/manpages/iscsi-scst-adm.8
iscsi-scst/usr/config.h
iscsi-scst/usr/iscsi_adm.c
iscsi-scst/usr/iscsi_adm.h
iscsi-scst/usr/message.c
iscsi-scst/usr/plain.c

index 4d30f85..ffea6b3 100644 (file)
@@ -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
index 9ad66b9..33cf495 100644 (file)
@@ -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);
 };
 
index d1a96ae..a300f70 100644 (file)
@@ -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(&params, ",")) != 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);
-               goto out;
+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;
        }
 
-       strncpy(req.u.acnt.user, user, sizeof(req.u.acnt.user) - 1);
+       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)
-               strncpy(req.u.acnt.pass, pass, sizeof(req.u.acnt.pass) - 1);
+               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;
+       }
+
+       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;
 }
index 3758e04..2dd651d 100644 (file)
@@ -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 {
index 88f1eef..01f5abb 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #include <sys/socket.h>
@@ -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;
 }
index d23e151..97bf51e 100644 (file)
@@ -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,
 };