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