tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

control.c (19587B)


      1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      2 * Copyright (c) 2007-2024, The Tor Project, Inc. */
      3 /* See LICENSE for licensing information */
      4 
      5 /**
      6 * \file control.c
      7 * \brief Implementation for Tor's control-socket interface.
      8 *
      9 * A "controller" is an external program that monitors and controls a Tor
     10 * instance via a text-based protocol. It connects to Tor via a connection
     11 * to a local socket.
     12 *
     13 * The protocol is line-driven.  The controller sends commands terminated by a
     14 * CRLF.  Tor sends lines that are either <em>replies</em> to what the
     15 * controller has said, or <em>events</em> that Tor sends to the controller
     16 * asynchronously based on occurrences in the Tor network model.
     17 *
     18 * See the control-spec.txt file in the torspec.git repository for full
     19 * details on protocol.
     20 *
     21 * This module generally has two kinds of entry points: those based on having
     22 * received a command on a controller socket, which are handled in
     23 * connection_control_process_inbuf(), and dispatched to individual functions
     24 * with names like control_handle_COMMANDNAME(); and those based on events
     25 * that occur elsewhere in Tor, which are handled by functions with names like
     26 * control_event_EVENTTYPE().
     27 *
     28 * Controller events are not sent immediately; rather, they are inserted into
     29 * the queued_control_events array, and flushed later from
     30 * flush_queued_events_cb().  Doing this simplifies our callgraph greatly,
     31 * by limiting the number of places in Tor that can call back into the network
     32 * stack.
     33 **/
     34 
     35 #define CONTROL_MODULE_PRIVATE
     36 #define CONTROL_PRIVATE
     37 
     38 #include "core/or/or.h"
     39 #include "app/config/config.h"
     40 #include "app/main/main.h"
     41 #include "core/mainloop/connection.h"
     42 #include "core/mainloop/mainloop.h"
     43 #include "core/or/connection_or.h"
     44 #include "core/proto/proto_control0.h"
     45 #include "core/proto/proto_http.h"
     46 #include "feature/control/control.h"
     47 #include "feature/control/control_auth.h"
     48 #include "feature/control/control_cmd.h"
     49 #include "feature/control/control_events.h"
     50 #include "feature/control/control_proto.h"
     51 #include "feature/hs/hs_common.h"
     52 #include "feature/hs/hs_service.h"
     53 #include "lib/evloop/procmon.h"
     54 
     55 #include "feature/control/control_connection_st.h"
     56 
     57 #ifdef HAVE_UNISTD_H
     58 #include <unistd.h>
     59 #endif
     60 #ifdef HAVE_SYS_STAT_H
     61 #include <sys/stat.h>
     62 #endif
     63 
     64 /**
     65 * Cast a `connection_t *` to a `control_connection_t *`.
     66 *
     67 * Exit with an assertion failure if the input is not a
     68 * `control_connection_t`.
     69 **/
     70 control_connection_t *
     71 TO_CONTROL_CONN(connection_t *c)
     72 {
     73  tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
     74  return DOWNCAST(control_connection_t, c);
     75 }
     76 
     77 /**
     78 * Cast a `const connection_t *` to a `const control_connection_t *`.
     79 *
     80 * Exit with an assertion failure if the input is not a
     81 * `control_connection_t`.
     82 **/
     83 const control_connection_t *
     84 CONST_TO_CONTROL_CONN(const connection_t *c)
     85 {
     86  return TO_CONTROL_CONN((connection_t*)c);
     87 }
     88 
     89 /** Create and add a new controller connection on <b>sock</b>.  If
     90 * <b>CC_LOCAL_FD_IS_OWNER</b> is set in <b>flags</b>, this Tor process should
     91 * exit when the connection closes.  If <b>CC_LOCAL_FD_IS_AUTHENTICATED</b>
     92 * is set, then the connection does not need to authenticate.
     93 */
     94 int
     95 control_connection_add_local_fd(tor_socket_t sock, unsigned flags)
     96 {
     97  if (BUG(! SOCKET_OK(sock)))
     98    return -1;
     99  const int is_owner = !!(flags & CC_LOCAL_FD_IS_OWNER);
    100  const int is_authenticated = !!(flags & CC_LOCAL_FD_IS_AUTHENTICATED);
    101  control_connection_t *control_conn = control_connection_new(AF_UNSPEC);
    102  connection_t *conn = TO_CONN(control_conn);
    103  conn->s = sock;
    104  tor_addr_make_unspec(&conn->addr);
    105  conn->port = 1;
    106  conn->address = tor_strdup("<local socket>");
    107 
    108  /* We take ownership of this socket so that later, when we close it,
    109   * we don't freak out. */
    110  tor_take_socket_ownership(sock);
    111 
    112  if (set_socket_nonblocking(sock) < 0 ||
    113      connection_add(conn) < 0) {
    114    connection_free(conn);
    115    return -1;
    116  }
    117 
    118  control_conn->is_owning_control_connection = is_owner;
    119 
    120  if (connection_init_accepted_conn(conn, NULL) < 0) {
    121    connection_mark_for_close(conn);
    122    return -1;
    123  }
    124 
    125  if (is_authenticated) {
    126    conn->state = CONTROL_CONN_STATE_OPEN;
    127  }
    128 
    129  return 0;
    130 }
    131 
    132 /** Write all of the open control ports to ControlPortWriteToFile */
    133 void
    134 control_ports_write_to_file(void)
    135 {
    136  smartlist_t *lines;
    137  char *joined = NULL;
    138  const or_options_t *options = get_options();
    139 
    140  if (!options->ControlPortWriteToFile)
    141    return;
    142 
    143  lines = smartlist_new();
    144 
    145  SMARTLIST_FOREACH_BEGIN(get_connection_array(), const connection_t *, conn) {
    146    if (conn->type != CONN_TYPE_CONTROL_LISTENER || conn->marked_for_close)
    147      continue;
    148 #ifdef AF_UNIX
    149    if (conn->socket_family == AF_UNIX) {
    150      smartlist_add_asprintf(lines, "UNIX_PORT=%s\n", conn->address);
    151      continue;
    152    }
    153 #endif /* defined(AF_UNIX) */
    154    smartlist_add_asprintf(lines, "PORT=%s:%d\n", conn->address, conn->port);
    155  } SMARTLIST_FOREACH_END(conn);
    156 
    157  joined = smartlist_join_strings(lines, "", 0, NULL);
    158 
    159  if (write_str_to_file(options->ControlPortWriteToFile, joined, 0) < 0) {
    160    log_warn(LD_CONTROL, "Writing %s failed: %s",
    161             options->ControlPortWriteToFile, strerror(errno));
    162  }
    163 #ifndef _WIN32
    164  if (options->ControlPortFileGroupReadable) {
    165    if (chmod(options->ControlPortWriteToFile, 0640)) {
    166      log_warn(LD_FS,"Unable to make %s group-readable.",
    167               options->ControlPortWriteToFile);
    168    }
    169  }
    170 #endif /* !defined(_WIN32) */
    171  tor_free(joined);
    172  SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
    173  smartlist_free(lines);
    174 }
    175 
    176 const struct signal_name_t signal_table[] = {
    177  /* NOTE: this table is used for handling SIGNAL commands and generating
    178   * SIGNAL events.  Order is significant: if there are two entries for the
    179   * same numeric signal, the first one is the canonical name generated
    180   * for the events. */
    181  { SIGHUP, "RELOAD" },
    182  { SIGHUP, "HUP" },
    183  { SIGINT, "SHUTDOWN" },
    184  { SIGUSR1, "DUMP" },
    185  { SIGUSR1, "USR1" },
    186  { SIGUSR2, "DEBUG" },
    187  { SIGUSR2, "USR2" },
    188  { SIGTERM, "HALT" },
    189  { SIGTERM, "TERM" },
    190  { SIGTERM, "INT" },
    191  { SIGNEWNYM, "NEWNYM" },
    192  { SIGCLEARDNSCACHE, "CLEARDNSCACHE"},
    193  { SIGHEARTBEAT, "HEARTBEAT"},
    194  { SIGACTIVE, "ACTIVE" },
    195  { SIGDORMANT, "DORMANT" },
    196  { 0, NULL },
    197 };
    198 
    199 /** Called when <b>conn</b> has no more bytes left on its outbuf. */
    200 int
    201 connection_control_finished_flushing(control_connection_t *conn)
    202 {
    203  tor_assert(conn);
    204  return 0;
    205 }
    206 
    207 /** Called when <b>conn</b> has gotten its socket closed. */
    208 int
    209 connection_control_reached_eof(control_connection_t *conn)
    210 {
    211  tor_assert(conn);
    212 
    213  log_info(LD_CONTROL,"Control connection reached EOF. Closing.");
    214  connection_mark_for_close(TO_CONN(conn));
    215  return 0;
    216 }
    217 
    218 /** Shut down this Tor instance in the same way that SIGINT would, but
    219 * with a log message appropriate for the loss of an owning controller. */
    220 static void
    221 lost_owning_controller(const char *owner_type, const char *loss_manner)
    222 {
    223  log_notice(LD_CONTROL, "Owning controller %s has %s -- exiting now.",
    224             owner_type, loss_manner);
    225 
    226  activate_signal(SIGTERM);
    227 }
    228 
    229 /** Called when <b>conn</b> is being freed. */
    230 void
    231 connection_control_closed(control_connection_t *conn)
    232 {
    233  tor_assert(conn);
    234 
    235  conn->event_mask = 0;
    236  control_update_global_event_mask();
    237 
    238  /* Close all ephemeral Onion Services if any.
    239   * The list and it's contents are scrubbed/freed in connection_free_.
    240   */
    241  if (conn->ephemeral_onion_services) {
    242    SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) {
    243      if (hs_address_is_valid(cp)) {
    244        hs_service_del_ephemeral(cp);
    245      } else {
    246        /* An invalid .onion in our list should NEVER happen */
    247        tor_fragile_assert();
    248      }
    249    } SMARTLIST_FOREACH_END(cp);
    250  }
    251 
    252  if (conn->is_owning_control_connection) {
    253    lost_owning_controller("connection", "closed");
    254  }
    255 
    256  control_remove_authenticated_connection(conn);
    257 }
    258 
    259 /** Return true iff <b>cmd</b> is allowable (or at least forgivable) at this
    260 * stage of the protocol. */
    261 static int
    262 is_valid_initial_command(control_connection_t *conn, const char *cmd)
    263 {
    264  if (conn->base_.state == CONTROL_CONN_STATE_OPEN)
    265    return 1;
    266  if (!strcasecmp(cmd, "PROTOCOLINFO"))
    267    return (!conn->have_sent_protocolinfo &&
    268            conn->safecookie_client_hash == NULL);
    269  if (!strcasecmp(cmd, "AUTHCHALLENGE"))
    270    return (conn->safecookie_client_hash == NULL);
    271  if (!strcasecmp(cmd, "AUTHENTICATE") ||
    272      !strcasecmp(cmd, "QUIT"))
    273    return 1;
    274  return 0;
    275 }
    276 
    277 /** Do not accept any control command of more than 1MB in length.  Anything
    278 * that needs to be anywhere near this long probably means that one of our
    279 * interfaces is broken. */
    280 #define MAX_COMMAND_LINE_LENGTH (1024*1024)
    281 
    282 /** Wrapper around peek_buf_has_control0 command: presents the same
    283 * interface as that underlying functions, but takes a connection_t instead of
    284 * a buf_t.
    285 */
    286 static int
    287 peek_connection_has_control0_command(connection_t *conn)
    288 {
    289  return peek_buf_has_control0_command(conn->inbuf);
    290 }
    291 
    292 static int
    293 peek_connection_has_http_command(connection_t *conn)
    294 {
    295  return peek_buf_has_http_command(conn->inbuf);
    296 }
    297 
    298 /**
    299 * Helper: take a nul-terminated command of given length, and find where the
    300 * command starts and the arguments begin.  Separate them, allocate a new
    301 * string in <b>current_cmd_out</b> for the command, and return a pointer
    302 * to the arguments.
    303 **/
    304 STATIC char *
    305 control_split_incoming_command(char *incoming_cmd,
    306                               size_t *data_len,
    307                               char **current_cmd_out)
    308 {
    309  const bool is_multiline = *data_len && incoming_cmd[0] == '+';
    310  size_t cmd_len = 0;
    311  while (cmd_len < *data_len
    312         && !TOR_ISSPACE(incoming_cmd[cmd_len]))
    313    ++cmd_len;
    314 
    315  *current_cmd_out = tor_memdup_nulterm(incoming_cmd, cmd_len);
    316  char *args = incoming_cmd+cmd_len;
    317  tor_assert(*data_len>=cmd_len);
    318  *data_len -= cmd_len;
    319  if (is_multiline) {
    320    // Only match horizontal space: any line after the first is data,
    321    // not arguments.
    322    while ((*args == '\t' || *args == ' ') && *data_len) {
    323      ++args;
    324      --*data_len;
    325    }
    326  } else {
    327    while (TOR_ISSPACE(*args) && *data_len) {
    328      ++args;
    329      --*data_len;
    330    }
    331  }
    332 
    333  return args;
    334 }
    335 
    336 static const char CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG[] =
    337  "HTTP/1.0 501 Tor ControlPort is not an HTTP proxy"
    338  "\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n"
    339  "<html>\n"
    340  "<head>\n"
    341  "<title>Tor's ControlPort is not an HTTP proxy</title>\n"
    342  "</head>\n"
    343  "<body>\n"
    344  "<h1>Tor's ControlPort is not an HTTP proxy</h1>\n"
    345  "<p>\n"
    346  "It appears you have configured your web browser to use Tor's control port"
    347  " as an HTTP proxy.\n"
    348  "This is not correct: Tor's default SOCKS proxy port is 9050.\n"
    349  "Please configure your client accordingly.\n"
    350  "</p>\n"
    351  "<p>\n"
    352  "See <a href=\"https://www.torproject.org/documentation.html\">"
    353  "https://www.torproject.org/documentation.html</a> for more "
    354  "information.\n"
    355  "<!-- Plus this comment, to make the body response more than 512 bytes, so "
    356  "     IE will be willing to display it. Comment comment comment comment "
    357  "     comment comment comment comment comment comment comment comment.-->\n"
    358  "</p>\n"
    359  "</body>\n"
    360  "</html>\n";
    361 
    362 /** Return an error on a control connection that tried to use the v0 protocol.
    363 */
    364 static void
    365 control_send_v0_reject(control_connection_t *conn)
    366 {
    367  size_t body_len;
    368  char buf[128];
    369  set_uint16(buf+2, htons(0x0000)); /* type == error */
    370  set_uint16(buf+4, htons(0x0001)); /* code == internal error */
    371  strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 "
    372          "and later; upgrade your controller.",
    373          sizeof(buf)-6);
    374  body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */
    375  set_uint16(buf+0, htons(body_len));
    376  connection_buf_add(buf, 4+body_len, TO_CONN(conn));
    377 
    378  connection_mark_and_flush(TO_CONN(conn));
    379 }
    380 
    381 /** Return an error on a control connection that tried to use HTTP.
    382 */
    383 static void
    384 control_send_http_reject(control_connection_t *conn)
    385 {
    386  connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn);
    387  log_notice(LD_CONTROL, "Received HTTP request on ControlPort");
    388  connection_mark_and_flush(TO_CONN(conn));
    389 }
    390 
    391 /** Check if a control connection has tried to use a known invalid protocol.
    392 * If it has, then:
    393 *  - send a reject response,
    394 *  - log a notice-level message, and
    395 *  - return false. */
    396 static bool
    397 control_protocol_is_valid(control_connection_t *conn)
    398 {
    399  /* Detect v0 commands and send a "no more v0" message. */
    400  if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
    401      peek_connection_has_control0_command(TO_CONN(conn))) {
    402    control_send_v0_reject(conn);
    403    return 0;
    404  }
    405 
    406  /* If the user has the HTTP proxy port and the control port confused. */
    407  if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
    408      peek_connection_has_http_command(TO_CONN(conn))) {
    409    control_send_http_reject(conn);
    410    return 0;
    411  }
    412 
    413  return 1;
    414 }
    415 
    416 /** Called when data has arrived on a v1 control connection: Try to fetch
    417 * commands from conn->inbuf, and execute them.
    418 */
    419 int
    420 connection_control_process_inbuf(control_connection_t *conn)
    421 {
    422  size_t data_len;
    423  uint32_t cmd_data_len;
    424  char *args;
    425 
    426  tor_assert(conn);
    427  tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN ||
    428             conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH);
    429 
    430  if (!conn->incoming_cmd) {
    431    conn->incoming_cmd = tor_malloc(1024);
    432    conn->incoming_cmd_len = 1024;
    433    conn->incoming_cmd_cur_len = 0;
    434  }
    435 
    436  if (!control_protocol_is_valid(conn)) {
    437    return 0;
    438  }
    439 
    440 again:
    441  while (1) {
    442    size_t last_idx;
    443    int r;
    444    /* First, fetch a line. */
    445    do {
    446      data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len;
    447      r = connection_buf_get_line(TO_CONN(conn),
    448                              conn->incoming_cmd+conn->incoming_cmd_cur_len,
    449                              &data_len);
    450      if (r == 0)
    451        /* Line not all here yet. Wait. */
    452        return 0;
    453      else if (r == -1) {
    454        if (data_len + conn->incoming_cmd_cur_len > MAX_COMMAND_LINE_LENGTH) {
    455          control_write_endreply(conn, 500, "Line too long.");
    456          connection_stop_reading(TO_CONN(conn));
    457          connection_mark_and_flush(TO_CONN(conn));
    458        }
    459        while (conn->incoming_cmd_len < data_len+conn->incoming_cmd_cur_len)
    460          conn->incoming_cmd_len *= 2;
    461        conn->incoming_cmd = tor_realloc(conn->incoming_cmd,
    462                                         conn->incoming_cmd_len);
    463      }
    464    } while (r != 1);
    465 
    466    tor_assert(data_len);
    467 
    468    last_idx = conn->incoming_cmd_cur_len;
    469    conn->incoming_cmd_cur_len += (int)data_len;
    470 
    471    /* We have appended a line to incoming_cmd.  Is the command done? */
    472    if (last_idx == 0 && *conn->incoming_cmd != '+')
    473      /* One line command, didn't start with '+'. */
    474      break;
    475    /* XXXX this code duplication is kind of dumb. */
    476    if (last_idx+3 == conn->incoming_cmd_cur_len &&
    477        tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) {
    478      /* Just appended ".\r\n"; we're done. Remove it. */
    479      conn->incoming_cmd[last_idx] = '\0';
    480      conn->incoming_cmd_cur_len -= 3;
    481      break;
    482    } else if (last_idx+2 == conn->incoming_cmd_cur_len &&
    483               tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) {
    484      /* Just appended ".\n"; we're done. Remove it. */
    485      conn->incoming_cmd[last_idx] = '\0';
    486      conn->incoming_cmd_cur_len -= 2;
    487      break;
    488    }
    489    /* Otherwise, read another line. */
    490  }
    491  data_len = conn->incoming_cmd_cur_len;
    492 
    493  /* Okay, we now have a command sitting on conn->incoming_cmd. See if we
    494   * recognize it.
    495   */
    496  tor_free(conn->current_cmd);
    497  args = control_split_incoming_command(conn->incoming_cmd, &data_len,
    498                                        &conn->current_cmd);
    499  if (BUG(!conn->current_cmd))
    500    return -1;
    501 
    502  /* If the connection is already closing, ignore further commands */
    503  if (TO_CONN(conn)->marked_for_close) {
    504    return 0;
    505  }
    506 
    507  /* Otherwise, Quit is always valid. */
    508  if (!strcasecmp(conn->current_cmd, "QUIT")) {
    509    control_write_endreply(conn, 250, "closing connection");
    510    connection_mark_and_flush(TO_CONN(conn));
    511    return 0;
    512  }
    513 
    514  if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
    515      !is_valid_initial_command(conn, conn->current_cmd)) {
    516    control_write_endreply(conn, 514, "Authentication required.");
    517    connection_mark_for_close(TO_CONN(conn));
    518    return 0;
    519  }
    520 
    521  if (data_len >= UINT32_MAX) {
    522    control_write_endreply(conn, 500, "A 4GB command? Nice try.");
    523    connection_mark_for_close(TO_CONN(conn));
    524    return 0;
    525  }
    526 
    527  cmd_data_len = (uint32_t)data_len;
    528  if (handle_control_command(conn, cmd_data_len, args) < 0)
    529    return -1;
    530 
    531  conn->incoming_cmd_cur_len = 0;
    532  goto again;
    533 }
    534 
    535 /** Cached liveness for network liveness events and GETINFO
    536 */
    537 
    538 static int network_is_live = 0;
    539 
    540 int
    541 get_cached_network_liveness(void)
    542 {
    543  return network_is_live;
    544 }
    545 
    546 void
    547 set_cached_network_liveness(int liveness)
    548 {
    549  network_is_live = liveness;
    550 }
    551 
    552 /** A copy of the process specifier of Tor's owning controller, or
    553 * NULL if this Tor instance is not currently owned by a process. */
    554 static char *owning_controller_process_spec = NULL;
    555 
    556 /** A process-termination monitor for Tor's owning controller, or NULL
    557 * if this Tor instance is not currently owned by a process. */
    558 static tor_process_monitor_t *owning_controller_process_monitor = NULL;
    559 
    560 /** Process-termination monitor callback for Tor's owning controller
    561 * process. */
    562 static void
    563 owning_controller_procmon_cb(void *unused)
    564 {
    565  (void)unused;
    566 
    567  lost_owning_controller("process", "vanished");
    568 }
    569 
    570 /** Set <b>process_spec</b> as Tor's owning controller process.
    571 * Exit on failure. */
    572 void
    573 monitor_owning_controller_process(const char *process_spec)
    574 {
    575  const char *msg;
    576 
    577  tor_assert((owning_controller_process_spec == NULL) ==
    578             (owning_controller_process_monitor == NULL));
    579 
    580  if (owning_controller_process_spec != NULL) {
    581    if ((process_spec != NULL) && !strcmp(process_spec,
    582                                          owning_controller_process_spec)) {
    583      /* Same process -- return now, instead of disposing of and
    584       * recreating the process-termination monitor. */
    585      return;
    586    }
    587 
    588    /* We are currently owned by a process, and we should no longer be
    589     * owned by it.  Free the process-termination monitor. */
    590    tor_process_monitor_free(owning_controller_process_monitor);
    591    owning_controller_process_monitor = NULL;
    592 
    593    tor_free(owning_controller_process_spec);
    594    owning_controller_process_spec = NULL;
    595  }
    596 
    597  tor_assert((owning_controller_process_spec == NULL) &&
    598             (owning_controller_process_monitor == NULL));
    599 
    600  if (process_spec == NULL)
    601    return;
    602 
    603  owning_controller_process_spec = tor_strdup(process_spec);
    604  owning_controller_process_monitor =
    605    tor_process_monitor_new(tor_libevent_get_base(),
    606                            owning_controller_process_spec,
    607                            LD_CONTROL,
    608                            owning_controller_procmon_cb, NULL,
    609                            &msg);
    610 
    611  if (owning_controller_process_monitor == NULL) {
    612    log_err(LD_BUG, "Couldn't create process-termination monitor for "
    613            "owning controller: %s.  Exiting.",
    614            msg);
    615    owning_controller_process_spec = NULL;
    616    tor_shutdown_event_loop_and_exit(1);
    617  }
    618 }
    619 
    620 /** Free any leftover allocated memory of the control.c subsystem. */
    621 void
    622 control_free_all(void)
    623 {
    624  control_auth_free_all();
    625  control_events_free_all();
    626  control_cmd_free_all();
    627  control_event_bootstrap_reset();
    628 }