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 : }
|