MINOR: anon: store the anonymizing key in the CLI's appctx

In order to allow users to dump internal states using a specific key
without changing the global one, we're introducing a key in the CLI's
appctx. This key is preloaded from the global one when "set anon on"
is used (and if none exists, a random one is assigned). And the key
can optionally be assigned manually for the whole CLI session.

A "show anon" command was also added to show the anon state, and the
current key if the users has sufficient permissions. In addition, a
"debug dev hash" command was added to test the feature.
diff --git a/src/cli.c b/src/cli.c
index aaf0677..d238a23 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -1874,6 +1874,50 @@
 	return 0;
 }
 
+/* enable or disable the anonymized mode, it returns 1 when it works or displays an error message if it doesn't. */
+static int cli_parse_set_anon(char **args, char *payload, struct appctx *appctx, void *private)
+{
+	uint32_t tmp;
+	long long key;
+
+	if (strcmp(args[2], "on") == 0) {
+		if (appctx->cli_anon_key != 0)
+			return cli_err(appctx, "Mode already enabled\n");
+		else {
+			if (*args[3]) {
+				key = atoll(args[3]);
+				if (key < 1 || key > UINT_MAX)
+					return cli_err(appctx, "Value out of range (1 to 4294967295 expected).\n");
+				appctx->cli_anon_key = key;
+			}
+			else {
+				tmp = HA_ATOMIC_LOAD(&global.anon_key);
+				if (tmp != 0)
+					appctx->cli_anon_key = tmp;
+				else
+					appctx->cli_anon_key = ha_random32();
+			}
+		}
+	}
+	else if (strcmp(args[2], "off") == 0) {
+		if (appctx->cli_anon_key == 0)
+			return cli_err(appctx, "Mode already disabled\n");
+		else if (*args[3]) {
+			return cli_err(appctx, "Key can't be added while disabling anonymized mode\n");
+		}
+		else {
+			appctx->cli_anon_key = 0;
+		}
+	}
+	else {
+		return cli_err(appctx,
+			"'set anon' only supports :\n"
+                        "   - 'on' [key] to enable the anonymized mode\n"
+                        "   - 'off' to disable the anonymized mode");
+	}
+	return 1;
+}
+
 /* This function set the global anonyzing key, restricted to level 'admin' */
 static int cli_parse_set_global_key(char **args, char *payload, struct appctx *appctx, void *private)
 {
@@ -1892,6 +1936,28 @@
 	return 1;
 }
 
+/* shows the anonymized mode state to everyone, and the key except for users, it always returns 1. */
+static int cli_parse_show_anon(char **args, char *payload, struct appctx *appctx, void *private)
+{
+	char *msg = NULL;
+	char *anon_mode = NULL;
+	uint32_t c_key = appctx->cli_anon_key;
+
+	if (!c_key)
+		anon_mode = "Anonymized mode disabled";
+	else
+		anon_mode = "Anonymized mode enabled";
+
+	if ( !((appctx->cli_level & ACCESS_LVL_MASK) < ACCESS_LVL_OPER) && c_key != 0) {
+		cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "%s\nKey : %u\n", anon_mode, c_key));
+	}
+	else {
+		cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "%s\n", anon_mode));
+	}
+
+	return 1;
+}
+
 /* parse a "set rate-limit" command. It always returns 1. */
 static int cli_parse_set_ratelimit(char **args, char *payload, struct appctx *appctx, void *private)
 {
@@ -3200,11 +3266,13 @@
 	{ { "expert-mode", NULL },               NULL,                                                                                                cli_parse_expert_experimental_mode, NULL, NULL, NULL, ACCESS_MASTER }, // not listed
 	{ { "experimental-mode", NULL },         NULL,                                                                                                cli_parse_expert_experimental_mode, NULL, NULL, NULL, ACCESS_MASTER }, // not listed
 	{ { "mcli-debug-mode", NULL },         NULL,                                                                                                  cli_parse_expert_experimental_mode, NULL, NULL, NULL, ACCESS_MASTER_ONLY }, // not listed
+	{ { "set", "anon", NULL },               "set anon <setting> [value]              : change the anonymized mode setting",                      cli_parse_set_anon, NULL, NULL },
 	{ { "set", "global-key", NULL },         "set global-key <value>                  : change the global anonymizing key",                       cli_parse_set_global_key, NULL, NULL },
 	{ { "set", "maxconn", "global",  NULL }, "set maxconn global <value>              : change the per-process maxconn setting",                  cli_parse_set_maxconn_global, NULL },
 	{ { "set", "rate-limit", NULL },         "set rate-limit <setting> <value>        : change a rate limiting value",                            cli_parse_set_ratelimit, NULL },
 	{ { "set", "severity-output",  NULL },   "set severity-output [none|number|string]: set presence of severity level in feedback information",  cli_parse_set_severity_output, NULL, NULL },
 	{ { "set", "timeout",  NULL },           "set timeout [cli] <delay>               : change a timeout setting",                                cli_parse_set_timeout, NULL, NULL },
+	{ { "show", "anon", NULL },              "show anon                               : display the current state of anonymized mode",            cli_parse_show_anon, NULL },
 	{ { "show", "env",  NULL },              "show env [var]                          : dump environment variables known to the process",         cli_parse_show_env, cli_io_handler_show_env, NULL },
 	{ { "show", "cli", "sockets",  NULL },   "show cli sockets                        : dump list of cli sockets",                                cli_parse_default, cli_io_handler_show_cli_sock, NULL, NULL, ACCESS_MASTER },
 	{ { "show", "cli", "level", NULL },      "show cli level                          : display the level of the current CLI session",            cli_parse_show_lvl, NULL, NULL, NULL, ACCESS_MASTER},