Line data Source code
1 : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file hs_config.c
6 : * \brief Implement hidden service configuration subsystem.
7 : *
8 : * \details
9 : *
10 : * This file has basically one main entry point: hs_config_service_all(). It
11 : * takes the torrc options and configure hidden service from it. In validate
12 : * mode, nothing is added to the global service list or keys are not generated
13 : * nor loaded.
14 : *
15 : * A service is configured in two steps. It is first created using the tor
16 : * options and then put in a staging list. It will stay there until
17 : * hs_service_load_all_keys() is called. That function is responsible to
18 : * load/generate the keys for the service in the staging list and if
19 : * successful, transferred the service to the main global service list where
20 : * at that point it is ready to be used.
21 : *
22 : * Configuration functions are per-version and there is a main generic one for
23 : * every option that is common to all version (config_generic_service).
24 : **/
25 :
26 : #include "feature/hs/hs_common.h"
27 : #include "feature/hs/hs_config.h"
28 : #include "feature/hs/hs_client.h"
29 : #include "feature/hs/hs_ob.h"
30 : #include "feature/hs/hs_service.h"
31 : #include "lib/encoding/confline.h"
32 : #include "lib/conf/confdecl.h"
33 : #include "lib/confmgt/confmgt.h"
34 :
35 : #include "feature/hs/hs_opts_st.h"
36 : #include "app/config/or_options_st.h"
37 :
38 : /* Declare the table mapping hs options to hs_opts_t */
39 : #define CONF_CONTEXT TABLE
40 : #include "feature/hs/hs_options.inc"
41 : #undef CONF_CONTEXT
42 :
43 : /** Magic number for hs_opts_t. */
44 : #define HS_OPTS_MAGIC 0x6f6e796e
45 :
46 : static const config_format_t hs_opts_fmt = {
47 : .size = sizeof(hs_opts_t),
48 : .magic = { "hs_opts_t",
49 : HS_OPTS_MAGIC,
50 : offsetof(hs_opts_t, magic) },
51 : .vars = hs_opts_t_vars,
52 : };
53 :
54 : /** Global configuration manager to handle HS sections*/
55 : static config_mgr_t *hs_opts_mgr = NULL;
56 :
57 : /**
58 : * Return a configuration manager for the hs_opts_t configuration type.
59 : **/
60 : static const config_mgr_t *
61 134 : get_hs_opts_mgr(void)
62 : {
63 134 : if (PREDICT_UNLIKELY(hs_opts_mgr == NULL)) {
64 15 : hs_opts_mgr = config_mgr_new(&hs_opts_fmt);
65 15 : config_mgr_freeze(hs_opts_mgr);
66 : }
67 134 : return hs_opts_mgr;
68 : }
69 :
70 : /**
71 : * Allocate, initialize, and return a new hs_opts_t.
72 : **/
73 : static hs_opts_t *
74 35 : hs_opts_new(void)
75 : {
76 35 : const config_mgr_t *mgr = get_hs_opts_mgr();
77 35 : hs_opts_t *r = config_new(mgr);
78 35 : tor_assert(r);
79 35 : config_init(mgr, r);
80 35 : return r;
81 : }
82 :
83 : /**
84 : * Free an hs_opts_t.
85 : **/
86 : #define hs_opts_free(opts) \
87 : config_free(get_hs_opts_mgr(), (opts))
88 :
89 : /** Using the given list of services, stage them into our global state. Every
90 : * service version are handled. This function can remove entries in the given
91 : * service_list.
92 : *
93 : * Staging a service means that we take all services in service_list and we
94 : * put them in the staging list (global) which acts as a temporary list that
95 : * is used by the service loading key process. In other words, staging a
96 : * service puts it in a list to be considered when loading the keys and then
97 : * moved to the main global list. */
98 : static void
99 10 : stage_services(smartlist_t *service_list)
100 : {
101 10 : tor_assert(service_list);
102 :
103 : /* This is >= v3 specific. Using the newly configured service list, stage
104 : * them into our global state. Every object ownership is lost after. */
105 10 : hs_service_stage_services(service_list);
106 10 : }
107 :
108 : /** Validate the given service against all service in the given list. If the
109 : * service is ephemeral, this function ignores it. Services with the same
110 : * directory path aren't allowed and will return an error. If a duplicate is
111 : * found, 1 is returned else 0 if none found. */
112 : static int
113 20 : service_is_duplicate_in_list(const smartlist_t *service_list,
114 : const hs_service_t *service)
115 : {
116 20 : int ret = 0;
117 :
118 20 : tor_assert(service_list);
119 20 : tor_assert(service);
120 :
121 : /* Ephemeral service don't have a directory configured so no need to check
122 : * for a service in the list having the same path. */
123 20 : if (service->config.is_ephemeral) {
124 0 : goto end;
125 : }
126 :
127 : /* XXX: Validate if we have any service that has the given service dir path.
128 : * This has two problems:
129 : *
130 : * a) It's O(n^2)
131 : *
132 : * b) We only compare directory paths as strings, so we can't
133 : * detect two distinct paths that specify the same directory
134 : * (which can arise from symlinks, case-insensitivity, bind
135 : * mounts, etc.).
136 : *
137 : * It also can't detect that two separate Tor instances are trying
138 : * to use the same HiddenServiceDir; for that, we would need a
139 : * lock file. But this is enough to detect a simple mistake that
140 : * at least one person has actually made. */
141 21 : SMARTLIST_FOREACH_BEGIN(service_list, const hs_service_t *, s) {
142 2 : if (!strcmp(s->config.directory_path, service->config.directory_path)) {
143 1 : log_warn(LD_REND, "Another hidden service is already configured "
144 : "for directory %s",
145 : escaped(service->config.directory_path));
146 1 : ret = 1;
147 1 : goto end;
148 : }
149 1 : } SMARTLIST_FOREACH_END(s);
150 :
151 19 : end:
152 20 : return ret;
153 : }
154 :
155 : /** Check whether an integer <b>i</b> is out of bounds (not between <b>low</b>
156 : * and <b>high</b> incusive). If it is, then log a warning about the option
157 : * <b>name</b>, and return true. Otherwise return false. */
158 : static bool
159 115 : check_value_oob(int i, const char *name, int low, int high)
160 : {
161 115 : if (i < low || i > high) {
162 4 : log_warn(LD_CONFIG, "%s must be between %d and %d, not %d.",
163 : name, low, high, i);
164 4 : return true;
165 : }
166 : return false;
167 : }
168 :
169 : /**
170 : * Helper: check whether the integer value called <b>name</b> in <b>opts</b>
171 : * is out-of-bounds.
172 : **/
173 : #define CHECK_OOB(opts, name, low, high) \
174 : check_value_oob((opts)->name, #name, (low), (high))
175 :
176 : /** Helper function: Given a configuration option and its value, parse the
177 : * value as a hs_circuit_id_protocol_t. On success, ok is set to 1 and ret is
178 : * the parse value. On error, ok is set to 0 and the "none"
179 : * hs_circuit_id_protocol_t is returned. This function logs on error. */
180 : static hs_circuit_id_protocol_t
181 0 : helper_parse_circuit_id_protocol(const char *key, const char *value, int *ok)
182 : {
183 0 : tor_assert(value);
184 0 : tor_assert(ok);
185 :
186 0 : hs_circuit_id_protocol_t ret = HS_CIRCUIT_ID_PROTOCOL_NONE;
187 0 : *ok = 0;
188 :
189 0 : if (! strcasecmp(value, "haproxy")) {
190 0 : *ok = 1;
191 0 : ret = HS_CIRCUIT_ID_PROTOCOL_HAPROXY;
192 0 : } else if (! strcasecmp(value, "none")) {
193 0 : *ok = 1;
194 0 : ret = HS_CIRCUIT_ID_PROTOCOL_NONE;
195 : } else {
196 0 : log_warn(LD_CONFIG, "%s must be 'haproxy' or 'none'.", key);
197 0 : goto err;
198 : }
199 :
200 0 : err:
201 0 : return ret;
202 : }
203 :
204 : /** Return the service version by trying to learn it from the key on disk if
205 : * any. If nothing is found, the current service configured version is
206 : * returned. */
207 : static int
208 11 : config_learn_service_version(hs_service_t *service)
209 : {
210 11 : int version;
211 :
212 11 : tor_assert(service);
213 :
214 11 : version = hs_service_get_version_from_key(service);
215 11 : if (version < 0) {
216 11 : version = service->config.version;
217 : }
218 :
219 11 : return version;
220 : }
221 :
222 : /**
223 : * Header key indicating the start of a new hidden service configuration
224 : * block.
225 : **/
226 : static const char SECTION_HEADER[] = "HiddenServiceDir";
227 :
228 : /** Return true iff the given options starting at line_ for a hidden service
229 : * contains at least one invalid option. Each hidden service option don't
230 : * apply to all versions so this function can find out. The line_ MUST start
231 : * right after the HiddenServiceDir line of this service.
232 : *
233 : * This is mainly for usability so we can inform the user of any invalid
234 : * option for the hidden service version instead of silently ignoring. */
235 : static int
236 25 : config_has_invalid_options(const config_line_t *line_,
237 : const hs_service_t *service)
238 : {
239 25 : int ret = 0;
240 25 : const char **optlist;
241 25 : const config_line_t *line;
242 :
243 25 : tor_assert(service);
244 25 : tor_assert(service->config.version <= HS_VERSION_MAX);
245 :
246 : /* List of options that a v3 service doesn't support thus must exclude from
247 : * its configuration. */
248 25 : const char *opts_exclude_v3[] = {
249 : "HiddenServiceAuthorizeClient",
250 : NULL /* End marker. */
251 : };
252 :
253 : /* Defining the size explicitly allows us to take advantage of the compiler
254 : * which warns us if we ever bump the max version but forget to grow this
255 : * array. The plus one is because we have a version 0 :). */
256 25 : struct {
257 : const char **list;
258 25 : } exclude_lists[HS_VERSION_MAX + 1] = {
259 : { NULL }, /* v0. */
260 : { NULL }, /* v1. */
261 : { NULL }, /* v2. */
262 : { opts_exclude_v3 }, /* v3. */
263 : };
264 :
265 25 : optlist = exclude_lists[service->config.version].list;
266 25 : if (optlist == NULL) {
267 : /* No exclude options to look at for this version. */
268 0 : goto end;
269 : }
270 50 : for (int i = 0; optlist[i]; i++) {
271 : const char *opt = optlist[i];
272 94 : for (line = line_; line; line = line->next) {
273 69 : if (!strcasecmp(line->key, SECTION_HEADER)) {
274 : /* We just hit the next hidden service, stop right now.
275 : * (This shouldn't be possible, now that we have partitioned the list
276 : * into sections.) */
277 0 : tor_assert_nonfatal_unreached();
278 0 : goto end;
279 : }
280 69 : if (!strcasecmp(line->key, opt)) {
281 0 : log_warn(LD_CONFIG, "Hidden service option %s is incompatible with "
282 : "version %" PRIu32 " of service in %s",
283 : opt, service->config.version,
284 : service->config.directory_path);
285 0 : ret = 1;
286 : /* Continue the loop so we can find all possible options. */
287 0 : continue;
288 : }
289 : }
290 : }
291 25 : end:
292 25 : return ret;
293 : }
294 :
295 : /** Validate service configuration. This is used when loading the configuration
296 : * and once we've setup a service object, it's config object is passed to this
297 : * function for further validation. This does not validate service key
298 : * material. Return 0 if valid else -1 if invalid. */
299 : static int
300 22 : config_validate_service(const hs_service_config_t *config)
301 : {
302 22 : tor_assert(config);
303 :
304 : /* Amount of ports validation. */
305 22 : if (!config->ports || smartlist_len(config->ports) == 0) {
306 1 : log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured.",
307 : escaped(config->directory_path));
308 1 : goto invalid;
309 : }
310 :
311 : /* DoS validation values. */
312 21 : if (config->has_dos_defense_enabled &&
313 2 : (config->intro_dos_burst_per_sec < config->intro_dos_rate_per_sec)) {
314 1 : log_warn(LD_CONFIG, "Hidden service DoS defenses burst (%" PRIu32 ") can "
315 : "not be smaller than the rate value (%" PRIu32 ").",
316 : config->intro_dos_burst_per_sec, config->intro_dos_rate_per_sec);
317 1 : goto invalid;
318 : }
319 :
320 : /* Valid. */
321 : return 0;
322 : invalid:
323 : return -1;
324 : }
325 :
326 : /** Configuration function for a version 3 service. The given service
327 : * object must be already allocated and passed through
328 : * config_generic_service() prior to calling this function.
329 : *
330 : * Return 0 on success else a negative value. */
331 : static int
332 25 : config_service_v3(const hs_opts_t *hs_opts,
333 : hs_service_config_t *config)
334 : {
335 25 : tor_assert(config);
336 25 : tor_assert(hs_opts);
337 :
338 : /* Number of introduction points. */
339 25 : if (CHECK_OOB(hs_opts, HiddenServiceNumIntroductionPoints,
340 : NUM_INTRO_POINTS_DEFAULT,
341 : HS_CONFIG_V3_MAX_INTRO_POINTS)) {
342 2 : goto err;
343 : }
344 23 : config->num_intro_points = hs_opts->HiddenServiceNumIntroductionPoints;
345 :
346 : /* Circuit ID export setting. */
347 23 : if (hs_opts->HiddenServiceExportCircuitID) {
348 0 : int ok;
349 0 : config->circuit_id_protocol =
350 0 : helper_parse_circuit_id_protocol("HiddenServcieExportCircuitID",
351 : hs_opts->HiddenServiceExportCircuitID,
352 : &ok);
353 0 : if (!ok) {
354 0 : goto err;
355 : }
356 : }
357 :
358 : /* Is the DoS defense enabled? */
359 23 : config->has_dos_defense_enabled =
360 23 : hs_opts->HiddenServiceEnableIntroDoSDefense;
361 :
362 : /* Rate for DoS defense */
363 23 : if (CHECK_OOB(hs_opts, HiddenServiceEnableIntroDoSRatePerSec,
364 : HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN,
365 : HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX)) {
366 0 : goto err;
367 : }
368 23 : config->intro_dos_rate_per_sec =
369 23 : hs_opts->HiddenServiceEnableIntroDoSRatePerSec;
370 23 : log_info(LD_REND, "Service INTRO2 DoS defenses rate set to: %" PRIu32,
371 : config->intro_dos_rate_per_sec);
372 :
373 23 : if (CHECK_OOB(hs_opts, HiddenServiceEnableIntroDoSBurstPerSec,
374 : HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN,
375 : HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX)) {
376 0 : goto err;
377 : }
378 23 : config->intro_dos_burst_per_sec =
379 23 : hs_opts->HiddenServiceEnableIntroDoSBurstPerSec;
380 23 : log_info(LD_REND, "Service INTRO2 DoS defenses burst set to: %" PRIu32,
381 : config->intro_dos_burst_per_sec);
382 :
383 : /* Is this an onionbalance instance? */
384 23 : if (hs_opts->HiddenServiceOnionBalanceInstance) {
385 : /* Option is enabled, parse config file. */
386 2 : if (! hs_ob_parse_config_file(config)) {
387 1 : goto err;
388 : }
389 : }
390 :
391 : /* We do not load the key material for the service at this stage. This is
392 : * done later once tor can confirm that it is in a running state. */
393 :
394 : /* We are about to return a fully configured service so do one last pass of
395 : * validation at it. */
396 22 : if (config_validate_service(config) < 0) {
397 2 : goto err;
398 : }
399 :
400 : return 0;
401 : err:
402 : return -1;
403 : }
404 :
405 : /** Configure a service using the given options in hs_opts and options. This is
406 : * called for any service regardless of its version which means that all
407 : * directives in this function are generic to any service version. This
408 : * function will also check the validity of the service directory path.
409 : *
410 : * The line_ must be pointing to the directive directly after a
411 : * HiddenServiceDir. That way, when hitting the next HiddenServiceDir line or
412 : * reaching the end of the list of lines, we know that we have to stop looking
413 : * for more options.
414 : *
415 : * Return 0 on success else -1. */
416 : static int
417 29 : config_generic_service(const hs_opts_t *hs_opts,
418 : const or_options_t *options,
419 : hs_service_t *service)
420 : {
421 29 : hs_service_config_t *config;
422 :
423 29 : tor_assert(hs_opts);
424 29 : tor_assert(options);
425 29 : tor_assert(service);
426 :
427 : /* Makes thing easier. */
428 29 : config = &service->config;
429 :
430 : /* Directory where the service's keys are stored. */
431 29 : tor_assert(hs_opts->HiddenServiceDir);
432 29 : config->directory_path = tor_strdup(hs_opts->HiddenServiceDir);
433 29 : log_info(LD_CONFIG, "%s=%s. Configuring...",
434 : SECTION_HEADER, escaped(config->directory_path));
435 :
436 : /* Protocol version for the service. */
437 29 : if (hs_opts->HiddenServiceVersion == -1) {
438 : /* No value was set; stay with the default. */
439 18 : } else if (hs_opts->HiddenServiceVersion == 2) {
440 0 : log_warn(LD_CONFIG, "Onion services version 2 are obsolete. Please see "
441 : "https://blog.torproject.org/v2-deprecation-timeline "
442 : "for more details and for instructions on how to "
443 : "transition to version 3.");
444 0 : goto err;
445 18 : } else if (CHECK_OOB(hs_opts, HiddenServiceVersion,
446 : HS_VERSION_MIN, HS_VERSION_MAX)) {
447 1 : goto err;
448 : } else {
449 17 : config->hs_version_explicitly_set = 1;
450 17 : config->version = hs_opts->HiddenServiceVersion;
451 : }
452 :
453 : /* Virtual port. */
454 28 : for (const config_line_t *portline = hs_opts->HiddenServicePort;
455 59 : portline; portline = portline->next) {
456 33 : char *err_msg = NULL;
457 : /* XXX: Can we rename this? */
458 33 : hs_port_config_t *portcfg =
459 33 : hs_parse_port_config(portline->value, " ", &err_msg);
460 33 : if (!portcfg) {
461 2 : if (err_msg) {
462 2 : log_warn(LD_CONFIG, "%s", err_msg);
463 : }
464 2 : tor_free(err_msg);
465 2 : goto err;
466 : }
467 31 : tor_assert(!err_msg);
468 31 : smartlist_add(config->ports, portcfg);
469 31 : log_info(LD_CONFIG, "HiddenServicePort=%s for %s",
470 : portline->value, escaped(config->directory_path));
471 : }
472 :
473 : /* Do we allow unknown ports? */
474 26 : config->allow_unknown_ports = hs_opts->HiddenServiceAllowUnknownPorts;
475 :
476 : /* Directory group readable. */
477 26 : config->dir_group_readable = hs_opts->HiddenServiceDirGroupReadable;
478 :
479 : /* Maximum streams per circuit. */
480 26 : if (CHECK_OOB(hs_opts, HiddenServiceMaxStreams,
481 : 0, HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT)) {
482 1 : goto err;
483 : }
484 25 : config->max_streams_per_rdv_circuit = hs_opts->HiddenServiceMaxStreams;
485 :
486 : /* Maximum amount of streams before we close the circuit. */
487 25 : config->max_streams_close_circuit =
488 25 : hs_opts->HiddenServiceMaxStreamsCloseCircuit;
489 :
490 : /* Check if we are configured in non anonymous mode meaning every service
491 : * becomes a single onion service. */
492 25 : if (hs_service_non_anonymous_mode_enabled(options)) {
493 1 : config->is_single_onion = 1;
494 : }
495 :
496 : /* Success */
497 : return 0;
498 : err:
499 : return -1;
500 : }
501 :
502 : /** Configure a service using the given line and options. This function will
503 : * call the corresponding configuration function for a specific service
504 : * version and validate the service against the other ones. On success, add
505 : * the service to the given list and return 0. On error, nothing is added to
506 : * the list and a negative value is returned. */
507 : static int
508 35 : config_service(config_line_t *line, const or_options_t *options,
509 : smartlist_t *service_list)
510 : {
511 35 : int ret;
512 35 : hs_service_t *service = NULL;
513 35 : hs_opts_t *hs_opts = NULL;
514 35 : char *msg = NULL;
515 :
516 35 : tor_assert(line);
517 35 : tor_assert(options);
518 35 : tor_assert(service_list);
519 :
520 : /* We have a new hidden service. */
521 35 : service = hs_service_new(options);
522 :
523 : /* Try to validate and parse the configuration lines into 'hs_opts' */
524 35 : hs_opts = hs_opts_new();
525 35 : ret = config_assign(get_hs_opts_mgr(), hs_opts, line, 0, &msg);
526 35 : if (ret < 0) {
527 6 : log_warn(LD_REND, "Can't parse configuration for onion service: %s", msg);
528 6 : goto err;
529 : }
530 29 : tor_assert_nonfatal(msg == NULL);
531 29 : validation_status_t vs = config_validate(get_hs_opts_mgr(), NULL,
532 : hs_opts, &msg);
533 29 : if (vs < 0) {
534 0 : log_warn(LD_REND, "Bad configuration for onion service: %s", msg);
535 0 : goto err;
536 : }
537 29 : tor_assert_nonfatal(msg == NULL);
538 :
539 : /* We'll configure that service as a generic one and then pass it to a
540 : * specific function according to the configured version number. */
541 29 : if (config_generic_service(hs_opts, options, service) < 0) {
542 4 : goto err;
543 : }
544 :
545 25 : tor_assert(service->config.version <= HS_VERSION_MAX);
546 :
547 : /* Check permission on service directory that was just parsed. And this must
548 : * be done regardless of the service version. Do not ask for the directory
549 : * to be created, this is done when the keys are loaded because we could be
550 : * in validation mode right now. */
551 25 : if (hs_check_service_private_dir(options->User,
552 25 : service->config.directory_path,
553 25 : service->config.dir_group_readable,
554 : 0) < 0) {
555 0 : goto err;
556 : }
557 :
558 : /* We'll try to learn the service version here by loading the key(s) if
559 : * present and we did not set HiddenServiceVersion. Depending on the key
560 : * format, we can figure out the service version. */
561 25 : if (!service->config.hs_version_explicitly_set) {
562 11 : service->config.version = config_learn_service_version(service);
563 : }
564 :
565 : /* We make sure that this set of options for a service are valid. */
566 25 : if (config_has_invalid_options(line->next, service)) {
567 0 : goto err;
568 : }
569 :
570 : /* Different functions are in charge of specific options for a version. We
571 : * start just after the service directory line so once we hit another
572 : * directory line, the function knows that it has to stop parsing. */
573 25 : switch (service->config.version) {
574 25 : case HS_VERSION_THREE:
575 25 : ret = config_service_v3(hs_opts, &service->config);
576 25 : break;
577 0 : default:
578 : /* We do validate before if we support the parsed version. */
579 0 : tor_assert_nonfatal_unreached();
580 0 : goto err;
581 : }
582 25 : if (ret < 0) {
583 5 : goto err;
584 : }
585 :
586 : /* We'll check if this service can be kept depending on the others
587 : * configured previously. */
588 20 : if (service_is_duplicate_in_list(service_list, service)) {
589 1 : goto err;
590 : }
591 :
592 : /* Passes, add it to the given list. */
593 19 : smartlist_add(service_list, service);
594 19 : hs_opts_free(hs_opts);
595 :
596 19 : return 0;
597 :
598 16 : err:
599 16 : hs_service_free(service);
600 16 : hs_opts_free(hs_opts);
601 16 : tor_free(msg);
602 16 : return -1;
603 : }
604 :
605 : /** From a set of <b>options</b>, setup every hidden service found. Return 0 on
606 : * success or -1 on failure. If <b>validate_only</b> is set, parse, warn and
607 : * return as normal, but don't actually change the configured services. */
608 : int
609 460 : hs_config_service_all(const or_options_t *options, int validate_only)
610 : {
611 460 : int ret = -1;
612 460 : config_line_t *remaining = NULL;
613 460 : smartlist_t *new_service_list = NULL;
614 :
615 460 : tor_assert(options);
616 :
617 : /* Newly configured service are put in that list which is then used for
618 : * validation and staging for >= v3. */
619 460 : new_service_list = smartlist_new();
620 :
621 : /* We need to start with a HiddenServiceDir line */
622 460 : if (options->RendConfigLines &&
623 35 : strcasecmp(options->RendConfigLines->key, SECTION_HEADER)) {
624 2 : log_warn(LD_CONFIG, "%s with no preceding %s directive",
625 : options->RendConfigLines->key, SECTION_HEADER);
626 2 : goto err;
627 : }
628 :
629 458 : remaining = config_lines_dup(options->RendConfigLines);
630 477 : while (remaining) {
631 35 : config_line_t *section = remaining;
632 35 : remaining = config_lines_partition(section, SECTION_HEADER);
633 :
634 : /* Try to configure this service now. On success, it will be added to the
635 : * list and validated against the service in that same list. */
636 35 : int rv = config_service(section, options, new_service_list);
637 35 : config_free_lines(section);
638 35 : if (rv < 0) {
639 16 : goto err;
640 : }
641 : }
642 :
643 : /* In non validation mode, we'll stage those services we just successfully
644 : * configured. Service ownership is transferred from the list to the global
645 : * state. If any service is invalid, it will be removed from the list and
646 : * freed. All versions are handled in that function. */
647 442 : if (!validate_only) {
648 10 : stage_services(new_service_list);
649 : } else {
650 : /* We've just validated that we were able to build a clean working list of
651 : * services. We don't need those objects anymore. */
652 444 : SMARTLIST_FOREACH(new_service_list, hs_service_t *, s,
653 : hs_service_free(s));
654 : }
655 :
656 : /* Success. Note that the service list has no ownership of its content. */
657 442 : ret = 0;
658 442 : goto end;
659 :
660 18 : err:
661 19 : SMARTLIST_FOREACH(new_service_list, hs_service_t *, s, hs_service_free(s));
662 :
663 460 : end:
664 460 : smartlist_free(new_service_list);
665 : /* Tor main should call the free all function on error. */
666 460 : return ret;
667 : }
668 :
669 : /** From a set of <b>options</b>, setup every client authorization found.
670 : * Return 0 on success or -1 on failure. If <b>validate_only</b> is set,
671 : * parse, warn and return as normal, but don't actually change the
672 : * configured state. */
673 : int
674 435 : hs_config_client_auth_all(const or_options_t *options, int validate_only)
675 : {
676 435 : int ret = -1;
677 :
678 : /* Configure v3 authorization. */
679 435 : if (hs_config_client_authorization(options, validate_only) < 0) {
680 0 : goto done;
681 : }
682 :
683 : /* Success. */
684 : ret = 0;
685 435 : done:
686 435 : return ret;
687 : }
688 :
689 : /**
690 : * Free all resources held by the hs_config.c module.
691 : **/
692 : void
693 285 : hs_config_free_all(void)
694 : {
695 285 : config_mgr_free(hs_opts_mgr);
696 285 : }
|