MINOR: cli: add an expert mode to hide dangerous commands
Some commands like the debug ones are not enabled by default but can be
useful on some production environments. In order to avoid the temptation
of using them incorrectly, let's introduce an "expert" mode for a CLI
connection, which allows some commands to appear and be used. It is
enabled by command "expert-mode on" which is not listed by default.
diff --git a/doc/management.txt b/doc/management.txt
index d56a031..890f260 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -1586,6 +1586,18 @@
This command is restricted and can only be issued on sockets configured for
level "admin".
+expert-mode [on|off]
+ Without options, this indicates whether the expert mode is enabled or
+ disabled on the current connection. When passed "on", it turns the expert
+ mode on for the current CLI connection only. With "off" it turns it off. The
+ expert mode enables displaying of expert commands that can be extremely
+ dangerous for the process and which may occasionally help developers collect
+ important information about complex bugs. Any misuse of these features will
+ likely lead to a process crash. Do not use this option without being invited
+ to do so. Note that this command is purposely not listed in the help message.
+ This command is only accessible in admin level. Changing to another level
+ automatically resets the expert mode.
+
get map <map> <value>
get acl <acl> <value>
Lookup the value <value> in the map <map> or in the ACL <acl>. <map> or <acl>
@@ -1841,11 +1853,11 @@
operator
Decrease the CLI level of the current CLI session to operator. It can't be
- increase. See also "show cli level"
+ increased. It also drops expert mode. See also "show cli level".
user
Decrease the CLI level of the current CLI session to user. It can't be
- increase. See also "show cli level"
+ increased. It also drops expert mode. See also "show cli level".
show activity
Reports some counters about internal events that will help developers and
diff --git a/include/types/cli.h b/include/types/cli.h
index 3dee3f8..8a44124 100644
--- a/include/types/cli.h
+++ b/include/types/cli.h
@@ -34,6 +34,8 @@
#define ACCESS_MASTER 0x8 /* works with the master (and every other processes) */
#define ACCESS_MASTER_ONLY 0x10 /* only works with the worker */
+#define ACCESS_EXPERT 0x20 /* access to dangerous commands reserved to experts */
+
struct cli_kw {
const char *str_kw[5]; /* keywords ended by NULL, limited to 5
separated keywords combination */
diff --git a/src/cli.c b/src/cli.c
index 6b0b5e7..6037e96 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -125,6 +125,10 @@
if (master == 1 && !(kw->level & (ACCESS_MASTER_ONLY|ACCESS_MASTER)))
goto next_kw;
+ /* only show expert commands in expert mode */
+ if ((kw->level & ~appctx->cli_level) & ACCESS_EXPERT)
+ goto next_kw;
+
if (kw->usage)
chunk_appendf(tmp, " %s\n", kw->usage);
@@ -567,6 +571,10 @@
if (master == 1 && !(kw->level & (ACCESS_MASTER_ONLY|ACCESS_MASTER)))
return 0;
+ /* only accept expert commands in expert mode */
+ if ((kw->level & ~appctx->cli_level) & ACCESS_EXPERT)
+ return 0;
+
appctx->io_handler = kw->io_handler;
appctx->io_release = kw->io_release;
/* kw->parse could set its own io_handler or ip_release handler */
@@ -1441,6 +1449,25 @@
appctx->cli_level &= ~ACCESS_LVL_MASK;
appctx->cli_level |= ACCESS_LVL_USER;
}
+ appctx->cli_level &= ~ACCESS_EXPERT;
+ return 1;
+}
+
+
+/* parse and set the CLI expert-mode dynamically */
+static int cli_parse_expert_mode(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+ return 1;
+
+ if (!*args[1])
+ return (appctx->cli_level & ACCESS_EXPERT)
+ ? cli_msg(appctx, LOG_INFO, "expert-mode is ON\n")
+ : cli_msg(appctx, LOG_INFO, "expert-mode is OFF\n");
+
+ appctx->cli_level &= ~ACCESS_EXPERT;
+ if (strcmp(args[1], "on") == 0)
+ appctx->cli_level |= ACCESS_EXPERT;
return 1;
}
@@ -2671,6 +2698,7 @@
{ { "operator", NULL }, "operator : lower the level of the current CLI session to operator", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER},
{ { "user", NULL }, "user : lower the level of the current CLI session to user", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER},
{ { "_getsocks", NULL }, NULL, _getsocks, NULL },
+ { { "expert-mode", NULL }, NULL, cli_parse_expert_mode, NULL }, // not listed
{{},}
}};