MEDIUM: cli: handle CLI level from the master CLI

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.
This commit is contained in:
William Lallemand 2018-12-13 09:05:47 +01:00 committed by Willy Tarreau
parent dc12c2e56c
commit b7ea141cbb
3 changed files with 49 additions and 3 deletions

View 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:

View 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

View File

@ -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;
}
/* foward the whole comand */
return 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:
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