Coverage Report

Created: 2025-07-11 06:57

/src/tor/src/feature/control/control.c
Line
Count
Source (jump to first uncovered line)
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
0
{
73
0
  tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
74
0
  return DOWNCAST(control_connection_t, c);
75
0
}
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
0
{
86
0
  return TO_CONTROL_CONN((connection_t*)c);
87
0
}
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
0
{
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
0
  }
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
0
  }
124
125
0
  if (is_authenticated) {
126
0
    conn->state = CONTROL_CONN_STATE_OPEN;
127
0
  }
128
129
0
  return 0;
130
0
}
131
132
/** Write all of the open control ports to ControlPortWriteToFile */
133
void
134
control_ports_write_to_file(void)
135
0
{
136
0
  smartlist_t *lines;
137
0
  char *joined = NULL;
138
0
  const or_options_t *options = get_options();
139
140
0
  if (!options->ControlPortWriteToFile)
141
0
    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
0
#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
0
    }
153
0
#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
0
             options->ControlPortWriteToFile, strerror(errno));
162
0
  }
163
0
#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
0
               options->ControlPortWriteToFile);
168
0
    }
169
0
  }
170
0
#endif /* !defined(_WIN32) */
171
0
  tor_free(joined);
172
0
  SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
173
0
  smartlist_free(lines);
174
0
}
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
0
{
203
0
  tor_assert(conn);
204
0
  return 0;
205
0
}
206
207
/** Called when <b>conn</b> has gotten its socket closed. */
208
int
209
connection_control_reached_eof(control_connection_t *conn)
210
0
{
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
0
}
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
0
{
223
0
  log_notice(LD_CONTROL, "Owning controller %s has %s -- exiting now.",
224
0
             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
connection_control_closed(control_connection_t *conn)
232
0
{
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
0
      } else {
246
        /* An invalid .onion in our list should NEVER happen */
247
0
        tor_fragile_assert();
248
0
      }
249
0
    } SMARTLIST_FOREACH_END(cp);
250
0
  }
251
252
0
  if (conn->is_owning_control_connection) {
253
0
    lost_owning_controller("connection", "closed");
254
0
  }
255
256
0
  control_remove_authenticated_connection(conn);
257
0
}
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
0
{
264
0
  if (conn->base_.state == CONTROL_CONN_STATE_OPEN)
265
0
    return 1;
266
0
  if (!strcasecmp(cmd, "PROTOCOLINFO"))
267
0
    return (!conn->have_sent_protocolinfo &&
268
0
            conn->safecookie_client_hash == NULL);
269
0
  if (!strcasecmp(cmd, "AUTHCHALLENGE"))
270
0
    return (conn->safecookie_client_hash == NULL);
271
0
  if (!strcasecmp(cmd, "AUTHENTICATE") ||
272
0
      !strcasecmp(cmd, "QUIT"))
273
0
    return 1;
274
0
  return 0;
275
0
}
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
0
#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
0
{
289
0
  return peek_buf_has_control0_command(conn->inbuf);
290
0
}
291
292
static int
293
peek_connection_has_http_command(connection_t *conn)
294
0
{
295
0
  return peek_buf_has_http_command(conn->inbuf);
296
0
}
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
0
{
309
0
  const bool is_multiline = *data_len && incoming_cmd[0] == '+';
310
0
  size_t cmd_len = 0;
311
0
  while (cmd_len < *data_len
312
0
         && !TOR_ISSPACE(incoming_cmd[cmd_len]))
313
0
    ++cmd_len;
314
315
0
  *current_cmd_out = tor_memdup_nulterm(incoming_cmd, cmd_len);
316
0
  char *args = incoming_cmd+cmd_len;
317
0
  tor_assert(*data_len>=cmd_len);
318
0
  *data_len -= cmd_len;
319
0
  if (is_multiline) {
320
    // Only match horizontal space: any line after the first is data,
321
    // not arguments.
322
0
    while ((*args == '\t' || *args == ' ') && *data_len) {
323
0
      ++args;
324
0
      --*data_len;
325
0
    }
326
0
  } else {
327
0
    while (TOR_ISSPACE(*args) && *data_len) {
328
0
      ++args;
329
0
      --*data_len;
330
0
    }
331
0
  }
332
333
0
  return args;
334
0
}
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
0
{
367
0
  size_t body_len;
368
0
  char buf[128];
369
0
  set_uint16(buf+2, htons(0x0000)); /* type == error */
370
0
  set_uint16(buf+4, htons(0x0001)); /* code == internal error */
371
0
  strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 "
372
0
          "and later; upgrade your controller.",
373
0
          sizeof(buf)-6);
374
0
  body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */
375
0
  set_uint16(buf+0, htons(body_len));
376
0
  connection_buf_add(buf, 4+body_len, TO_CONN(conn));
377
378
0
  connection_mark_and_flush(TO_CONN(conn));
379
0
}
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
0
{
386
0
  connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn);
387
0
  log_notice(LD_CONTROL, "Received HTTP request on ControlPort");
388
0
  connection_mark_and_flush(TO_CONN(conn));
389
0
}
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
0
{
399
  /* Detect v0 commands and send a "no more v0" message. */
400
0
  if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
401
0
      peek_connection_has_control0_command(TO_CONN(conn))) {
402
0
    control_send_v0_reject(conn);
403
0
    return 0;
404
0
  }
405
406
  /* If the user has the HTTP proxy port and the control port confused. */
407
0
  if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
408
0
      peek_connection_has_http_command(TO_CONN(conn))) {
409
0
    control_send_http_reject(conn);
410
0
    return 0;
411
0
  }
412
413
0
  return 1;
414
0
}
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
0
{
422
0
  size_t data_len;
423
0
  uint32_t cmd_data_len;
424
0
  char *args;
425
426
0
  tor_assert(conn);
427
0
  tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN ||
428
0
             conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH);
429
430
0
  if (!conn->incoming_cmd) {
431
0
    conn->incoming_cmd = tor_malloc(1024);
432
0
    conn->incoming_cmd_len = 1024;
433
0
    conn->incoming_cmd_cur_len = 0;
434
0
  }
435
436
0
  if (!control_protocol_is_valid(conn)) {
437
0
    return 0;
438
0
  }
439
440
0
 again:
441
0
  while (1) {
442
0
    size_t last_idx;
443
0
    int r;
444
    /* First, fetch a line. */
445
0
    do {
446
0
      data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len;
447
0
      r = connection_buf_get_line(TO_CONN(conn),
448
0
                              conn->incoming_cmd+conn->incoming_cmd_cur_len,
449
0
                              &data_len);
450
0
      if (r == 0)
451
        /* Line not all here yet. Wait. */
452
0
        return 0;
453
0
      else if (r == -1) {
454
0
        if (data_len + conn->incoming_cmd_cur_len > MAX_COMMAND_LINE_LENGTH) {
455
0
          control_write_endreply(conn, 500, "Line too long.");
456
0
          connection_stop_reading(TO_CONN(conn));
457
0
          connection_mark_and_flush(TO_CONN(conn));
458
0
        }
459
0
        while (conn->incoming_cmd_len < data_len+conn->incoming_cmd_cur_len)
460
0
          conn->incoming_cmd_len *= 2;
461
0
        conn->incoming_cmd = tor_realloc(conn->incoming_cmd,
462
0
                                         conn->incoming_cmd_len);
463
0
      }
464
0
    } while (r != 1);
465
466
0
    tor_assert(data_len);
467
468
0
    last_idx = conn->incoming_cmd_cur_len;
469
0
    conn->incoming_cmd_cur_len += (int)data_len;
470
471
    /* We have appended a line to incoming_cmd.  Is the command done? */
472
0
    if (last_idx == 0 && *conn->incoming_cmd != '+')
473
      /* One line command, didn't start with '+'. */
474
0
      break;
475
    /* XXXX this code duplication is kind of dumb. */
476
0
    if (last_idx+3 == conn->incoming_cmd_cur_len &&
477
0
        tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) {
478
      /* Just appended ".\r\n"; we're done. Remove it. */
479
0
      conn->incoming_cmd[last_idx] = '\0';
480
0
      conn->incoming_cmd_cur_len -= 3;
481
0
      break;
482
0
    } else if (last_idx+2 == conn->incoming_cmd_cur_len &&
483
0
               tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) {
484
      /* Just appended ".\n"; we're done. Remove it. */
485
0
      conn->incoming_cmd[last_idx] = '\0';
486
0
      conn->incoming_cmd_cur_len -= 2;
487
0
      break;
488
0
    }
489
    /* Otherwise, read another line. */
490
0
  }
491
0
  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
0
  tor_free(conn->current_cmd);
497
0
  args = control_split_incoming_command(conn->incoming_cmd, &data_len,
498
0
                                        &conn->current_cmd);
499
0
  if (BUG(!conn->current_cmd))
500
0
    return -1;
501
502
  /* If the connection is already closing, ignore further commands */
503
0
  if (TO_CONN(conn)->marked_for_close) {
504
0
    return 0;
505
0
  }
506
507
  /* Otherwise, Quit is always valid. */
508
0
  if (!strcasecmp(conn->current_cmd, "QUIT")) {
509
0
    control_write_endreply(conn, 250, "closing connection");
510
0
    connection_mark_and_flush(TO_CONN(conn));
511
0
    return 0;
512
0
  }
513
514
0
  if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
515
0
      !is_valid_initial_command(conn, conn->current_cmd)) {
516
0
    control_write_endreply(conn, 514, "Authentication required.");
517
0
    connection_mark_for_close(TO_CONN(conn));
518
0
    return 0;
519
0
  }
520
521
0
  if (data_len >= UINT32_MAX) {
522
0
    control_write_endreply(conn, 500, "A 4GB command? Nice try.");
523
0
    connection_mark_for_close(TO_CONN(conn));
524
0
    return 0;
525
0
  }
526
527
0
  cmd_data_len = (uint32_t)data_len;
528
0
  if (handle_control_command(conn, cmd_data_len, args) < 0)
529
0
    return -1;
530
531
0
  conn->incoming_cmd_cur_len = 0;
532
0
  goto again;
533
0
}
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
0
{
543
0
  return network_is_live;
544
0
}
545
546
void
547
set_cached_network_liveness(int liveness)
548
0
{
549
0
  network_is_live = liveness;
550
0
}
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
0
{
565
0
  (void)unused;
566
567
0
  lost_owning_controller("process", "vanished");
568
0
}
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
0
{
575
0
  const char *msg;
576
577
0
  tor_assert((owning_controller_process_spec == NULL) ==
578
0
             (owning_controller_process_monitor == NULL));
579
580
0
  if (owning_controller_process_spec != NULL) {
581
0
    if ((process_spec != NULL) && !strcmp(process_spec,
582
0
                                          owning_controller_process_spec)) {
583
      /* Same process -- return now, instead of disposing of and
584
       * recreating the process-termination monitor. */
585
0
      return;
586
0
    }
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
0
    tor_process_monitor_free(owning_controller_process_monitor);
591
0
    owning_controller_process_monitor = NULL;
592
593
0
    tor_free(owning_controller_process_spec);
594
0
    owning_controller_process_spec = NULL;
595
0
  }
596
597
0
  tor_assert((owning_controller_process_spec == NULL) &&
598
0
             (owning_controller_process_monitor == NULL));
599
600
0
  if (process_spec == NULL)
601
0
    return;
602
603
0
  owning_controller_process_spec = tor_strdup(process_spec);
604
0
  owning_controller_process_monitor =
605
0
    tor_process_monitor_new(tor_libevent_get_base(),
606
0
                            owning_controller_process_spec,
607
0
                            LD_CONTROL,
608
0
                            owning_controller_procmon_cb, NULL,
609
0
                            &msg);
610
611
0
  if (owning_controller_process_monitor == NULL) {
612
0
    log_err(LD_BUG, "Couldn't create process-termination monitor for "
613
0
            "owning controller: %s.  Exiting.",
614
0
            msg);
615
0
    owning_controller_process_spec = NULL;
616
0
    tor_shutdown_event_loop_and_exit(1);
617
0
  }
618
0
}
619
620
/** Free any leftover allocated memory of the control.c subsystem. */
621
void
622
control_free_all(void)
623
0
{
624
0
  control_auth_free_all();
625
0
  control_events_free_all();
626
0
  control_cmd_free_all();
627
0
  control_event_bootstrap_reset();
628
0
}