Tor  0.4.4.0-alpha-dev
hs_config.c
Go to the documentation of this file.
1 /* Copyright (c) 2017-2020, 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, transfert 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_service.h"
32 #include "lib/encoding/confline.h"
34 
35 /** Using the given list of services, stage them into our global state. Every
36  * service version are handled. This function can remove entries in the given
37  * service_list.
38  *
39  * Staging a service means that we take all services in service_list and we
40  * put them in the staging list (global) which acts as a temporary list that
41  * is used by the service loading key process. In other words, staging a
42  * service puts it in a list to be considered when loading the keys and then
43  * moved to the main global list. */
44 static void
46 {
47  tor_assert(service_list);
48 
49  /* This is v2 specific. Trigger service pruning which will make sure the
50  * just configured services end up in the main global list. It should only
51  * be done in non validation mode because v2 subsystem handles service
52  * object differently. */
53  rend_service_prune_list();
54 
55  /* Cleanup v2 service from the list, we don't need those object anymore
56  * because we validated them all against the others and we want to stage
57  * only >= v3 service. And remember, v2 has a different object type which is
58  * shadow copied from an hs_service_t type. */
59  SMARTLIST_FOREACH_BEGIN(service_list, hs_service_t *, s) {
60  if (s->config.version == HS_VERSION_TWO) {
61  SMARTLIST_DEL_CURRENT(service_list, s);
62  hs_service_free(s);
63  }
64  } SMARTLIST_FOREACH_END(s);
65 
66  /* This is >= v3 specific. Using the newly configured service list, stage
67  * them into our global state. Every object ownership is lost after. */
68  hs_service_stage_services(service_list);
69 }
70 
71 /** Validate the given service against all service in the given list. If the
72  * service is ephemeral, this function ignores it. Services with the same
73  * directory path aren't allowed and will return an error. If a duplicate is
74  * found, 1 is returned else 0 if none found. */
75 static int
77  const hs_service_t *service)
78 {
79  int ret = 0;
80 
81  tor_assert(service_list);
82  tor_assert(service);
83 
84  /* Ephemeral service don't have a directory configured so no need to check
85  * for a service in the list having the same path. */
86  if (service->config.is_ephemeral) {
87  goto end;
88  }
89 
90  /* XXX: Validate if we have any service that has the given service dir path.
91  * This has two problems:
92  *
93  * a) It's O(n^2), but the same comment from the bottom of
94  * rend_config_services() should apply.
95  *
96  * b) We only compare directory paths as strings, so we can't
97  * detect two distinct paths that specify the same directory
98  * (which can arise from symlinks, case-insensitivity, bind
99  * mounts, etc.).
100  *
101  * It also can't detect that two separate Tor instances are trying
102  * to use the same HiddenServiceDir; for that, we would need a
103  * lock file. But this is enough to detect a simple mistake that
104  * at least one person has actually made. */
105  SMARTLIST_FOREACH_BEGIN(service_list, const hs_service_t *, s) {
106  if (!strcmp(s->config.directory_path, service->config.directory_path)) {
107  log_warn(LD_REND, "Another hidden service is already configured "
108  "for directory %s",
109  escaped(service->config.directory_path));
110  ret = 1;
111  goto end;
112  }
113  } SMARTLIST_FOREACH_END(s);
114 
115  end:
116  return ret;
117 }
118 
119 /** Helper function: Given an configuration option name, its value, a minimum
120  * min and a maxium max, parse the value as a uint64_t. On success, ok is set
121  * to 1 and ret is the parsed value. On error, ok is set to 0 and ret must be
122  * ignored. This function logs both on error and success. */
123 static uint64_t
124 helper_parse_uint64(const char *opt, const char *value, uint64_t min,
125  uint64_t max, int *ok)
126 {
127  uint64_t ret = 0;
128 
129  tor_assert(opt);
130  tor_assert(value);
131  tor_assert(ok);
132 
133  *ok = 0;
134  ret = tor_parse_uint64(value, 10, min, max, ok, NULL);
135  if (!*ok) {
136  log_warn(LD_CONFIG, "%s must be between %" PRIu64 " and %"PRIu64
137  ", not %s.",
138  opt, min, max, value);
139  goto err;
140  }
141  log_info(LD_CONFIG, "%s was parsed to %" PRIu64, opt, ret);
142  err:
143  return ret;
144 }
145 
146 /** Helper function: Given a configuration option and its value, parse the
147  * value as a hs_circuit_id_protocol_t. On success, ok is set to 1 and ret is
148  * the parse value. On error, ok is set to 0 and the "none"
149  * hs_circuit_id_protocol_t is returned. This function logs on error. */
151 helper_parse_circuit_id_protocol(const char *key, const char *value, int *ok)
152 {
153  tor_assert(value);
154  tor_assert(ok);
155 
157  *ok = 0;
158 
159  if (! strcasecmp(value, "haproxy")) {
160  *ok = 1;
162  } else if (! strcasecmp(value, "none")) {
163  *ok = 1;
165  } else {
166  log_warn(LD_CONFIG, "%s must be 'haproxy' or 'none'.", key);
167  goto err;
168  }
169 
170  err:
171  return ret;
172 }
173 
174 /** Return the service version by trying to learn it from the key on disk if
175  * any. If nothing is found, the current service configured version is
176  * returned. */
177 static int
179 {
180  int version;
181 
182  tor_assert(service);
183 
184  version = hs_service_get_version_from_key(service);
185  if (version < 0) {
186  version = service->config.version;
187  }
188 
189  return version;
190 }
191 
192 /** Return true iff the given options starting at line_ for a hidden service
193  * contains at least one invalid option. Each hidden service option don't
194  * apply to all versions so this function can find out. The line_ MUST start
195  * right after the HiddenServiceDir line of this service.
196  *
197  * This is mainly for usability so we can inform the user of any invalid
198  * option for the hidden service version instead of silently ignoring. */
199 static int
201  const hs_service_t *service)
202 {
203  int ret = 0;
204  const char **optlist;
205  const config_line_t *line;
206 
207  tor_assert(service);
209 
210  /* List of options that a v3 service doesn't support thus must exclude from
211  * its configuration. */
212  const char *opts_exclude_v3[] = {
213  "HiddenServiceAuthorizeClient",
214  NULL /* End marker. */
215  };
216 
217  const char *opts_exclude_v2[] = {
218  "HiddenServiceExportCircuitID",
219  "HiddenServiceEnableIntroDoSDefense",
220  "HiddenServiceEnableIntroDoSRatePerSec",
221  "HiddenServiceEnableIntroDoSBurstPerSec",
222  NULL /* End marker. */
223  };
224 
225  /* Defining the size explicitly allows us to take advantage of the compiler
226  * which warns us if we ever bump the max version but forget to grow this
227  * array. The plus one is because we have a version 0 :). */
228  struct {
229  const char **list;
230  } exclude_lists[HS_VERSION_MAX + 1] = {
231  { NULL }, /* v0. */
232  { NULL }, /* v1. */
233  { opts_exclude_v2 }, /* v2 */
234  { opts_exclude_v3 }, /* v3. */
235  };
236 
237  optlist = exclude_lists[service->config.version].list;
238  if (optlist == NULL) {
239  /* No exclude options to look at for this version. */
240  goto end;
241  }
242  for (int i = 0; optlist[i]; i++) {
243  const char *opt = optlist[i];
244  for (line = line_; line; line = line->next) {
245  if (!strcasecmp(line->key, "HiddenServiceDir")) {
246  /* We just hit the next hidden service, stop right now. */
247  goto end;
248  }
249  if (!strcasecmp(line->key, opt)) {
250  log_warn(LD_CONFIG, "Hidden service option %s is incompatible with "
251  "version %" PRIu32 " of service in %s",
252  opt, service->config.version,
253  service->config.directory_path);
254 
255  if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
256  /* Special case this v2 option so that we can offer alternatives.
257  * If more such special cases appear, it would be good to
258  * generalize the exception mechanism here. */
259  log_warn(LD_CONFIG, "For v3 onion service client authorization, "
260  "please read the 'CLIENT AUTHORIZATION' section in the "
261  "manual.");
262  }
263 
264  ret = 1;
265  /* Continue the loop so we can find all possible options. */
266  continue;
267  }
268  }
269  }
270  end:
271  return ret;
272 }
273 
274 /** Validate service configuration. This is used when loading the configuration
275  * and once we've setup a service object, it's config object is passed to this
276  * function for further validation. This does not validate service key
277  * material. Return 0 if valid else -1 if invalid. */
278 static int
280 {
281  tor_assert(config);
282 
283  /* Amount of ports validation. */
284  if (!config->ports || smartlist_len(config->ports) == 0) {
285  log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured.",
286  escaped(config->directory_path));
287  goto invalid;
288  }
289 
290  /* DoS validation values. */
291  if (config->has_dos_defense_enabled &&
292  (config->intro_dos_burst_per_sec < config->intro_dos_rate_per_sec)) {
293  log_warn(LD_CONFIG, "Hidden service DoS defenses burst (%" PRIu32 ") can "
294  "not be smaller than the rate value (%" PRIu32 ").",
295  config->intro_dos_burst_per_sec, config->intro_dos_rate_per_sec);
296  goto invalid;
297  }
298 
299  /* Valid. */
300  return 0;
301  invalid:
302  return -1;
303 }
304 
305 /** Configuration funcion for a version 3 service. The line_ must be pointing
306  * to the directive directly after a HiddenServiceDir. That way, when hitting
307  * the next HiddenServiceDir line or reaching the end of the list of lines, we
308  * know that we have to stop looking for more options. The given service
309  * object must be already allocated and passed through
310  * config_generic_service() prior to calling this function.
311  *
312  * Return 0 on success else a negative value. */
313 static int
315  hs_service_config_t *config)
316 {
317  int have_num_ip = 0;
318  bool export_circuit_id = false; /* just to detect duplicate options */
319  bool dos_enabled = false, dos_rate_per_sec = false;
320  bool dos_burst_per_sec = false;
321  const char *dup_opt_seen = NULL;
322  const config_line_t *line;
323 
324  tor_assert(config);
325 
326  for (line = line_; line; line = line->next) {
327  int ok = 0;
328  if (!strcasecmp(line->key, "HiddenServiceDir")) {
329  /* We just hit the next hidden service, stop right now. */
330  break;
331  }
332  /* Number of introduction points. */
333  if (!strcasecmp(line->key, "HiddenServiceNumIntroductionPoints")) {
334  config->num_intro_points =
335  (unsigned int) helper_parse_uint64(line->key, line->value,
337  HS_CONFIG_V3_MAX_INTRO_POINTS,
338  &ok);
339  if (!ok || have_num_ip) {
340  if (have_num_ip)
341  dup_opt_seen = line->key;
342  goto err;
343  }
344  have_num_ip = 1;
345  continue;
346  }
347  if (!strcasecmp(line->key, "HiddenServiceExportCircuitID")) {
348  config->circuit_id_protocol =
349  helper_parse_circuit_id_protocol(line->key, line->value, &ok);
350  if (!ok || export_circuit_id) {
351  if (export_circuit_id) {
352  dup_opt_seen = line->key;
353  }
354  goto err;
355  }
356  export_circuit_id = true;
357  continue;
358  }
359  if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSDefense")) {
360  config->has_dos_defense_enabled =
361  (unsigned int) helper_parse_uint64(line->key, line->value,
362  HS_CONFIG_V3_DOS_DEFENSE_DEFAULT,
363  1, &ok);
364  if (!ok || dos_enabled) {
365  if (dos_enabled) {
366  dup_opt_seen = line->key;
367  }
368  goto err;
369  }
370  dos_enabled = true;
371  continue;
372  }
373  if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSRatePerSec")) {
374  config->intro_dos_rate_per_sec =
375  (unsigned int) helper_parse_uint64(line->key, line->value,
376  HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN,
377  HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX, &ok);
378  if (!ok || dos_rate_per_sec) {
379  if (dos_rate_per_sec) {
380  dup_opt_seen = line->key;
381  }
382  goto err;
383  }
384  dos_rate_per_sec = true;
385  log_info(LD_REND, "Service INTRO2 DoS defenses rate set to: %" PRIu32,
386  config->intro_dos_rate_per_sec);
387  continue;
388  }
389  if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSBurstPerSec")) {
390  config->intro_dos_burst_per_sec =
391  (unsigned int) helper_parse_uint64(line->key, line->value,
392  HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN,
393  HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX, &ok);
394  if (!ok || dos_burst_per_sec) {
395  if (dos_burst_per_sec) {
396  dup_opt_seen = line->key;
397  }
398  goto err;
399  }
400  dos_burst_per_sec = true;
401  log_info(LD_REND, "Service INTRO2 DoS defenses burst set to: %" PRIu32,
402  config->intro_dos_burst_per_sec);
403  continue;
404  }
405  }
406 
407  /* We do not load the key material for the service at this stage. This is
408  * done later once tor can confirm that it is in a running state. */
409 
410  /* We are about to return a fully configured service so do one last pass of
411  * validation at it. */
412  if (config_validate_service(config) < 0) {
413  goto err;
414  }
415 
416  return 0;
417  err:
418  if (dup_opt_seen) {
419  log_warn(LD_CONFIG, "Duplicate directive %s.", dup_opt_seen);
420  }
421  return -1;
422 }
423 
424 /** Configure a service using the given options in line_ and options. This is
425  * called for any service regardless of its version which means that all
426  * directives in this function are generic to any service version. This
427  * function will also check the validity of the service directory path.
428  *
429  * The line_ must be pointing to the directive directly after a
430  * HiddenServiceDir. That way, when hitting the next HiddenServiceDir line or
431  * reaching the end of the list of lines, we know that we have to stop looking
432  * for more options.
433  *
434  * Return 0 on success else -1. */
435 static int
437  const or_options_t *options,
438  hs_service_t *service)
439 {
440  int dir_seen = 0;
441  const config_line_t *line;
442  hs_service_config_t *config;
443  /* If this is set, we've seen a duplicate of this option. Keep the string
444  * so we can log the directive. */
445  const char *dup_opt_seen = NULL;
446  /* These variables will tell us if we ever have duplicate. */
447  int have_version = 0, have_allow_unknown_ports = 0;
448  int have_dir_group_read = 0, have_max_streams = 0;
449  int have_max_streams_close = 0;
450 
451  tor_assert(line_);
452  tor_assert(options);
453  tor_assert(service);
454 
455  /* Makes thing easier. */
456  config = &service->config;
457 
458  /* The first line starts with HiddenServiceDir so we consider what's next is
459  * the configuration of the service. */
460  for (line = line_; line ; line = line->next) {
461  int ok = 0;
462 
463  /* This indicate that we have a new service to configure. */
464  if (!strcasecmp(line->key, "HiddenServiceDir")) {
465  /* This function only configures one service at a time so if we've
466  * already seen one, stop right now. */
467  if (dir_seen) {
468  break;
469  }
470  /* Ok, we've seen one and we are about to configure it. */
471  dir_seen = 1;
472  config->directory_path = tor_strdup(line->value);
473  log_info(LD_CONFIG, "HiddenServiceDir=%s. Configuring...",
474  escaped(config->directory_path));
475  continue;
476  }
477  if (BUG(!dir_seen)) {
478  goto err;
479  }
480  /* Version of the service. */
481  if (!strcasecmp(line->key, "HiddenServiceVersion")) {
482  service->config.version =
483  (uint32_t) helper_parse_uint64(line->key, line->value, HS_VERSION_MIN,
484  HS_VERSION_MAX, &ok);
485  if (!ok || have_version) {
486  if (have_version)
487  dup_opt_seen = line->key;
488  goto err;
489  }
490  have_version = service->config.hs_version_explicitly_set = 1;
491  continue;
492  }
493  /* Virtual port. */
494  if (!strcasecmp(line->key, "HiddenServicePort")) {
495  char *err_msg = NULL;
496  /* XXX: Can we rename this? */
497  rend_service_port_config_t *portcfg =
498  rend_service_parse_port_config(line->value, " ", &err_msg);
499  if (!portcfg) {
500  if (err_msg) {
501  log_warn(LD_CONFIG, "%s", err_msg);
502  }
503  tor_free(err_msg);
504  goto err;
505  }
506  tor_assert(!err_msg);
507  smartlist_add(config->ports, portcfg);
508  log_info(LD_CONFIG, "HiddenServicePort=%s for %s",
509  line->value, escaped(config->directory_path));
510  continue;
511  }
512  /* Do we allow unknown ports. */
513  if (!strcasecmp(line->key, "HiddenServiceAllowUnknownPorts")) {
514  config->allow_unknown_ports =
515  (unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
516  if (!ok || have_allow_unknown_ports) {
517  if (have_allow_unknown_ports)
518  dup_opt_seen = line->key;
519  goto err;
520  }
521  have_allow_unknown_ports = 1;
522  continue;
523  }
524  /* Directory group readable. */
525  if (!strcasecmp(line->key, "HiddenServiceDirGroupReadable")) {
526  config->dir_group_readable =
527  (unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
528  if (!ok || have_dir_group_read) {
529  if (have_dir_group_read)
530  dup_opt_seen = line->key;
531  goto err;
532  }
533  have_dir_group_read = 1;
534  continue;
535  }
536  /* Maximum streams per circuit. */
537  if (!strcasecmp(line->key, "HiddenServiceMaxStreams")) {
539  helper_parse_uint64(line->key, line->value, 0,
540  HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT, &ok);
541  if (!ok || have_max_streams) {
542  if (have_max_streams)
543  dup_opt_seen = line->key;
544  goto err;
545  }
546  have_max_streams = 1;
547  continue;
548  }
549  /* Maximum amount of streams before we close the circuit. */
550  if (!strcasecmp(line->key, "HiddenServiceMaxStreamsCloseCircuit")) {
551  config->max_streams_close_circuit =
552  (unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
553  if (!ok || have_max_streams_close) {
554  if (have_max_streams_close)
555  dup_opt_seen = line->key;
556  goto err;
557  }
558  have_max_streams_close = 1;
559  continue;
560  }
561  }
562 
563  /* Check if we are configured in non anonymous mode meaning every service
564  * becomes a single onion service. */
565  if (rend_service_non_anonymous_mode_enabled(options)) {
566  config->is_single_onion = 1;
567  }
568 
569  /* Success */
570  return 0;
571  err:
572  if (dup_opt_seen) {
573  log_warn(LD_CONFIG, "Duplicate directive %s.", dup_opt_seen);
574  }
575  return -1;
576 }
577 
578 /** Configure a service using the given line and options. This function will
579  * call the corresponding configuration function for a specific service
580  * version and validate the service against the other ones. On success, add
581  * the service to the given list and return 0. On error, nothing is added to
582  * the list and a negative value is returned. */
583 static int
584 config_service(const config_line_t *line, const or_options_t *options,
585  smartlist_t *service_list)
586 {
587  int ret;
588  hs_service_t *service = NULL;
589 
590  tor_assert(line);
591  tor_assert(options);
592  tor_assert(service_list);
593 
594  /* We have a new hidden service. */
595  service = hs_service_new(options);
596 
597  /* We'll configure that service as a generic one and then pass it to a
598  * specific function according to the configured version number. */
599  if (config_generic_service(line, options, service) < 0) {
600  goto err;
601  }
602 
604 
605  /* Check permission on service directory that was just parsed. And this must
606  * be done regardless of the service version. Do not ask for the directory
607  * to be created, this is done when the keys are loaded because we could be
608  * in validation mode right now. */
609  if (hs_check_service_private_dir(options->User,
610  service->config.directory_path,
611  service->config.dir_group_readable,
612  0) < 0) {
613  goto err;
614  }
615 
616  /* We'll try to learn the service version here by loading the key(s) if
617  * present and we did not set HiddenServiceVersion. Depending on the key
618  * format, we can figure out the service version. */
619  if (!service->config.hs_version_explicitly_set) {
620  service->config.version = config_learn_service_version(service);
621  }
622 
623  /* We make sure that this set of options for a service are valid that is for
624  * instance an option only for v2 is not used for v3. */
625  if (config_has_invalid_options(line->next, service)) {
626  goto err;
627  }
628 
629  /* Different functions are in charge of specific options for a version. We
630  * start just after the service directory line so once we hit another
631  * directory line, the function knows that it has to stop parsing. */
632  switch (service->config.version) {
633  case HS_VERSION_TWO:
634  ret = rend_config_service(line->next, options, &service->config);
635  break;
636  case HS_VERSION_THREE:
637  ret = config_service_v3(line->next, &service->config);
638  break;
639  default:
640  /* We do validate before if we support the parsed version. */
641  tor_assert_nonfatal_unreached();
642  goto err;
643  }
644  if (ret < 0) {
645  goto err;
646  }
647 
648  /* We'll check if this service can be kept depending on the others
649  * configured previously. */
650  if (service_is_duplicate_in_list(service_list, service)) {
651  goto err;
652  }
653 
654  /* Passes, add it to the given list. */
655  smartlist_add(service_list, service);
656 
657  return 0;
658 
659  err:
660  hs_service_free(service);
661  return -1;
662 }
663 
664 /** From a set of <b>options</b>, setup every hidden service found. Return 0 on
665  * success or -1 on failure. If <b>validate_only</b> is set, parse, warn and
666  * return as normal, but don't actually change the configured services. */
667 int
668 hs_config_service_all(const or_options_t *options, int validate_only)
669 {
670  int dir_option_seen = 0, ret = -1;
671  const config_line_t *line;
672  smartlist_t *new_service_list = NULL;
673 
674  tor_assert(options);
675 
676  /* Newly configured service are put in that list which is then used for
677  * validation and staging for >= v3. */
678  new_service_list = smartlist_new();
679 
680  for (line = options->RendConfigLines; line; line = line->next) {
681  /* Ignore all directives that aren't the start of a service. */
682  if (strcasecmp(line->key, "HiddenServiceDir")) {
683  if (!dir_option_seen) {
684  log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive",
685  line->key);
686  goto err;
687  }
688  continue;
689  }
690  /* Flag that we've seen a directory directive and we'll use it to make
691  * sure that the torrc options ordering is actually valid. */
692  dir_option_seen = 1;
693 
694  /* Try to configure this service now. On success, it will be added to the
695  * list and validated against the service in that same list. */
696  if (config_service(line, options, new_service_list) < 0) {
697  goto err;
698  }
699  }
700 
701  /* In non validation mode, we'll stage those services we just successfully
702  * configured. Service ownership is transferred from the list to the global
703  * state. If any service is invalid, it will be removed from the list and
704  * freed. All versions are handled in that function. */
705  if (!validate_only) {
706  stage_services(new_service_list);
707  } else {
708  /* We've just validated that we were able to build a clean working list of
709  * services. We don't need those objects anymore. */
710  SMARTLIST_FOREACH(new_service_list, hs_service_t *, s,
711  hs_service_free(s));
712  /* For the v2 subsystem, the configuration function adds the service
713  * object to the staging list and it is transferred in the main list
714  * through the prunning process. In validation mode, we thus have to purge
715  * the staging list so it's not kept in memory as valid service. */
716  rend_service_free_staging_list();
717  }
718 
719  /* Success. Note that the service list has no ownership of its content. */
720  ret = 0;
721  goto end;
722 
723  err:
724  SMARTLIST_FOREACH(new_service_list, hs_service_t *, s, hs_service_free(s));
725 
726  end:
727  smartlist_free(new_service_list);
728  /* Tor main should call the free all function on error. */
729  return ret;
730 }
731 
732 /** From a set of <b>options</b>, setup every client authorization found.
733  * Return 0 on success or -1 on failure. If <b>validate_only</b> is set,
734  * parse, warn and return as normal, but don't actually change the
735  * configured state. */
736 int
737 hs_config_client_auth_all(const or_options_t *options, int validate_only)
738 {
739  int ret = -1;
740 
741  /* Configure v2 authorization. */
742  if (rend_parse_service_authorization(options, validate_only) < 0) {
743  goto done;
744  }
745 
746  /* Configure v3 authorization. */
747  if (hs_config_client_authorization(options, validate_only) < 0) {
748  goto done;
749  }
750 
751  /* Success. */
752  ret = 0;
753  done:
754  return ret;
755 }
static int service_is_duplicate_in_list(const smartlist_t *service_list, const hs_service_t *service)
Definition: hs_config.c:76
Header for confline.c.
Header file containing common data for the whole HS subsytem.
int hs_config_service_all(const or_options_t *options, int validate_only)
Definition: hs_config.c:668
Header file containing configuration ABI/API for the HS subsytem.
static hs_circuit_id_protocol_t helper_parse_circuit_id_protocol(const char *key, const char *value, int *ok)
Definition: hs_config.c:151
Header file containing service data for the HS subsytem.
int hs_service_get_version_from_key(const hs_service_t *service)
Definition: hs_service.c:3925
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next)
Definition: parse_int.c:110
Header file containing client data for the HS subsytem.
static uint64_t helper_parse_uint64(const char *opt, const char *value, uint64_t min, uint64_t max, int *ok)
Definition: hs_config.c:124
unsigned int num_intro_points
Definition: hs_service.h:224
unsigned int max_streams_close_circuit
Definition: hs_service.h:220
unsigned int dir_group_readable
Definition: hs_service.h:243
int hs_check_service_private_dir(const char *username, const char *path, unsigned int dir_group_readable, unsigned int create)
Definition: hs_common.c:199
struct config_line_t * RendConfigLines
void smartlist_add(smartlist_t *sl, void *element)
int hs_config_client_auth_all(const or_options_t *options, int validate_only)
Definition: hs_config.c:737
static int config_learn_service_version(hs_service_t *service)
Definition: hs_config.c:178
#define tor_assert(expr)
Definition: util_bug.h:102
The or_options_t structure, which represents Tor's configuration.
#define tor_free(p)
Definition: malloc.h:52
unsigned int allow_unknown_ports
Definition: hs_service.h:235
#define SMARTLIST_DEL_CURRENT(sl, var)
smartlist_t * ports
Definition: hs_service.h:207
smartlist_t * smartlist_new(void)
#define HS_VERSION_MIN
Definition: hs_common.h:28
#define HS_VERSION_THREE
Definition: hs_common.h:26
uint64_t max_streams_per_rdv_circuit
Definition: hs_service.h:216
static int config_service(const config_line_t *line, const or_options_t *options, smartlist_t *service_list)
Definition: hs_config.c:584
rend_service_port_config_t * rend_service_parse_port_config(const char *string, const char *sep, char **err_msg_out)
Definition: rendservice.c:419
static int config_validate_service(const hs_service_config_t *config)
Definition: hs_config.c:279
static int config_service_v3(const config_line_t *line_, hs_service_config_t *config)
Definition: hs_config.c:314
#define hs_service_free(s)
Definition: hs_service.h:327
hs_service_config_t config
Definition: hs_service.h:297
unsigned int is_single_onion
Definition: hs_service.h:239
#define LD_REND
Definition: log.h:84
Header file for rendservice.c.
hs_circuit_id_protocol_t
Definition: hs_service.h:187
hs_circuit_id_protocol_t circuit_id_protocol
Definition: hs_service.h:249
#define NUM_INTRO_POINTS_DEFAULT
Definition: hs_common.h:33
#define HS_VERSION_MAX
Definition: hs_common.h:30
static int config_generic_service(const config_line_t *line_, const or_options_t *options, hs_service_t *service)
Definition: hs_config.c:436
#define SMARTLIST_FOREACH(sl, type, var, cmd)
const char * escaped(const char *s)
Definition: escape.c:126
unsigned int hs_version_explicitly_set
Definition: hs_service.h:204
#define HS_VERSION_TWO
Definition: hs_common.h:24
static int config_has_invalid_options(const config_line_t *line_, const hs_service_t *service)
Definition: hs_config.c:200
static void stage_services(smartlist_t *service_list)
Definition: hs_config.c:45
unsigned int is_ephemeral
Definition: hs_service.h:246
int hs_config_client_authorization(const or_options_t *options, int validate_only)
Definition: hs_client.c:2161
Header file for rendclient.c.
void hs_service_stage_services(const smartlist_t *service_list)
Definition: hs_service.c:3991
hs_service_t * hs_service_new(const or_options_t *options)
Definition: hs_service.c:4008
int rend_parse_service_authorization(const or_options_t *options, int validate_only)
Definition: rendclient.c:1182
#define LD_CONFIG
Definition: log.h:68