Loading src/or/rendservice.c +56 −17 Original line number Diff line number Diff line Loading @@ -216,16 +216,30 @@ rend_service_free_all(void) rend_service_list = NULL; } /** Validate <b>service</b> and add it to rend_service_list if possible. /** Validate <b>service</b> and add it to <b>service_list</b>, or to * the global rend_service_list if <b>service_list</b> is NULL. * Return 0 on success. On failure, free <b>service</b> and return -1. * Takes ownership of <b>service</b>. */ static int rend_add_service(rend_service_t *service) rend_add_service(smartlist_t *service_list, rend_service_t *service) { int i; rend_service_port_config_t *p; smartlist_t *s_list; /* If no special service list is provided, then just use the global one. */ if (!service_list) { if (BUG(!rend_service_list)) { /* No global HS list, which is a failure. */ return -1; } s_list = rend_service_list; } else { s_list = service_list; } service->intro_nodes = smartlist_new(); service->expiring_nodes = smartlist_new(); Loading @@ -247,7 +261,8 @@ rend_add_service(rend_service_t *service) } if (service->auth_type != REND_NO_AUTH && smartlist_len(service->clients) == 0) { (!service->clients || smartlist_len(service->clients) == 0)) { log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but no " "clients; ignoring.", rend_service_escaped_dir(service)); Loading @@ -255,7 +270,7 @@ rend_add_service(rend_service_t *service) return -1; } if (!smartlist_len(service->ports)) { if (!service->ports || !smartlist_len(service->ports)) { log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured; " "ignoring.", rend_service_escaped_dir(service)); Loading @@ -278,8 +293,9 @@ rend_add_service(rend_service_t *service) * lock file. But this is enough to detect a simple mistake that * at least one person has actually made. */ if (service->directory != NULL) { /* Skip dupe for ephemeral services. */ SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr, if (service->directory != NULL) { /* Skip dupe for ephemeral services. */ SMARTLIST_FOREACH(s_list, rend_service_t*, ptr, dupe = dupe || !strcmp(ptr->directory, service->directory)); if (dupe) { Loading @@ -290,7 +306,7 @@ rend_add_service(rend_service_t *service) return -1; } } smartlist_add(rend_service_list, service); smartlist_add(s_list, service); log_debug(LD_REND,"Configuring service with directory \"%s\"", service->directory); for (i = 0; i < smartlist_len(service->ports); ++i) { Loading Loading @@ -445,16 +461,18 @@ rend_service_port_config_free(rend_service_port_config_t *p) tor_free(p); } /* Check the directory for <b>service</b>, and add the service to the global * list if <b>validate_only</b> is false. /* Check the directory for <b>service</b>, and add the service to * <b>service_list</b>, or to the global list if <b>service_list</b> is NULL. * Only add the service to the list if <b>validate_only</b> is false. * If <b>validate_only</b> is true, free the service. * If <b>service</b> is NULL, ignore it, and return 0. * Returns 0 on success, and -1 on failure. * Takes ownership of <b>service</b>, either freeing it, or adding it to the * global service list. */ static int rend_service_check_dir_and_add(const or_options_t *options, STATIC int rend_service_check_dir_and_add(smartlist_t *service_list, const or_options_t *options, rend_service_t *service, int validate_only) { Loading @@ -463,6 +481,22 @@ rend_service_check_dir_and_add(const or_options_t *options, return 0; } smartlist_t *s_list = NULL; /* If no special service list is provided, then just use the global one. */ if (!service_list) { if (!rend_service_list) { /* No global HS list, which is a failure if we plan on adding to it */ if (BUG(!validate_only)) { return -1; } /* Otherwise, we validate, */ } s_list = rend_service_list; } else { s_list = service_list; } if (rend_service_check_private_dir(options, service, !validate_only) < 0) { rend_service_free(service); Loading @@ -474,8 +508,12 @@ rend_service_check_dir_and_add(const or_options_t *options, return 0; } else { /* rend_add_service takes ownership, either adding or freeing the service * s_list can not be NULL here - if both service_list and rend_service_list * are NULL, and validate_only is false, we exit earlier in the function */ rend_add_service(service); tor_assert(s_list); /* Ignore service failures until 030 */ rend_add_service(s_list, service); return 0; } } Loading Loading @@ -504,8 +542,8 @@ rend_config_services(const or_options_t *options, int validate_only) /* register the service we just finished parsing * this code registers every service except the last one parsed, * which is registered below the loop */ if (rend_service_check_dir_and_add(options, service, !validate_only) < 0) { if (rend_service_check_dir_and_add(NULL, options, service, validate_only) < 0) { return -1; } service = tor_malloc_zero(sizeof(rend_service_t)); Loading Loading @@ -715,8 +753,8 @@ rend_config_services(const or_options_t *options, int validate_only) /* register the final service after we have finished parsing all services * this code only registers the last service, other services are registered * within the loop */ if (rend_service_check_dir_and_add(options, service, !validate_only) < 0) { if (rend_service_check_dir_and_add(NULL, options, service, validate_only) < 0) { return -1; } Loading Loading @@ -874,7 +912,7 @@ rend_service_add_ephemeral(crypto_pk_t *pk, } /* Initialize the service. */ if (rend_add_service(s)) { if (rend_add_service(NULL, s)) { return RSAE_INTERNAL; } *service_id_out = tor_strdup(s->service_id); Loading Loading @@ -1310,6 +1348,7 @@ rend_service_check_private_dir(const or_options_t *options, } /* Check/create directory */ if (check_private_dir(s->directory, check_opts, options->User) < 0) { log_warn(LD_REND, "Checking service directory %s failed.", s->directory); return -1; } return 0; Loading src/or/rendservice.h +4 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ typedef struct rend_service_t { STATIC void rend_service_free(rend_service_t *service); STATIC char *rend_service_sos_poison_path(const rend_service_t *service); STATIC int rend_service_check_dir_and_add(smartlist_t *service_list, const or_options_t *options, rend_service_t *service, int validate_only); #endif Loading src/test/test_hs.c +23 −5 Original line number Diff line number Diff line Loading @@ -571,8 +571,28 @@ test_single_onion_poisoning(void *arg) service_1->directory = dir1; service_2->directory = dir2; /* The services own the directory pointers now */ dir1 = dir2 = NULL; smartlist_add(services, service_1); /* Add port to service 1 */ service_1->ports = smartlist_new(); service_2->ports = smartlist_new(); char *err_msg = NULL; rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ", &err_msg); tt_assert(port1); tt_assert(!err_msg); smartlist_add(service_1->ports, port1); rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ", &err_msg); /* Add port to service 2 */ tt_assert(port2); tt_assert(!err_msg); smartlist_add(service_2->ports, port2); /* Add the first service */ ret = rend_service_check_dir_and_add(services, mock_options, service_1, 0); tt_assert(ret == 0); /* But don't add the second service yet. */ /* Service directories, but no previous keys, no problem! */ Loading Loading @@ -636,7 +656,7 @@ test_single_onion_poisoning(void *arg) tt_assert(ret == 0); /* Now add the second service: it has no key and no poison file */ smartlist_add(services, service_2); ret = rend_service_check_dir_and_add(services, mock_options, service_2, 0); /* A new service, and an existing poisoned service. Not ok. */ mock_options->HiddenServiceSingleHopMode = 0; Loading Loading @@ -698,13 +718,11 @@ test_single_onion_poisoning(void *arg) done: /* The test harness deletes the directories at exit */ smartlist_free(services); rend_service_free(service_1); rend_service_free(service_2); smartlist_free(services); UNMOCK(get_options); tor_free(mock_options->DataDirectory); tor_free(dir1); tor_free(dir2); } struct testcase_t hs_tests[] = { Loading Loading
src/or/rendservice.c +56 −17 Original line number Diff line number Diff line Loading @@ -216,16 +216,30 @@ rend_service_free_all(void) rend_service_list = NULL; } /** Validate <b>service</b> and add it to rend_service_list if possible. /** Validate <b>service</b> and add it to <b>service_list</b>, or to * the global rend_service_list if <b>service_list</b> is NULL. * Return 0 on success. On failure, free <b>service</b> and return -1. * Takes ownership of <b>service</b>. */ static int rend_add_service(rend_service_t *service) rend_add_service(smartlist_t *service_list, rend_service_t *service) { int i; rend_service_port_config_t *p; smartlist_t *s_list; /* If no special service list is provided, then just use the global one. */ if (!service_list) { if (BUG(!rend_service_list)) { /* No global HS list, which is a failure. */ return -1; } s_list = rend_service_list; } else { s_list = service_list; } service->intro_nodes = smartlist_new(); service->expiring_nodes = smartlist_new(); Loading @@ -247,7 +261,8 @@ rend_add_service(rend_service_t *service) } if (service->auth_type != REND_NO_AUTH && smartlist_len(service->clients) == 0) { (!service->clients || smartlist_len(service->clients) == 0)) { log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but no " "clients; ignoring.", rend_service_escaped_dir(service)); Loading @@ -255,7 +270,7 @@ rend_add_service(rend_service_t *service) return -1; } if (!smartlist_len(service->ports)) { if (!service->ports || !smartlist_len(service->ports)) { log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured; " "ignoring.", rend_service_escaped_dir(service)); Loading @@ -278,8 +293,9 @@ rend_add_service(rend_service_t *service) * lock file. But this is enough to detect a simple mistake that * at least one person has actually made. */ if (service->directory != NULL) { /* Skip dupe for ephemeral services. */ SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr, if (service->directory != NULL) { /* Skip dupe for ephemeral services. */ SMARTLIST_FOREACH(s_list, rend_service_t*, ptr, dupe = dupe || !strcmp(ptr->directory, service->directory)); if (dupe) { Loading @@ -290,7 +306,7 @@ rend_add_service(rend_service_t *service) return -1; } } smartlist_add(rend_service_list, service); smartlist_add(s_list, service); log_debug(LD_REND,"Configuring service with directory \"%s\"", service->directory); for (i = 0; i < smartlist_len(service->ports); ++i) { Loading Loading @@ -445,16 +461,18 @@ rend_service_port_config_free(rend_service_port_config_t *p) tor_free(p); } /* Check the directory for <b>service</b>, and add the service to the global * list if <b>validate_only</b> is false. /* Check the directory for <b>service</b>, and add the service to * <b>service_list</b>, or to the global list if <b>service_list</b> is NULL. * Only add the service to the list if <b>validate_only</b> is false. * If <b>validate_only</b> is true, free the service. * If <b>service</b> is NULL, ignore it, and return 0. * Returns 0 on success, and -1 on failure. * Takes ownership of <b>service</b>, either freeing it, or adding it to the * global service list. */ static int rend_service_check_dir_and_add(const or_options_t *options, STATIC int rend_service_check_dir_and_add(smartlist_t *service_list, const or_options_t *options, rend_service_t *service, int validate_only) { Loading @@ -463,6 +481,22 @@ rend_service_check_dir_and_add(const or_options_t *options, return 0; } smartlist_t *s_list = NULL; /* If no special service list is provided, then just use the global one. */ if (!service_list) { if (!rend_service_list) { /* No global HS list, which is a failure if we plan on adding to it */ if (BUG(!validate_only)) { return -1; } /* Otherwise, we validate, */ } s_list = rend_service_list; } else { s_list = service_list; } if (rend_service_check_private_dir(options, service, !validate_only) < 0) { rend_service_free(service); Loading @@ -474,8 +508,12 @@ rend_service_check_dir_and_add(const or_options_t *options, return 0; } else { /* rend_add_service takes ownership, either adding or freeing the service * s_list can not be NULL here - if both service_list and rend_service_list * are NULL, and validate_only is false, we exit earlier in the function */ rend_add_service(service); tor_assert(s_list); /* Ignore service failures until 030 */ rend_add_service(s_list, service); return 0; } } Loading Loading @@ -504,8 +542,8 @@ rend_config_services(const or_options_t *options, int validate_only) /* register the service we just finished parsing * this code registers every service except the last one parsed, * which is registered below the loop */ if (rend_service_check_dir_and_add(options, service, !validate_only) < 0) { if (rend_service_check_dir_and_add(NULL, options, service, validate_only) < 0) { return -1; } service = tor_malloc_zero(sizeof(rend_service_t)); Loading Loading @@ -715,8 +753,8 @@ rend_config_services(const or_options_t *options, int validate_only) /* register the final service after we have finished parsing all services * this code only registers the last service, other services are registered * within the loop */ if (rend_service_check_dir_and_add(options, service, !validate_only) < 0) { if (rend_service_check_dir_and_add(NULL, options, service, validate_only) < 0) { return -1; } Loading Loading @@ -874,7 +912,7 @@ rend_service_add_ephemeral(crypto_pk_t *pk, } /* Initialize the service. */ if (rend_add_service(s)) { if (rend_add_service(NULL, s)) { return RSAE_INTERNAL; } *service_id_out = tor_strdup(s->service_id); Loading Loading @@ -1310,6 +1348,7 @@ rend_service_check_private_dir(const or_options_t *options, } /* Check/create directory */ if (check_private_dir(s->directory, check_opts, options->User) < 0) { log_warn(LD_REND, "Checking service directory %s failed.", s->directory); return -1; } return 0; Loading
src/or/rendservice.h +4 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ typedef struct rend_service_t { STATIC void rend_service_free(rend_service_t *service); STATIC char *rend_service_sos_poison_path(const rend_service_t *service); STATIC int rend_service_check_dir_and_add(smartlist_t *service_list, const or_options_t *options, rend_service_t *service, int validate_only); #endif Loading
src/test/test_hs.c +23 −5 Original line number Diff line number Diff line Loading @@ -571,8 +571,28 @@ test_single_onion_poisoning(void *arg) service_1->directory = dir1; service_2->directory = dir2; /* The services own the directory pointers now */ dir1 = dir2 = NULL; smartlist_add(services, service_1); /* Add port to service 1 */ service_1->ports = smartlist_new(); service_2->ports = smartlist_new(); char *err_msg = NULL; rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ", &err_msg); tt_assert(port1); tt_assert(!err_msg); smartlist_add(service_1->ports, port1); rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ", &err_msg); /* Add port to service 2 */ tt_assert(port2); tt_assert(!err_msg); smartlist_add(service_2->ports, port2); /* Add the first service */ ret = rend_service_check_dir_and_add(services, mock_options, service_1, 0); tt_assert(ret == 0); /* But don't add the second service yet. */ /* Service directories, but no previous keys, no problem! */ Loading Loading @@ -636,7 +656,7 @@ test_single_onion_poisoning(void *arg) tt_assert(ret == 0); /* Now add the second service: it has no key and no poison file */ smartlist_add(services, service_2); ret = rend_service_check_dir_and_add(services, mock_options, service_2, 0); /* A new service, and an existing poisoned service. Not ok. */ mock_options->HiddenServiceSingleHopMode = 0; Loading Loading @@ -698,13 +718,11 @@ test_single_onion_poisoning(void *arg) done: /* The test harness deletes the directories at exit */ smartlist_free(services); rend_service_free(service_1); rend_service_free(service_2); smartlist_free(services); UNMOCK(get_options); tor_free(mock_options->DataDirectory); tor_free(dir1); tor_free(dir2); } struct testcase_t hs_tests[] = { Loading