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