LCOV - code coverage report
Current view: top level - feature/control - control.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 24 233 10.3 %
Date: 2021-11-24 03:28:48 Functions: 5 21 23.8 %

          Line data    Source code
       1             : /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       2             :  * Copyright (c) 2007-2021, 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           0 : TO_CONTROL_CONN(connection_t *c)
      72             : {
      73           0 :   tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
      74           0 :   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           0 : CONST_TO_CONTROL_CONN(const connection_t *c)
      85             : {
      86           0 :   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           0 : control_connection_add_local_fd(tor_socket_t sock, unsigned flags)
      96             : {
      97           0 :   if (BUG(! SOCKET_OK(sock)))
      98           0 :     return -1;
      99           0 :   const int is_owner = !!(flags & CC_LOCAL_FD_IS_OWNER);
     100           0 :   const int is_authenticated = !!(flags & CC_LOCAL_FD_IS_AUTHENTICATED);
     101           0 :   control_connection_t *control_conn = control_connection_new(AF_UNSPEC);
     102           0 :   connection_t *conn = TO_CONN(control_conn);
     103           0 :   conn->s = sock;
     104           0 :   tor_addr_make_unspec(&conn->addr);
     105           0 :   conn->port = 1;
     106           0 :   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           0 :   tor_take_socket_ownership(sock);
     111             : 
     112           0 :   if (set_socket_nonblocking(sock) < 0 ||
     113           0 :       connection_add(conn) < 0) {
     114           0 :     connection_free(conn);
     115           0 :     return -1;
     116             :   }
     117             : 
     118           0 :   control_conn->is_owning_control_connection = is_owner;
     119             : 
     120           0 :   if (connection_init_accepted_conn(conn, NULL) < 0) {
     121           0 :     connection_mark_for_close(conn);
     122           0 :     return -1;
     123             :   }
     124             : 
     125           0 :   if (is_authenticated) {
     126           0 :     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         213 : control_ports_write_to_file(void)
     135             : {
     136         213 :   smartlist_t *lines;
     137         213 :   char *joined = NULL;
     138         213 :   const or_options_t *options = get_options();
     139             : 
     140         213 :   if (!options->ControlPortWriteToFile)
     141         213 :     return;
     142             : 
     143           0 :   lines = smartlist_new();
     144             : 
     145           0 :   SMARTLIST_FOREACH_BEGIN(get_connection_array(), const connection_t *, conn) {
     146           0 :     if (conn->type != CONN_TYPE_CONTROL_LISTENER || conn->marked_for_close)
     147           0 :       continue;
     148             : #ifdef AF_UNIX
     149           0 :     if (conn->socket_family == AF_UNIX) {
     150           0 :       smartlist_add_asprintf(lines, "UNIX_PORT=%s\n", conn->address);
     151           0 :       continue;
     152             :     }
     153             : #endif /* defined(AF_UNIX) */
     154           0 :     smartlist_add_asprintf(lines, "PORT=%s:%d\n", conn->address, conn->port);
     155           0 :   } SMARTLIST_FOREACH_END(conn);
     156             : 
     157           0 :   joined = smartlist_join_strings(lines, "", 0, NULL);
     158             : 
     159           0 :   if (write_str_to_file(options->ControlPortWriteToFile, joined, 0) < 0) {
     160           0 :     log_warn(LD_CONTROL, "Writing %s failed: %s",
     161             :              options->ControlPortWriteToFile, strerror(errno));
     162             :   }
     163             : #ifndef _WIN32
     164           0 :   if (options->ControlPortFileGroupReadable) {
     165           0 :     if (chmod(options->ControlPortWriteToFile, 0640)) {
     166           0 :       log_warn(LD_FS,"Unable to make %s group-readable.",
     167             :                options->ControlPortWriteToFile);
     168             :     }
     169             :   }
     170             : #endif /* !defined(_WIN32) */
     171           0 :   tor_free(joined);
     172           0 :   SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
     173           0 :   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           0 : connection_control_finished_flushing(control_connection_t *conn)
     202             : {
     203           0 :   tor_assert(conn);
     204           0 :   return 0;
     205             : }
     206             : 
     207             : /** Called when <b>conn</b> has gotten its socket closed. */
     208             : int
     209           0 : connection_control_reached_eof(control_connection_t *conn)
     210             : {
     211           0 :   tor_assert(conn);
     212             : 
     213           0 :   log_info(LD_CONTROL,"Control connection reached EOF. Closing.");
     214           0 :   connection_mark_for_close(TO_CONN(conn));
     215           0 :   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           0 : lost_owning_controller(const char *owner_type, const char *loss_manner)
     222             : {
     223           0 :   log_notice(LD_CONTROL, "Owning controller %s has %s -- exiting now.",
     224             :              owner_type, loss_manner);
     225             : 
     226           0 :   activate_signal(SIGTERM);
     227           0 : }
     228             : 
     229             : /** Called when <b>conn</b> is being freed. */
     230             : void
     231           0 : connection_control_closed(control_connection_t *conn)
     232             : {
     233           0 :   tor_assert(conn);
     234             : 
     235           0 :   conn->event_mask = 0;
     236           0 :   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           0 :   if (conn->ephemeral_onion_services) {
     242           0 :     SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) {
     243           0 :       if (hs_address_is_valid(cp)) {
     244           0 :         hs_service_del_ephemeral(cp);
     245             :       } else {
     246             :         /* An invalid .onion in our list should NEVER happen */
     247           0 :         tor_fragile_assert();
     248             :       }
     249           0 :     } SMARTLIST_FOREACH_END(cp);
     250             :   }
     251             : 
     252           0 :   if (conn->is_owning_control_connection) {
     253           0 :     lost_owning_controller("connection", "closed");
     254             :   }
     255           0 : }
     256             : 
     257             : /** Return true iff <b>cmd</b> is allowable (or at least forgivable) at this
     258             :  * stage of the protocol. */
     259             : static int
     260           0 : is_valid_initial_command(control_connection_t *conn, const char *cmd)
     261             : {
     262           0 :   if (conn->base_.state == CONTROL_CONN_STATE_OPEN)
     263             :     return 1;
     264           0 :   if (!strcasecmp(cmd, "PROTOCOLINFO"))
     265           0 :     return (!conn->have_sent_protocolinfo &&
     266           0 :             conn->safecookie_client_hash == NULL);
     267           0 :   if (!strcasecmp(cmd, "AUTHCHALLENGE"))
     268           0 :     return (conn->safecookie_client_hash == NULL);
     269           0 :   if (!strcasecmp(cmd, "AUTHENTICATE") ||
     270           0 :       !strcasecmp(cmd, "QUIT"))
     271           0 :     return 1;
     272             :   return 0;
     273             : }
     274             : 
     275             : /** Do not accept any control command of more than 1MB in length.  Anything
     276             :  * that needs to be anywhere near this long probably means that one of our
     277             :  * interfaces is broken. */
     278             : #define MAX_COMMAND_LINE_LENGTH (1024*1024)
     279             : 
     280             : /** Wrapper around peek_buf_has_control0 command: presents the same
     281             :  * interface as that underlying functions, but takes a connection_t instead of
     282             :  * a buf_t.
     283             :  */
     284             : static int
     285           0 : peek_connection_has_control0_command(connection_t *conn)
     286             : {
     287           0 :   return peek_buf_has_control0_command(conn->inbuf);
     288             : }
     289             : 
     290             : static int
     291           0 : peek_connection_has_http_command(connection_t *conn)
     292             : {
     293           0 :   return peek_buf_has_http_command(conn->inbuf);
     294             : }
     295             : 
     296             : /**
     297             :  * Helper: take a nul-terminated command of given length, and find where the
     298             :  * command starts and the arguments begin.  Separate them, allocate a new
     299             :  * string in <b>current_cmd_out</b> for the command, and return a pointer
     300             :  * to the arguments.
     301             :  **/
     302             : STATIC char *
     303           0 : control_split_incoming_command(char *incoming_cmd,
     304             :                                size_t *data_len,
     305             :                                char **current_cmd_out)
     306             : {
     307           0 :   const bool is_multiline = *data_len && incoming_cmd[0] == '+';
     308           0 :   size_t cmd_len = 0;
     309           0 :   while (cmd_len < *data_len
     310           0 :          && !TOR_ISSPACE(incoming_cmd[cmd_len]))
     311           0 :     ++cmd_len;
     312             : 
     313           0 :   *current_cmd_out = tor_memdup_nulterm(incoming_cmd, cmd_len);
     314           0 :   char *args = incoming_cmd+cmd_len;
     315           0 :   tor_assert(*data_len>=cmd_len);
     316           0 :   *data_len -= cmd_len;
     317           0 :   if (is_multiline) {
     318             :     // Only match horizontal space: any line after the first is data,
     319             :     // not arguments.
     320           0 :     while ((*args == '\t' || *args == ' ') && *data_len) {
     321           0 :       ++args;
     322           0 :       --*data_len;
     323             :     }
     324             :   } else {
     325           0 :     while (TOR_ISSPACE(*args) && *data_len) {
     326           0 :       ++args;
     327           0 :       --*data_len;
     328             :     }
     329             :   }
     330             : 
     331           0 :   return args;
     332             : }
     333             : 
     334             : static const char CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG[] =
     335             :   "HTTP/1.0 501 Tor ControlPort is not an HTTP proxy"
     336             :   "\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n"
     337             :   "<html>\n"
     338             :   "<head>\n"
     339             :   "<title>Tor's ControlPort is not an HTTP proxy</title>\n"
     340             :   "</head>\n"
     341             :   "<body>\n"
     342             :   "<h1>Tor's ControlPort is not an HTTP proxy</h1>\n"
     343             :   "<p>\n"
     344             :   "It appears you have configured your web browser to use Tor's control port"
     345             :   " as an HTTP proxy.\n"
     346             :   "This is not correct: Tor's default SOCKS proxy port is 9050.\n"
     347             :   "Please configure your client accordingly.\n"
     348             :   "</p>\n"
     349             :   "<p>\n"
     350             :   "See <a href=\"https://www.torproject.org/documentation.html\">"
     351             :   "https://www.torproject.org/documentation.html</a> for more "
     352             :   "information.\n"
     353             :   "<!-- Plus this comment, to make the body response more than 512 bytes, so "
     354             :   "     IE will be willing to display it. Comment comment comment comment "
     355             :   "     comment comment comment comment comment comment comment comment.-->\n"
     356             :   "</p>\n"
     357             :   "</body>\n"
     358             :   "</html>\n";
     359             : 
     360             : /** Return an error on a control connection that tried to use the v0 protocol.
     361             :  */
     362             : static void
     363           0 : control_send_v0_reject(control_connection_t *conn)
     364             : {
     365           0 :   size_t body_len;
     366           0 :   char buf[128];
     367           0 :   set_uint16(buf+2, htons(0x0000)); /* type == error */
     368           0 :   set_uint16(buf+4, htons(0x0001)); /* code == internal error */
     369           0 :   strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 "
     370             :           "and later; upgrade your controller.",
     371             :           sizeof(buf)-6);
     372           0 :   body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */
     373           0 :   set_uint16(buf+0, htons(body_len));
     374           0 :   connection_buf_add(buf, 4+body_len, TO_CONN(conn));
     375             : 
     376           0 :   connection_mark_and_flush(TO_CONN(conn));
     377           0 : }
     378             : 
     379             : /** Return an error on a control connection that tried to use HTTP.
     380             :  */
     381             : static void
     382           0 : control_send_http_reject(control_connection_t *conn)
     383             : {
     384           0 :   connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn);
     385           0 :   log_notice(LD_CONTROL, "Received HTTP request on ControlPort");
     386           0 :   connection_mark_and_flush(TO_CONN(conn));
     387           0 : }
     388             : 
     389             : /** Check if a control connection has tried to use a known invalid protocol.
     390             :  * If it has, then:
     391             :  *  - send a reject response,
     392             :  *  - log a notice-level message, and
     393             :  *  - return false. */
     394             : static bool
     395           0 : control_protocol_is_valid(control_connection_t *conn)
     396             : {
     397             :   /* Detect v0 commands and send a "no more v0" message. */
     398           0 :   if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
     399           0 :       peek_connection_has_control0_command(TO_CONN(conn))) {
     400           0 :     control_send_v0_reject(conn);
     401           0 :     return 0;
     402             :   }
     403             : 
     404             :   /* If the user has the HTTP proxy port and the control port confused. */
     405           0 :   if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
     406           0 :       peek_connection_has_http_command(TO_CONN(conn))) {
     407           0 :     control_send_http_reject(conn);
     408           0 :     return 0;
     409             :   }
     410             : 
     411             :   return 1;
     412             : }
     413             : 
     414             : /** Called when data has arrived on a v1 control connection: Try to fetch
     415             :  * commands from conn->inbuf, and execute them.
     416             :  */
     417             : int
     418           0 : connection_control_process_inbuf(control_connection_t *conn)
     419             : {
     420           0 :   size_t data_len;
     421           0 :   uint32_t cmd_data_len;
     422           0 :   char *args;
     423             : 
     424           0 :   tor_assert(conn);
     425           0 :   tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN ||
     426             :              conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH);
     427             : 
     428           0 :   if (!conn->incoming_cmd) {
     429           0 :     conn->incoming_cmd = tor_malloc(1024);
     430           0 :     conn->incoming_cmd_len = 1024;
     431           0 :     conn->incoming_cmd_cur_len = 0;
     432             :   }
     433             : 
     434           0 :   if (!control_protocol_is_valid(conn)) {
     435             :     return 0;
     436             :   }
     437             : 
     438           0 :  again:
     439           0 :   while (1) {
     440           0 :     size_t last_idx;
     441           0 :     int r;
     442             :     /* First, fetch a line. */
     443           0 :     do {
     444           0 :       data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len;
     445           0 :       r = connection_buf_get_line(TO_CONN(conn),
     446           0 :                               conn->incoming_cmd+conn->incoming_cmd_cur_len,
     447             :                               &data_len);
     448           0 :       if (r == 0)
     449             :         /* Line not all here yet. Wait. */
     450             :         return 0;
     451           0 :       else if (r == -1) {
     452           0 :         if (data_len + conn->incoming_cmd_cur_len > MAX_COMMAND_LINE_LENGTH) {
     453           0 :           control_write_endreply(conn, 500, "Line too long.");
     454           0 :           connection_stop_reading(TO_CONN(conn));
     455           0 :           connection_mark_and_flush(TO_CONN(conn));
     456             :         }
     457           0 :         while (conn->incoming_cmd_len < data_len+conn->incoming_cmd_cur_len)
     458           0 :           conn->incoming_cmd_len *= 2;
     459           0 :         conn->incoming_cmd = tor_realloc(conn->incoming_cmd,
     460             :                                          conn->incoming_cmd_len);
     461             :       }
     462           0 :     } while (r != 1);
     463             : 
     464           0 :     tor_assert(data_len);
     465             : 
     466           0 :     last_idx = conn->incoming_cmd_cur_len;
     467           0 :     conn->incoming_cmd_cur_len += (int)data_len;
     468             : 
     469             :     /* We have appended a line to incoming_cmd.  Is the command done? */
     470           0 :     if (last_idx == 0 && *conn->incoming_cmd != '+')
     471             :       /* One line command, didn't start with '+'. */
     472             :       break;
     473             :     /* XXXX this code duplication is kind of dumb. */
     474           0 :     if (last_idx+3 == conn->incoming_cmd_cur_len &&
     475           0 :         tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) {
     476             :       /* Just appended ".\r\n"; we're done. Remove it. */
     477           0 :       conn->incoming_cmd[last_idx] = '\0';
     478           0 :       conn->incoming_cmd_cur_len -= 3;
     479           0 :       break;
     480           0 :     } else if (last_idx+2 == conn->incoming_cmd_cur_len &&
     481           0 :                tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) {
     482             :       /* Just appended ".\n"; we're done. Remove it. */
     483           0 :       conn->incoming_cmd[last_idx] = '\0';
     484           0 :       conn->incoming_cmd_cur_len -= 2;
     485           0 :       break;
     486             :     }
     487             :     /* Otherwise, read another line. */
     488             :   }
     489           0 :   data_len = conn->incoming_cmd_cur_len;
     490             : 
     491             :   /* Okay, we now have a command sitting on conn->incoming_cmd. See if we
     492             :    * recognize it.
     493             :    */
     494           0 :   tor_free(conn->current_cmd);
     495           0 :   args = control_split_incoming_command(conn->incoming_cmd, &data_len,
     496             :                                         &conn->current_cmd);
     497           0 :   if (BUG(!conn->current_cmd))
     498           0 :     return -1;
     499             : 
     500             :   /* If the connection is already closing, ignore further commands */
     501           0 :   if (TO_CONN(conn)->marked_for_close) {
     502             :     return 0;
     503             :   }
     504             : 
     505             :   /* Otherwise, Quit is always valid. */
     506           0 :   if (!strcasecmp(conn->current_cmd, "QUIT")) {
     507           0 :     control_write_endreply(conn, 250, "closing connection");
     508           0 :     connection_mark_and_flush(TO_CONN(conn));
     509           0 :     return 0;
     510             :   }
     511             : 
     512           0 :   if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
     513           0 :       !is_valid_initial_command(conn, conn->current_cmd)) {
     514           0 :     control_write_endreply(conn, 514, "Authentication required.");
     515           0 :     connection_mark_for_close(TO_CONN(conn));
     516           0 :     return 0;
     517             :   }
     518             : 
     519           0 :   if (data_len >= UINT32_MAX) {
     520           0 :     control_write_endreply(conn, 500, "A 4GB command? Nice try.");
     521           0 :     connection_mark_for_close(TO_CONN(conn));
     522           0 :     return 0;
     523             :   }
     524             : 
     525           0 :   cmd_data_len = (uint32_t)data_len;
     526           0 :   if (handle_control_command(conn, cmd_data_len, args) < 0)
     527             :     return -1;
     528             : 
     529           0 :   conn->incoming_cmd_cur_len = 0;
     530           0 :   goto again;
     531             : }
     532             : 
     533             : /** Cached liveness for network liveness events and GETINFO
     534             :  */
     535             : 
     536             : static int network_is_live = 0;
     537             : 
     538             : int
     539         221 : get_cached_network_liveness(void)
     540             : {
     541         221 :   return network_is_live;
     542             : }
     543             : 
     544             : void
     545         107 : set_cached_network_liveness(int liveness)
     546             : {
     547         107 :   network_is_live = liveness;
     548         107 : }
     549             : 
     550             : /** A copy of the process specifier of Tor's owning controller, or
     551             :  * NULL if this Tor instance is not currently owned by a process. */
     552             : static char *owning_controller_process_spec = NULL;
     553             : 
     554             : /** A process-termination monitor for Tor's owning controller, or NULL
     555             :  * if this Tor instance is not currently owned by a process. */
     556             : static tor_process_monitor_t *owning_controller_process_monitor = NULL;
     557             : 
     558             : /** Process-termination monitor callback for Tor's owning controller
     559             :  * process. */
     560             : static void
     561           0 : owning_controller_procmon_cb(void *unused)
     562             : {
     563           0 :   (void)unused;
     564             : 
     565           0 :   lost_owning_controller("process", "vanished");
     566           0 : }
     567             : 
     568             : /** Set <b>process_spec</b> as Tor's owning controller process.
     569             :  * Exit on failure. */
     570             : void
     571           4 : monitor_owning_controller_process(const char *process_spec)
     572             : {
     573           4 :   const char *msg;
     574             : 
     575           4 :   tor_assert((owning_controller_process_spec == NULL) ==
     576             :              (owning_controller_process_monitor == NULL));
     577             : 
     578           4 :   if (owning_controller_process_spec != NULL) {
     579           0 :     if ((process_spec != NULL) && !strcmp(process_spec,
     580             :                                           owning_controller_process_spec)) {
     581             :       /* Same process -- return now, instead of disposing of and
     582             :        * recreating the process-termination monitor. */
     583           4 :       return;
     584             :     }
     585             : 
     586             :     /* We are currently owned by a process, and we should no longer be
     587             :      * owned by it.  Free the process-termination monitor. */
     588           0 :     tor_process_monitor_free(owning_controller_process_monitor);
     589           0 :     owning_controller_process_monitor = NULL;
     590             : 
     591           0 :     tor_free(owning_controller_process_spec);
     592           0 :     owning_controller_process_spec = NULL;
     593             :   }
     594             : 
     595           4 :   tor_assert((owning_controller_process_spec == NULL) &&
     596             :              (owning_controller_process_monitor == NULL));
     597             : 
     598           4 :   if (process_spec == NULL)
     599             :     return;
     600             : 
     601           0 :   owning_controller_process_spec = tor_strdup(process_spec);
     602           0 :   owning_controller_process_monitor =
     603           0 :     tor_process_monitor_new(tor_libevent_get_base(),
     604             :                             owning_controller_process_spec,
     605             :                             LD_CONTROL,
     606             :                             owning_controller_procmon_cb, NULL,
     607             :                             &msg);
     608             : 
     609           0 :   if (owning_controller_process_monitor == NULL) {
     610           0 :     log_err(LD_BUG, "Couldn't create process-termination monitor for "
     611             :             "owning controller: %s.  Exiting.",
     612             :             msg);
     613           0 :     owning_controller_process_spec = NULL;
     614           0 :     tor_shutdown_event_loop_and_exit(1);
     615             :   }
     616             : }
     617             : 
     618             : /** Free any leftover allocated memory of the control.c subsystem. */
     619             : void
     620         235 : control_free_all(void)
     621             : {
     622         235 :   control_auth_free_all();
     623         235 :   control_events_free_all();
     624         235 :   control_cmd_free_all();
     625         235 :   control_event_bootstrap_reset();
     626         235 : }

Generated by: LCOV version 1.14