]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: cli: handle CLI level from the master CLI
authorWilliam Lallemand <wlallemand@haproxy.com>
Thu, 13 Dec 2018 08:05:47 +0000 (09:05 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 13 Dec 2018 08:45:16 +0000 (09:45 +0100)
Handle the CLI level in the master CLI. In order to do this, the master
CLI stores the level in the stream. Each command are prefixed by a
"user" or "operator" command before they are forwarded to the target
CLI.

The level can be configured in the haproxy program arguments with the
level keyword: -S /tmp/sock,level,admin -S /tmp/sock2,level,user.

doc/management.txt
include/types/stream.h
src/cli.c

index 24a253faf3d07b19ca790f2d50912d5c16fe1e15..ff98b7498933c9483e2631b8812266539bf96878 100644 (file)
@@ -2517,6 +2517,7 @@ Example:
 
    # haproxy -W -S 127.0.0.1:1234 -f test1.cfg
    # haproxy -Ws -S /tmp/master-socket,uid,1000,gid,1000,mode,600 -f test1.cfg
+   # haproxy -W -S /tmp/master-socket,level,user -f test1.cfg
 
 The master CLI introduces a new 'show proc' command to surpervise the
 processes:
index cdd6a51197ec90ad0028a12b05da847b0871e092..5e854c54bb29d94bd841b97321068afd105305e7 100644 (file)
@@ -94,6 +94,7 @@
 
 
 /* flags for the proxy of the master CLI */
+/* 0x1.. to 0x3 are reserved for ACCESS_LVL_MASK */
 
 #define PCLI_F_PROMPT          0x4
 #define PCLI_F_PAYLOAD         0x8
index 9a8a636461b43146f644fb9fe3cd883ff2979fe0..2299c1cf8698fbfa465509f772c1becd89b021d8 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -391,6 +391,15 @@ int cli_has_level(struct appctx *appctx, int level)
        return 1;
 }
 
+/* same as cli_has_level but for the CLI proxy and without error message */
+int pcli_has_level(struct stream *s, int level)
+{
+       if ((s->pcli_flags & ACCESS_LVL_MASK) < level) {
+               return 0;
+       }
+       return 1;
+}
+
 /* Returns severity_output for the current session if set, or default for the socket */
 static int cli_get_severity_output(struct appctx *appctx)
 {
@@ -1841,6 +1850,23 @@ int pcli_find_and_exec_kw(struct stream *s, char **args, int argl, char **errmsg
                channel_shutr_now(&s->req);
                channel_shutw_now(&s->res);
                return argl; /* return the number of elements in the array */
+       } else if (!strcmp(args[0], "operator")) {
+               if (!pcli_has_level(s, ACCESS_LVL_OPER)) {
+                       memprintf(errmsg, "Permission denied!\n");
+                       return -1;
+               }
+               s->pcli_flags &= ~ACCESS_LVL_MASK;
+               s->pcli_flags |= ACCESS_LVL_OPER;
+               return argl;
+
+       } else if (!strcmp(args[0], "user")) {
+               if (!pcli_has_level(s, ACCESS_LVL_USER)) {
+                       memprintf(errmsg, "Permission denied!\n");
+                       return -1;
+               }
+               s->pcli_flags &= ~ACCESS_LVL_MASK;
+               s->pcli_flags |= ACCESS_LVL_USER;
+               return argl;
        }
 
        return 0;
@@ -1866,6 +1892,7 @@ int pcli_parse_request(struct stream *s, struct channel *req, char **errmsg, int
        char *payload = NULL;
        int wtrim = 0; /* number of words to trim */
        int reql = 0;
+       int ret;
        int i = 0;
 
        p = str;
@@ -1974,15 +2001,29 @@ int pcli_parse_request(struct stream *s, struct channel *req, char **errmsg, int
 
                b_del(&req->buf, trim - str);
 
-               return end - trim;
+               ret = end - trim;
        } else if (wtrim < 0) {
                /* parsing error */
                return -1;
+       } else {
+               /* the whole string */
+               ret = end - str;
+       }
+
+       if (ret > 1) {
+               if (pcli_has_level(s, ACCESS_LVL_ADMIN)) {
+                       goto end;
+               } else if (pcli_has_level(s, ACCESS_LVL_OPER)) {
+                       ci_insert_line2(req, 0, "operator", strlen("operator"));
+                       ret += strlen("operator") + 2;
+               } else if (pcli_has_level(s, ACCESS_LVL_USER)) {
+                       ci_insert_line2(req, 0, "user", strlen("user"));
+                       ret += strlen("user") + 2;
+               }
        }
+end:
 
-       /* foward the whole comand */
-       return end - str;
-
+       return ret;
 }
 
 int pcli_wait_for_request(struct stream *s, struct channel *req, int an_bit)
@@ -1991,6 +2032,9 @@ int pcli_wait_for_request(struct stream *s, struct channel *req, int an_bit)
        int to_forward;
        char *errmsg = NULL;
 
+       if ((s->pcli_flags & ACCESS_LVL_MASK) == ACCESS_LVL_NONE)
+               s->pcli_flags |= strm_li(s)->bind_conf->level & ACCESS_LVL_MASK;
+
 read_again:
        /* if the channel is closed for read, we won't receive any more data
           from the client, but we don't want to forward this close to the