diff options
-rw-r--r-- | scripts/maint/practracker/exceptions.txt | 4 | ||||
-rw-r--r-- | src/feature/control/control_cmd.c | 239 | ||||
-rw-r--r-- | src/feature/control/control_cmd.h | 44 | ||||
-rw-r--r-- | src/feature/control/control_getinfo.c | 16 | ||||
-rw-r--r-- | src/feature/control/control_getinfo.h | 8 |
5 files changed, 154 insertions, 157 deletions
diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 7582395fea..438c1c582a 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -54,7 +54,7 @@ problem function-size /src/app/main/main.c:sandbox_init_filter() 291 problem function-size /src/app/main/main.c:run_tor_main_loop() 105 problem function-size /src/app/main/ntmain.c:nt_service_install() 125 problem include-count /src/app/main/shutdown.c 52 -problem file-size /src/core/mainloop/connection.c 5558 +problem file-size /src/core/mainloop/connection.c 5559 problem include-count /src/core/mainloop/connection.c 61 problem function-size /src/core/mainloop/connection.c:connection_free_minimal() 185 problem function-size /src/core/mainloop/connection.c:connection_listener_new() 328 @@ -152,7 +152,7 @@ problem function-size /src/feature/control/control_cmd.c:handle_control_add_onio problem function-size /src/feature/control/control_cmd.c:add_onion_helper_keyarg() 125 problem function-size /src/feature/control/control_cmd.c:handle_control_command() 104 problem function-size /src/feature/control/control_events.c:control_event_stream_status() 119 -problem include-count /src/feature/control/control_getinfo.c 52 +problem include-count /src/feature/control/control_getinfo.c 53 problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_misc() 109 problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_dir() 304 problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_events() 236 diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index 53cbf2bd0f..f457e9fa54 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -160,13 +160,17 @@ handle_control_resetconf(control_connection_t *conn, uint32_t len, char *body) return control_setconf_helper(conn, len, body, 1); } +static const control_cmd_syntax_t getconf_syntax = { + .max_args=UINT_MAX +}; + /** Called when we receive a GETCONF message. Parse the request, and * reply with a CONFVALUE or an ERROR message */ static int -handle_control_getconf(control_connection_t *conn, uint32_t body_len, - char *body) +handle_control_getconf(control_connection_t *conn, + const control_cmd_args_t *args) { - smartlist_t *questions = smartlist_new(); + const smartlist_t *questions = args->args; smartlist_t *answers = smartlist_new(); smartlist_t *unrecognized = smartlist_new(); char *msg = NULL; @@ -174,9 +178,6 @@ handle_control_getconf(control_connection_t *conn, uint32_t body_len, const or_options_t *options = get_options(); int i, len; - (void) body_len; /* body is NUL-terminated; so we can ignore len. */ - smartlist_split_string(questions, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { if (!option_is_recognized(q)) { smartlist_add(unrecognized, (char*) q); @@ -221,8 +222,6 @@ handle_control_getconf(control_connection_t *conn, uint32_t body_len, SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); smartlist_free(answers); - SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp)); - smartlist_free(questions); smartlist_free(unrecognized); tor_free(msg); @@ -230,17 +229,21 @@ handle_control_getconf(control_connection_t *conn, uint32_t body_len, return 0; } +static const control_cmd_syntax_t loadconf_syntax = { + .want_object = true +}; + /** Called when we get a +LOADCONF message. */ static int -handle_control_loadconf(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_loadconf(control_connection_t *conn, + const control_cmd_args_t *args) { setopt_err_t retval; char *errstring = NULL; const char *msg = NULL; - (void) len; - retval = options_init_from_string(NULL, body, CMD_RUN_TOR, NULL, &errstring); + retval = options_init_from_string(NULL, args->object, + CMD_RUN_TOR, NULL, &errstring); if (retval != SETOPT_OK) log_warn(LD_CONTROL, @@ -276,20 +279,20 @@ handle_control_loadconf(control_connection_t *conn, uint32_t len, return 0; } +static const control_cmd_syntax_t setevents_syntax = { + .max_args = UINT_MAX +}; + /** Called when we get a SETEVENTS message: update conn->event_mask, * and reply with DONE or ERROR. */ static int -handle_control_setevents(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_setevents(control_connection_t *conn, + const control_cmd_args_t *args) { int event_code; event_mask_t event_mask = 0; - smartlist_t *events = smartlist_new(); - - (void) len; + const smartlist_t *events = args->args; - smartlist_split_string(events, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(events, const char *, ev) { if (!strcasecmp(ev, "EXTENDED") || @@ -311,16 +314,12 @@ handle_control_setevents(control_connection_t *conn, uint32_t len, if (event_code == -1) { connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n", ev); - SMARTLIST_FOREACH(events, char *, e, tor_free(e)); - smartlist_free(events); return 0; } } event_mask |= (((event_mask_t)1) << event_code); } SMARTLIST_FOREACH_END(ev); - SMARTLIST_FOREACH(events, char *, e, tor_free(e)); - smartlist_free(events); conn->event_mask = event_mask; @@ -348,23 +347,23 @@ handle_control_saveconf(control_connection_t *conn, uint32_t len, return 0; } +static const control_cmd_syntax_t signal_syntax = { + .min_args = 1, + .max_args = 1, +}; + /** Called when we get a SIGNAL command. React to the provided signal, and * report success or failure. (If the signal results in a shutdown, success * may not be reported.) */ static int -handle_control_signal(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_signal(control_connection_t *conn, + const control_cmd_args_t *args) { int sig = -1; int i; - int n = 0; - char *s; - - (void) len; - while (body[n] && ! TOR_ISSPACE(body[n])) - ++n; - s = tor_strndup(body, n); + tor_assert(smartlist_len(args->args) == 1); + const char *s = smartlist_get(args->args, 0); for (i = 0; signal_table[i].signal_name != NULL; ++i) { if (!strcasecmp(s, signal_table[i].signal_name)) { @@ -376,7 +375,6 @@ handle_control_signal(control_connection_t *conn, uint32_t len, if (sig < 0) connection_printf_to_buf(conn, "552 Unrecognized signal code \"%s\"\r\n", s); - tor_free(s); if (sig < 0) return 0; @@ -390,15 +388,18 @@ handle_control_signal(control_connection_t *conn, uint32_t len, return 0; } +static const control_cmd_syntax_t takeownership_syntax = { + .max_args = UINT_MAX, // This should probably become zero. XXXXX +}; + /** Called when we get a TAKEOWNERSHIP command. Mark this connection * as an owning connection, so that we will exit if the connection * closes. */ static int -handle_control_takeownership(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_takeownership(control_connection_t *conn, + const control_cmd_args_t *args) { - (void)len; - (void)body; + (void)args; conn->is_owning_control_connection = 1; @@ -410,15 +411,18 @@ handle_control_takeownership(control_connection_t *conn, uint32_t len, return 0; } +static const control_cmd_syntax_t dropownership_syntax = { + .max_args = UINT_MAX, // This should probably become zero. XXXXX +}; + /** Called when we get a DROPOWNERSHIP command. Mark this connection * as a non-owning connection, so that we will not exit if the connection * closes. */ static int -handle_control_dropownership(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_dropownership(control_connection_t *conn, + const control_cmd_args_t *args) { - (void)len; - (void)body; + (void)args; conn->is_owning_control_connection = 0; @@ -1099,21 +1103,21 @@ handle_control_postdescriptor(control_connection_t *conn, uint32_t len, return 0; } +static const control_cmd_syntax_t redirectstream_syntax = { + .min_args = 2, + .max_args = UINT_MAX, // XXX should be 3. +}; + /** Called when we receive a REDIRECTSTERAM command. Try to change the target * address of the named AP stream, and report success or failure. */ static int -handle_control_redirectstream(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_redirectstream(control_connection_t *conn, + const control_cmd_args_t *cmd_args) { entry_connection_t *ap_conn = NULL; char *new_addr = NULL; uint16_t new_port = 0; - smartlist_t *args; - (void) len; - - args = getargs_helper("REDIRECTSTREAM", conn, body, 2, -1); - if (!args) - return 0; + const smartlist_t *args = cmd_args->args; if (!(ap_conn = get_stream(smartlist_get(args, 0))) || !ap_conn->socks_request) { @@ -1133,8 +1137,6 @@ handle_control_redirectstream(control_connection_t *conn, uint32_t len, } } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); if (!new_addr) return 0; @@ -1147,23 +1149,26 @@ handle_control_redirectstream(control_connection_t *conn, uint32_t len, return 0; } +static const control_cmd_syntax_t closestream_syntax = { + .min_args = 2, + .max_args = UINT_MAX, /* XXXX This is the original behavior, but + * maybe we should change the spec. */ +}; + /** Called when we get a CLOSESTREAM command; try to close the named stream * and report success or failure. */ static int -handle_control_closestream(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_closestream(control_connection_t *conn, + const control_cmd_args_t *cmd_args) { entry_connection_t *ap_conn=NULL; uint8_t reason=0; - smartlist_t *args; int ok; - (void) len; + const smartlist_t *args = cmd_args->args; - args = getargs_helper("CLOSESTREAM", conn, body, 2, -1); - if (!args) - return 0; + tor_assert(smartlist_len(args) >= 2); - else if (!(ap_conn = get_stream(smartlist_get(args, 0)))) + if (!(ap_conn = get_stream(smartlist_get(args, 0)))) connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n", (char*)smartlist_get(args, 0)); else { @@ -1175,8 +1180,6 @@ handle_control_closestream(control_connection_t *conn, uint32_t len, ap_conn = NULL; } } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); if (!ap_conn) return 0; @@ -1269,19 +1272,20 @@ handle_control_resolve(control_connection_t *conn, uint32_t len, return 0; } +static const control_cmd_syntax_t protocolinfo_syntax = { + .max_args = UINT_MAX +}; + /** Called when we get a PROTOCOLINFO command: send back a reply. */ static int -handle_control_protocolinfo(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_protocolinfo(control_connection_t *conn, + const control_cmd_args_t *cmd_args) { const char *bad_arg = NULL; - smartlist_t *args; - (void)len; + const smartlist_t *args = cmd_args->args; conn->have_sent_protocolinfo = 1; - args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH(args, const char *, arg, { int ok; tor_parse_long(arg, 10, 0, LONG_MAX, &ok, NULL); @@ -1337,24 +1341,21 @@ handle_control_protocolinfo(control_connection_t *conn, uint32_t len, tor_free(esc_cfile); } done: - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); return 0; } +static const control_cmd_syntax_t usefeature_syntax = { + .max_args = UINT_MAX +}; + /** Called when we get a USEFEATURE command: parse the feature list, and * set up the control_connection's options properly. */ static int handle_control_usefeature(control_connection_t *conn, - uint32_t len, - const char *body) + const control_cmd_args_t *cmd_args) { - smartlist_t *args; + const smartlist_t *args = cmd_args->args; int bad = 0; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(args, const char *, arg) { if (!strcasecmp(arg, "VERBOSE_NAMES")) ; @@ -1372,22 +1373,19 @@ handle_control_usefeature(control_connection_t *conn, send_control_done(conn); } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); return 0; } +static const control_cmd_syntax_t dropguards_syntax = { + .max_args = 0, +}; + /** Implementation for the DROPGUARDS command. */ static int handle_control_dropguards(control_connection_t *conn, - uint32_t len, - const char *body) + const control_cmd_args_t *args) { - smartlist_t *args; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + (void) args; /* We don't take arguments. */ static int have_warned = 0; if (! have_warned) { @@ -1397,15 +1395,9 @@ handle_control_dropguards(control_connection_t *conn, have_warned = 1; } - if (smartlist_len(args)) { - connection_printf_to_buf(conn, "512 Too many arguments to DROPGUARDS\r\n"); - } else { - remove_all_entry_guards(); - send_control_done(conn); - } + remove_all_entry_guards(); + send_control_done(conn); - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); return 0; } @@ -2202,19 +2194,19 @@ add_onion_helper_clientauth(const char *arg, int *created, char **err_msg) return client; } +static const control_cmd_syntax_t del_onion_syntax = { + .min_args = 1, .max_args = 1, +}; + /** Called when we get a DEL_ONION command; parse the body, and remove * the existing ephemeral Onion Service. */ static int handle_control_del_onion(control_connection_t *conn, - uint32_t len, - const char *body) + const control_cmd_args_t *cmd_args) { int hs_version = 0; - smartlist_t *args; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - args = getargs_helper("DEL_ONION", conn, body, 1, 1); - if (!args) - return 0; + smartlist_t *args = cmd_args->args; + tor_assert(smartlist_len(args) == 1); const char *service_id = smartlist_get(args, 0); if (rend_valid_v2_service_id(service_id)) { @@ -2280,11 +2272,6 @@ handle_control_del_onion(control_connection_t *conn, } out: - SMARTLIST_FOREACH(args, char *, cp, { - memwipe(cp, 0, strlen(cp)); - tor_free(cp); - }); - smartlist_free(args); return 0; } @@ -2399,20 +2386,26 @@ typedef struct control_cmd_def_t { **/ #define ONE_LINE(name, htype, flags) \ ONE_LINE_(name, htype, flags, NULL) -#define ONE_LINE_PARSED(name, flags, syntax) \ - ONE_LINE_(name, parsed, flags, syntax) +#define ONE_LINE_PARSED(name, flags) \ + ONE_LINE_(name, parsed, flags, &name ##_syntax) /** * Macro: declare a command with a multi-line argument and a given set of * flags. **/ -#define MULTLINE(name, htype, flags) \ +#define MULTLINE_(name, htype, flags, syntax) \ { "+"#name, \ hnd_ ##htype, \ { .htype = handle_control_ ##name }, \ flags, \ - NULL \ + syntax \ } + +#define MULTLINE(name, htype, flags) \ + MULTLINE_(name, htype, flags, NULL) +#define MULTLINE_PARSED(name, flags) \ + MULTLINE_(name, parsed, flags, &name##_syntax) + /** * Macro: declare an obsolete command. (Obsolete commands give a different * error than non-existent ones.) @@ -2432,33 +2425,33 @@ static const control_cmd_def_t CONTROL_COMMANDS[] = { ONE_LINE(setconf, legacy_mut, 0), ONE_LINE(resetconf, legacy_mut, 0), - ONE_LINE(getconf, legacy_mut, 0), - MULTLINE(loadconf, legacy, 0), - ONE_LINE(setevents, legacy, 0), + ONE_LINE_PARSED(getconf, 0), + MULTLINE_PARSED(loadconf, 0), + ONE_LINE_PARSED(setevents, 0), ONE_LINE(authenticate, legacy, CMD_FL_WIPE), ONE_LINE(saveconf, legacy, 0), - ONE_LINE(signal, legacy, 0), - ONE_LINE(takeownership, legacy, 0), - ONE_LINE(dropownership, legacy, 0), + ONE_LINE_PARSED(signal, 0), + ONE_LINE_PARSED(takeownership, 0), + ONE_LINE_PARSED(dropownership, 0), ONE_LINE(mapaddress, legacy, 0), - ONE_LINE(getinfo, legacy, 0), + ONE_LINE_PARSED(getinfo, 0), ONE_LINE(extendcircuit, legacy, 0), ONE_LINE(setcircuitpurpose, legacy, 0), OBSOLETE(setrouterpurpose), ONE_LINE(attachstream, legacy, 0), MULTLINE(postdescriptor, legacy, 0), - ONE_LINE(redirectstream, legacy, 0), - ONE_LINE(closestream, legacy, 0), + ONE_LINE_PARSED(redirectstream, 0), + ONE_LINE_PARSED(closestream, 0), ONE_LINE(closecircuit, legacy, 0), - ONE_LINE(usefeature, legacy, 0), + ONE_LINE_PARSED(usefeature, 0), ONE_LINE(resolve, legacy, 0), - ONE_LINE(protocolinfo, legacy, 0), + ONE_LINE_PARSED(protocolinfo, 0), ONE_LINE(authchallenge, legacy, CMD_FL_WIPE), - ONE_LINE(dropguards, legacy, 0), + ONE_LINE_PARSED(dropguards, 0), ONE_LINE(hsfetch, legacy, 0), MULTLINE(hspost, legacy, 0), ONE_LINE(add_onion, legacy, CMD_FL_WIPE), - ONE_LINE(del_onion, legacy, CMD_FL_WIPE), + ONE_LINE_PARSED(del_onion, CMD_FL_WIPE), }; /** diff --git a/src/feature/control/control_cmd.h b/src/feature/control/control_cmd.h index 1070a9edb7..801bf43709 100644 --- a/src/feature/control/control_cmd.h +++ b/src/feature/control/control_cmd.h @@ -25,28 +25,6 @@ void control_cmd_args_free_(control_cmd_args_t *args); #define control_cmd_args_free(v) \ FREE_AND_NULL(control_cmd_args_t, control_cmd_args_free_, (v)) -#ifdef CONTROL_CMD_PRIVATE -#include "lib/crypt_ops/crypto_ed25519.h" - -/* ADD_ONION secret key to create an ephemeral service. The command supports - * multiple versions so this union stores the key and passes it to the HS - * subsystem depending on the requested version. */ -typedef union add_onion_secret_key_t { - /* Hidden service v2 secret key. */ - crypto_pk_t *v2; - /* Hidden service v3 secret key. */ - ed25519_secret_key_t *v3; -} add_onion_secret_key_t; - -STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk, - const char **key_new_alg_out, - char **key_new_blob_out, - add_onion_secret_key_t *decoded_key, - int *hs_version, char **err_msg_out); - -STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg, - int *created, char **err_msg_out); - /** * Definition for the syntax of a controller command, as parsed by * control_cmd_parse_args. @@ -71,6 +49,28 @@ typedef struct control_cmd_syntax_t { bool want_object; } control_cmd_syntax_t; +#ifdef CONTROL_CMD_PRIVATE +#include "lib/crypt_ops/crypto_ed25519.h" + +/* ADD_ONION secret key to create an ephemeral service. The command supports + * multiple versions so this union stores the key and passes it to the HS + * subsystem depending on the requested version. */ +typedef union add_onion_secret_key_t { + /* Hidden service v2 secret key. */ + crypto_pk_t *v2; + /* Hidden service v3 secret key. */ + ed25519_secret_key_t *v3; +} add_onion_secret_key_t; + +STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk, + const char **key_new_alg_out, + char **key_new_blob_out, + add_onion_secret_key_t *decoded_key, + int *hs_version, char **err_msg_out); + +STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg, + int *created, char **err_msg_out); + STATIC control_cmd_args_t *control_cmd_parse_args( const char *command, const control_cmd_syntax_t *syntax, diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c index a7a85f2fdf..5c6a0d4aa2 100644 --- a/src/feature/control/control_getinfo.c +++ b/src/feature/control/control_getinfo.c @@ -55,6 +55,7 @@ #include "core/or/origin_circuit_st.h" #include "core/or/socks_request_st.h" #include "feature/control/control_connection_st.h" +#include "feature/control/control_cmd_args_st.h" #include "feature/dircache/cached_dir_st.h" #include "feature/nodelist/extrainfo_st.h" #include "feature/nodelist/microdesc_st.h" @@ -1584,21 +1585,22 @@ handle_getinfo_helper(control_connection_t *control_conn, return 0; /* unrecognized */ } +const control_cmd_syntax_t getinfo_syntax = { + .max_args = UINT_MAX, +}; + /** Called when we receive a GETINFO command. Try to fetch all requested * information, and reply with information or error message. */ int -handle_control_getinfo(control_connection_t *conn, uint32_t len, - const char *body) +handle_control_getinfo(control_connection_t *conn, + const control_cmd_args_t *args) { - smartlist_t *questions = smartlist_new(); + const smartlist_t *questions = args->args; smartlist_t *answers = smartlist_new(); smartlist_t *unrecognized = smartlist_new(); char *ans = NULL; int i; - (void) len; /* body is NUL-terminated, so it's safe to ignore the length. */ - smartlist_split_string(questions, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { const char *errmsg = NULL; @@ -1653,8 +1655,6 @@ handle_control_getinfo(control_connection_t *conn, uint32_t len, done: SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); smartlist_free(answers); - SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp)); - smartlist_free(questions); SMARTLIST_FOREACH(unrecognized, char *, cp, tor_free(cp)); smartlist_free(unrecognized); diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h index d5a2feb3e0..2d56586f6d 100644 --- a/src/feature/control/control_getinfo.h +++ b/src/feature/control/control_getinfo.h @@ -12,8 +12,12 @@ #ifndef TOR_CONTROL_GETINFO_H #define TOR_CONTROL_GETINFO_H -int handle_control_getinfo(control_connection_t *conn, uint32_t len, - const char *body); +struct control_cmd_syntax_t; +struct control_cmd_args_t; +extern const struct control_cmd_syntax_t getinfo_syntax; + +int handle_control_getinfo(control_connection_t *conn, + const struct control_cmd_args_t *args); #ifdef CONTROL_GETINFO_PRIVATE STATIC int getinfo_helper_onions( |