hs_config.c (24384B)
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 get_hs_opts_mgr(void) 62 { 63 if (PREDICT_UNLIKELY(hs_opts_mgr == NULL)) { 64 hs_opts_mgr = config_mgr_new(&hs_opts_fmt); 65 config_mgr_freeze(hs_opts_mgr); 66 } 67 return hs_opts_mgr; 68 } 69 70 /** 71 * Allocate, initialize, and return a new hs_opts_t. 72 **/ 73 static hs_opts_t * 74 hs_opts_new(void) 75 { 76 const config_mgr_t *mgr = get_hs_opts_mgr(); 77 hs_opts_t *r = config_new(mgr); 78 tor_assert(r); 79 config_init(mgr, r); 80 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 stage_services(smartlist_t *service_list) 100 { 101 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 hs_service_stage_services(service_list); 106 } 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 service_is_duplicate_in_list(const smartlist_t *service_list, 114 const hs_service_t *service) 115 { 116 int ret = 0; 117 118 tor_assert(service_list); 119 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 if (service->config.is_ephemeral) { 124 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 SMARTLIST_FOREACH_BEGIN(service_list, const hs_service_t *, s) { 142 if (!strcmp(s->config.directory_path, service->config.directory_path)) { 143 log_warn(LD_REND, "Another hidden service is already configured " 144 "for directory %s", 145 escaped(service->config.directory_path)); 146 ret = 1; 147 goto end; 148 } 149 } SMARTLIST_FOREACH_END(s); 150 151 end: 152 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 check_value_oob(int i, const char *name, int low, int high) 160 { 161 if (i < low || i > high) { 162 if (low == high) { 163 log_warn(LD_CONFIG, "%s must be %d, not %d.", name, low, i); 164 } else { 165 log_warn(LD_CONFIG, "%s must be between %d and %d, not %d.", 166 name, low, high, i); 167 } 168 return true; 169 } 170 return false; 171 } 172 173 /** 174 * Helper: check whether the integer value called <b>name</b> in <b>opts</b> 175 * is out-of-bounds. 176 **/ 177 #define CHECK_OOB(opts, name, low, high) \ 178 check_value_oob((opts)->name, #name, (low), (high)) 179 180 /** Helper function: Given a configuration option and its value, parse the 181 * value as a hs_circuit_id_protocol_t. On success, ok is set to 1 and ret is 182 * the parse value. On error, ok is set to 0 and the "none" 183 * hs_circuit_id_protocol_t is returned. This function logs on error. */ 184 static hs_circuit_id_protocol_t 185 helper_parse_circuit_id_protocol(const char *key, const char *value, int *ok) 186 { 187 tor_assert(value); 188 tor_assert(ok); 189 190 hs_circuit_id_protocol_t ret = HS_CIRCUIT_ID_PROTOCOL_NONE; 191 *ok = 0; 192 193 if (! strcasecmp(value, "haproxy")) { 194 *ok = 1; 195 ret = HS_CIRCUIT_ID_PROTOCOL_HAPROXY; 196 } else if (! strcasecmp(value, "none")) { 197 *ok = 1; 198 ret = HS_CIRCUIT_ID_PROTOCOL_NONE; 199 } else { 200 log_warn(LD_CONFIG, "%s must be 'haproxy' or 'none'.", key); 201 goto err; 202 } 203 204 err: 205 return ret; 206 } 207 208 /** Return the service version by trying to learn it from the key on disk if 209 * any. If nothing is found, the current service configured version is 210 * returned. */ 211 static int 212 config_learn_service_version(hs_service_t *service) 213 { 214 int version; 215 216 tor_assert(service); 217 218 version = hs_service_get_version_from_key(service); 219 if (version < 0) { 220 version = service->config.version; 221 } 222 223 return version; 224 } 225 226 /** 227 * Header key indicating the start of a new hidden service configuration 228 * block. 229 **/ 230 static const char SECTION_HEADER[] = "HiddenServiceDir"; 231 232 /** Return true iff the given options starting at line_ for a hidden service 233 * contains at least one invalid option. Each hidden service option don't 234 * apply to all versions so this function can find out. The line_ MUST start 235 * right after the HiddenServiceDir line of this service. 236 * 237 * This is mainly for usability so we can inform the user of any invalid 238 * option for the hidden service version instead of silently ignoring. */ 239 static int 240 config_has_invalid_options(const config_line_t *line_, 241 const hs_service_t *service) 242 { 243 int ret = 0; 244 const char **optlist; 245 const config_line_t *line; 246 247 tor_assert(service); 248 tor_assert(service->config.version <= HS_VERSION_MAX); 249 250 /* List of options that a v3 service doesn't support thus must exclude from 251 * its configuration. */ 252 const char *opts_exclude_v3[] = { 253 "HiddenServiceAuthorizeClient", 254 NULL /* End marker. */ 255 }; 256 257 /* Defining the size explicitly allows us to take advantage of the compiler 258 * which warns us if we ever bump the max version but forget to grow this 259 * array. The plus one is because we have a version 0 :). */ 260 struct { 261 const char **list; 262 } exclude_lists[HS_VERSION_MAX + 1] = { 263 { NULL }, /* v0. */ 264 { NULL }, /* v1. */ 265 { NULL }, /* v2. */ 266 { opts_exclude_v3 }, /* v3. */ 267 }; 268 269 optlist = exclude_lists[service->config.version].list; 270 if (optlist == NULL) { 271 /* No exclude options to look at for this version. */ 272 goto end; 273 } 274 for (int i = 0; optlist[i]; i++) { 275 const char *opt = optlist[i]; 276 for (line = line_; line; line = line->next) { 277 if (!strcasecmp(line->key, SECTION_HEADER)) { 278 /* We just hit the next hidden service, stop right now. 279 * (This shouldn't be possible, now that we have partitioned the list 280 * into sections.) */ 281 tor_assert_nonfatal_unreached(); 282 goto end; 283 } 284 if (!strcasecmp(line->key, opt)) { 285 log_warn(LD_CONFIG, "Hidden service option %s is incompatible with " 286 "version %" PRIu32 " of service in %s", 287 opt, service->config.version, 288 service->config.directory_path); 289 ret = 1; 290 /* Continue the loop so we can find all possible options. */ 291 continue; 292 } 293 } 294 } 295 end: 296 return ret; 297 } 298 299 /** Validate service configuration. This is used when loading the configuration 300 * and once we've setup a service object, it's config object is passed to this 301 * function for further validation. This does not validate service key 302 * material. Return 0 if valid else -1 if invalid. */ 303 static int 304 config_validate_service(const hs_service_config_t *config) 305 { 306 tor_assert(config); 307 308 /* Amount of ports validation. */ 309 if (!config->ports || smartlist_len(config->ports) == 0) { 310 log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured.", 311 escaped(config->directory_path)); 312 goto invalid; 313 } 314 315 /* DoS validation values. */ 316 if (config->has_dos_defense_enabled && 317 (config->intro_dos_burst_per_sec < config->intro_dos_rate_per_sec)) { 318 log_warn(LD_CONFIG, "Hidden service DoS defenses burst (%" PRIu32 ") can " 319 "not be smaller than the rate value (%" PRIu32 ").", 320 config->intro_dos_burst_per_sec, config->intro_dos_rate_per_sec); 321 goto invalid; 322 } 323 if (config->has_pow_defenses_enabled && 324 (config->pow_queue_burst < config->pow_queue_rate)) { 325 log_warn(LD_CONFIG, "Hidden service PoW queue burst (%" PRIu32 ") can " 326 "not be smaller than the rate value (%" PRIu32 ").", 327 config->pow_queue_burst, config->pow_queue_rate); 328 goto invalid; 329 } 330 if (config->has_pow_defenses_enabled && !have_module_pow()) { 331 log_warn(LD_CONFIG, "Hidden service proof-of-work defenses are enabled " 332 "in our configuration but this build of tor does not " 333 "include the required 'pow' module."); 334 goto invalid; 335 } 336 337 /* Valid. */ 338 return 0; 339 invalid: 340 return -1; 341 } 342 343 /** Configuration function for a version 3 service. The given service 344 * object must be already allocated and passed through 345 * config_generic_service() prior to calling this function. 346 * 347 * Return 0 on success else a negative value. */ 348 static int 349 config_service_v3(const hs_opts_t *hs_opts, 350 hs_service_config_t *config) 351 { 352 tor_assert(config); 353 tor_assert(hs_opts); 354 355 /* Number of introduction points. */ 356 if (CHECK_OOB(hs_opts, HiddenServiceNumIntroductionPoints, 357 NUM_INTRO_POINTS_DEFAULT, 358 HS_CONFIG_V3_MAX_INTRO_POINTS)) { 359 goto err; 360 } 361 config->num_intro_points = hs_opts->HiddenServiceNumIntroductionPoints; 362 363 /* Circuit ID export setting. */ 364 if (hs_opts->HiddenServiceExportCircuitID) { 365 int ok; 366 config->circuit_id_protocol = 367 helper_parse_circuit_id_protocol("HiddenServiceExportCircuitID", 368 hs_opts->HiddenServiceExportCircuitID, 369 &ok); 370 if (!ok) { 371 goto err; 372 } 373 } 374 375 /* Is the DoS defense enabled? */ 376 config->has_dos_defense_enabled = 377 hs_opts->HiddenServiceEnableIntroDoSDefense; 378 379 /* Rate for DoS defense */ 380 if (CHECK_OOB(hs_opts, HiddenServiceEnableIntroDoSRatePerSec, 381 HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN, 382 HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX)) { 383 goto err; 384 } 385 config->intro_dos_rate_per_sec = 386 hs_opts->HiddenServiceEnableIntroDoSRatePerSec; 387 log_info(LD_REND, "Service INTRO2 DoS defenses rate set to: %" PRIu32, 388 config->intro_dos_rate_per_sec); 389 390 if (CHECK_OOB(hs_opts, HiddenServiceEnableIntroDoSBurstPerSec, 391 HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN, 392 HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX)) { 393 goto err; 394 } 395 config->intro_dos_burst_per_sec = 396 hs_opts->HiddenServiceEnableIntroDoSBurstPerSec; 397 log_info(LD_REND, "Service INTRO2 DoS defenses burst set to: %" PRIu32, 398 config->intro_dos_burst_per_sec); 399 400 /* Is this an onionbalance instance? */ 401 if (hs_opts->HiddenServiceOnionBalanceInstance) { 402 /* Option is enabled, parse config file. */ 403 if (! hs_ob_parse_config_file(config)) { 404 goto err; 405 } 406 } 407 408 /* Are the PoW anti-DoS defenses enabled? */ 409 config->has_pow_defenses_enabled = hs_opts->HiddenServicePoWDefensesEnabled; 410 config->pow_queue_rate = hs_opts->HiddenServicePoWQueueRate; 411 config->pow_queue_burst = hs_opts->HiddenServicePoWQueueBurst; 412 413 log_info(LD_REND, "Service PoW defenses are %s", 414 config->has_pow_defenses_enabled ? "enabled" : "disabled"); 415 if (config->has_pow_defenses_enabled) { 416 log_info(LD_REND, "Service PoW queue rate set to: %" PRIu32, 417 config->pow_queue_rate); 418 log_info(LD_REND, "Service PoW queue burst set to: %" PRIu32, 419 config->pow_queue_burst); 420 } 421 422 /* We do not load the key material for the service at this stage. This is 423 * done later once tor can confirm that it is in a running state. */ 424 425 /* We are about to return a fully configured service so do one last pass of 426 * validation at it. */ 427 if (config_validate_service(config) < 0) { 428 goto err; 429 } 430 431 return 0; 432 err: 433 return -1; 434 } 435 436 /** Configure a service using the given options in hs_opts and options. This is 437 * called for any service regardless of its version which means that all 438 * directives in this function are generic to any service version. This 439 * function will also check the validity of the service directory path. 440 * 441 * The line_ must be pointing to the directive directly after a 442 * HiddenServiceDir. That way, when hitting the next HiddenServiceDir line or 443 * reaching the end of the list of lines, we know that we have to stop looking 444 * for more options. 445 * 446 * Return 0 on success else -1. */ 447 static int 448 config_generic_service(const hs_opts_t *hs_opts, 449 const or_options_t *options, 450 hs_service_t *service) 451 { 452 hs_service_config_t *config; 453 454 tor_assert(hs_opts); 455 tor_assert(options); 456 tor_assert(service); 457 458 /* Makes thing easier. */ 459 config = &service->config; 460 461 /* Directory where the service's keys are stored. */ 462 tor_assert(hs_opts->HiddenServiceDir); 463 config->directory_path = tor_strdup(hs_opts->HiddenServiceDir); 464 log_info(LD_CONFIG, "%s=%s. Configuring...", 465 SECTION_HEADER, escaped(config->directory_path)); 466 467 /* Protocol version for the service. */ 468 if (hs_opts->HiddenServiceVersion == -1) { 469 /* No value was set; stay with the default. */ 470 } else if (hs_opts->HiddenServiceVersion == 2) { 471 log_warn(LD_CONFIG, "Onion services version 2 are obsolete. Please see " 472 "https://blog.torproject.org/v2-deprecation-timeline " 473 "for more details and for instructions on how to " 474 "transition to version 3."); 475 goto err; 476 } else if (CHECK_OOB(hs_opts, HiddenServiceVersion, 477 HS_VERSION_MIN, HS_VERSION_MAX)) { 478 goto err; 479 } else { 480 config->hs_version_explicitly_set = 1; 481 config->version = hs_opts->HiddenServiceVersion; 482 } 483 484 /* Virtual port. */ 485 for (const config_line_t *portline = hs_opts->HiddenServicePort; 486 portline; portline = portline->next) { 487 char *err_msg = NULL; 488 /* XXX: Can we rename this? */ 489 hs_port_config_t *portcfg = 490 hs_parse_port_config(portline->value, " ", &err_msg); 491 if (!portcfg) { 492 if (err_msg) { 493 log_warn(LD_CONFIG, "%s", err_msg); 494 } 495 tor_free(err_msg); 496 goto err; 497 } 498 tor_assert(!err_msg); 499 smartlist_add(config->ports, portcfg); 500 log_info(LD_CONFIG, "HiddenServicePort=%s for %s", 501 portline->value, escaped(config->directory_path)); 502 } 503 504 /* Do we allow unknown ports? */ 505 config->allow_unknown_ports = hs_opts->HiddenServiceAllowUnknownPorts; 506 507 /* Directory group readable. */ 508 config->dir_group_readable = hs_opts->HiddenServiceDirGroupReadable; 509 510 /* Maximum streams per circuit. */ 511 if (CHECK_OOB(hs_opts, HiddenServiceMaxStreams, 512 0, HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT)) { 513 goto err; 514 } 515 config->max_streams_per_rdv_circuit = hs_opts->HiddenServiceMaxStreams; 516 517 /* Maximum amount of streams before we close the circuit. */ 518 config->max_streams_close_circuit = 519 hs_opts->HiddenServiceMaxStreamsCloseCircuit; 520 521 /* Check if we are configured in non anonymous mode meaning every service 522 * becomes a single onion service. */ 523 if (hs_service_non_anonymous_mode_enabled(options)) { 524 config->is_single_onion = 1; 525 } 526 527 /* Success */ 528 return 0; 529 err: 530 return -1; 531 } 532 533 /** Configure a service using the given line and options. This function will 534 * call the corresponding configuration function for a specific service 535 * version and validate the service against the other ones. On success, add 536 * the service to the given list and return 0. On error, nothing is added to 537 * the list and a negative value is returned. */ 538 static int 539 config_service(config_line_t *line, const or_options_t *options, 540 smartlist_t *service_list) 541 { 542 int ret; 543 hs_service_t *service = NULL; 544 hs_opts_t *hs_opts = NULL; 545 char *msg = NULL; 546 547 tor_assert(line); 548 tor_assert(options); 549 tor_assert(service_list); 550 551 /* We have a new hidden service. */ 552 service = hs_service_new(options); 553 554 /* Try to validate and parse the configuration lines into 'hs_opts' */ 555 hs_opts = hs_opts_new(); 556 ret = config_assign(get_hs_opts_mgr(), hs_opts, line, 0, &msg); 557 if (ret < 0) { 558 log_warn(LD_REND, "Can't parse configuration for onion service: %s", msg); 559 goto err; 560 } 561 tor_assert_nonfatal(msg == NULL); 562 validation_status_t vs = config_validate(get_hs_opts_mgr(), NULL, 563 hs_opts, &msg); 564 if (vs < 0) { 565 log_warn(LD_REND, "Bad configuration for onion service: %s", msg); 566 goto err; 567 } 568 tor_assert_nonfatal(msg == NULL); 569 570 /* We'll configure that service as a generic one and then pass it to a 571 * specific function according to the configured version number. */ 572 if (config_generic_service(hs_opts, options, service) < 0) { 573 goto err; 574 } 575 576 tor_assert(service->config.version <= HS_VERSION_MAX); 577 578 /* If we're running with TestingTorNetwork enabled, we relax the permissions 579 * check on the hs directory. */ 580 if (!options->TestingTorNetwork) { 581 /* Check permission on service directory that was just parsed. And this 582 * must be done regardless of the service version. Do not ask for the 583 * directory to be created, this is done when the keys are loaded because 584 * we could be in validation mode right now. */ 585 if (hs_check_service_private_dir(options->User, 586 service->config.directory_path, 587 service->config.dir_group_readable, 588 0) < 0) { 589 goto err; 590 } 591 } 592 593 /* We'll try to learn the service version here by loading the key(s) if 594 * present and we did not set HiddenServiceVersion. Depending on the key 595 * format, we can figure out the service version. */ 596 if (!service->config.hs_version_explicitly_set) { 597 service->config.version = config_learn_service_version(service); 598 } 599 600 /* We make sure that this set of options for a service are valid. */ 601 if (config_has_invalid_options(line->next, service)) { 602 goto err; 603 } 604 605 /* Different functions are in charge of specific options for a version. We 606 * start just after the service directory line so once we hit another 607 * directory line, the function knows that it has to stop parsing. */ 608 switch (service->config.version) { 609 case HS_VERSION_THREE: 610 ret = config_service_v3(hs_opts, &service->config); 611 break; 612 default: 613 /* We do validate before if we support the parsed version. */ 614 tor_assert_nonfatal_unreached(); 615 goto err; 616 } 617 if (ret < 0) { 618 goto err; 619 } 620 621 /* We'll check if this service can be kept depending on the others 622 * configured previously. */ 623 if (service_is_duplicate_in_list(service_list, service)) { 624 goto err; 625 } 626 627 /* Passes, add it to the given list. */ 628 smartlist_add(service_list, service); 629 hs_opts_free(hs_opts); 630 631 return 0; 632 633 err: 634 hs_service_free(service); 635 hs_opts_free(hs_opts); 636 tor_free(msg); 637 return -1; 638 } 639 640 /** From a set of <b>options</b>, setup every hidden service found. Return 0 on 641 * success or -1 on failure. If <b>validate_only</b> is set, parse, warn and 642 * return as normal, but don't actually change the configured services. */ 643 int 644 hs_config_service_all(const or_options_t *options, int validate_only) 645 { 646 int ret = -1; 647 config_line_t *remaining = NULL; 648 smartlist_t *new_service_list = NULL; 649 650 tor_assert(options); 651 652 /* Newly configured service are put in that list which is then used for 653 * validation and staging for >= v3. */ 654 new_service_list = smartlist_new(); 655 656 /* We need to start with a HiddenServiceDir line */ 657 if (options->RendConfigLines && 658 strcasecmp(options->RendConfigLines->key, SECTION_HEADER)) { 659 log_warn(LD_CONFIG, "%s with no preceding %s directive", 660 options->RendConfigLines->key, SECTION_HEADER); 661 goto err; 662 } 663 664 remaining = config_lines_dup(options->RendConfigLines); 665 while (remaining) { 666 config_line_t *section = remaining; 667 remaining = config_lines_partition(section, SECTION_HEADER); 668 669 /* Try to configure this service now. On success, it will be added to the 670 * list and validated against the service in that same list. */ 671 int rv = config_service(section, options, new_service_list); 672 config_free_lines(section); 673 if (rv < 0) { 674 config_free_lines(remaining); 675 goto err; 676 } 677 } 678 679 /* In non validation mode, we'll stage those services we just successfully 680 * configured. Service ownership is transferred from the list to the global 681 * state. If any service is invalid, it will be removed from the list and 682 * freed. All versions are handled in that function. */ 683 if (!validate_only) { 684 stage_services(new_service_list); 685 } else { 686 /* We've just validated that we were able to build a clean working list of 687 * services. We don't need those objects anymore. */ 688 SMARTLIST_FOREACH(new_service_list, hs_service_t *, s, 689 hs_service_free(s)); 690 } 691 692 /* Success. Note that the service list has no ownership of its content. */ 693 ret = 0; 694 goto end; 695 696 err: 697 SMARTLIST_FOREACH(new_service_list, hs_service_t *, s, hs_service_free(s)); 698 699 end: 700 smartlist_free(new_service_list); 701 /* Tor main should call the free all function on error. */ 702 return ret; 703 } 704 705 /** From a set of <b>options</b>, setup every client authorization found. 706 * Return 0 on success or -1 on failure. If <b>validate_only</b> is set, 707 * parse, warn and return as normal, but don't actually change the 708 * configured state. */ 709 int 710 hs_config_client_auth_all(const or_options_t *options, int validate_only) 711 { 712 int ret = -1; 713 714 /* Configure v3 authorization. */ 715 if (hs_config_client_authorization(options, validate_only) < 0) { 716 goto done; 717 } 718 719 /* Success. */ 720 ret = 0; 721 done: 722 return ret; 723 } 724 725 /** 726 * Free all resources held by the hs_config.c module. 727 **/ 728 void 729 hs_config_free_all(void) 730 { 731 config_mgr_free(hs_opts_mgr); 732 }