aboutsummaryrefslogtreecommitdiff
path: root/src/feature/control/control_cmd.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-04-05 15:29:56 -0400
committerNick Mathewson <nickm@torproject.org>2019-04-25 14:13:03 -0400
commit0841a69357d73353905f8012f455ec6128201131 (patch)
treec1da557a1b7798f1df18671896419dbfee4bb83c /src/feature/control/control_cmd.c
parentbb37ad695729984553275880cce131c47361345f (diff)
downloadtor-0841a69357d73353905f8012f455ec6128201131.tar.gz
tor-0841a69357d73353905f8012f455ec6128201131.zip
Allow kvlines in control commands.
Diffstat (limited to 'src/feature/control/control_cmd.c')
-rw-r--r--src/feature/control/control_cmd.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index f457e9fa54..727950a938 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -40,6 +40,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/encoding/confline.h"
+#include "lib/encoding/kvline.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/entry_connection_st.h"
@@ -74,12 +75,28 @@ control_cmd_args_free_(control_cmd_args_t *args)
SMARTLIST_FOREACH(args->args, char *, c, tor_free(c));
smartlist_free(args->args);
}
+ config_free_lines(args->kwargs);
tor_free(args->object);
tor_free(args);
}
/**
+ * Return true iff any element of the NULL-terminated <b>array</b> matches
+ * <b>kwd</b>. Case-insensitive.
+ **/
+static bool
+string_array_contains_keyword(const char **array, const char *kwd)
+{
+ for (unsigned i = 0; array[i]; ++i) {
+ if (! strcasecmp(array[i], kwd))
+ return true;
+ }
+ return false;
+}
+
+
+/**
* Helper: parse the arguments to a command according to <b>syntax</b>. On
* success, set *<b>error_out</b> to NULL and return a newly allocated
* control_cmd_args_t. On failure, set *<b>error_out</b> to newly allocated
@@ -96,6 +113,7 @@ control_cmd_parse_args(const char *command,
control_cmd_args_t *result = tor_malloc_zero(sizeof(control_cmd_args_t));
const char *cmdline;
char *cmdline_alloc = NULL;
+ tor_assert(syntax->max_args < INT_MAX || syntax->max_args == UINT_MAX);
result->command = command;
@@ -120,18 +138,42 @@ control_cmd_parse_args(const char *command,
result->args = smartlist_new();
smartlist_split_string(result->args, cmdline, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,
+ (int)(syntax->max_args+1));
size_t n_args = smartlist_len(result->args);
if (n_args < syntax->min_args) {
tor_asprintf(error_out, "Need at least %u argument(s)",
syntax->min_args);
goto err;
- } else if (n_args > syntax->max_args) {
+ } else if (n_args > syntax->max_args && ! syntax->accept_keywords) {
tor_asprintf(error_out, "Cannot accept more than %u argument(s)",
syntax->max_args);
goto err;
}
+ if (n_args > syntax->max_args) {
+ tor_assert(n_args == syntax->max_args + 1);
+ tor_assert(syntax->accept_keywords);
+ char *remainder = smartlist_pop_last(result->args);
+ result->kwargs = kvline_parse(remainder, syntax->kvline_flags);
+ tor_free(remainder);
+ if (result->kwargs == NULL) {
+ tor_asprintf(error_out, "Cannot parse keyword argument(s)");
+ goto err;
+ }
+ if (syntax->allowed_keywords) {
+ /* Check for unpermitted arguments */
+ const config_line_t *line;
+ for (line = result->kwargs; line; line = line->next) {
+ if (! string_array_contains_keyword(syntax->allowed_keywords,
+ line->key)) {
+ tor_asprintf(error_out, "Unrecognized keyword argument %s",
+ escaped(line->key));
+ }
+ }
+ }
+ }
+
tor_assert_nonfatal(*error_out == NULL);
goto done;
err: