diff --git a/src/or/config.c b/src/or/config.c index 8caf968381..7f2d7d101b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -164,7 +164,7 @@ static int options_validate(or_options_t *options); static int options_transition_allowed(or_options_t *old, or_options_t *new); static int check_nickname_list(const char *lst, const char *name); -static int parse_dir_server_line(const char *line); +static int parse_dir_server_line(const char *line, int validate_only); static int parse_redirect_line(or_options_t *options, struct config_line_t *line); static int parse_log_severity_range(const char *range, int *min_out, @@ -184,12 +184,46 @@ static int normalize_log_options(or_options_t *options); /** Command-line and config-file options. */ static or_options_t *global_options=NULL; -or_options_t *get_options(void) { +/** Return the currently configured options. */ +or_options_t * +get_options(void) { tor_assert(global_options); return global_options; } -void set_options(or_options_t *new) { - global_options = new; + +/** Change the current global options tocontain new instead of + * their current value; free the old value as necessary. Where + * new is different from the old value, update the process to + * use the new value instead. + * + * Note 1: new_val must have previously been validated with + * options_validate(), or Tor may freak out and exit. + * + * Note 2: We haven't moved all the "act on new configuration" logic + * here yet. Some is still in do_hup() and other places. + */ +void +set_options(or_options_t *new_val) { + struct config_line_t *cl; + + if (global_options) + options_free(global_options); + global_options = new_val; + + clear_trusted_dir_servers(); + for (cl = new_val->DirServers; cl; cl = cl->next) { + if (parse_dir_server_line(cl->value, 0)<0) { + log_fn(LOG_ERR, + "Previously validated DirServer line could not be added!"); + tor_assert(0); + } + } + + if (rend_config_services(new_val, 0)<0) { + log_fn(LOG_ERR, + "Previously validated hidden services line could not be added!"); + tor_assert(0); + } } /* @@ -578,10 +612,7 @@ config_trial_assign(or_options_t **options, struct config_line_t *list, int rese return -3; } - /* XXX now act on options */ - - options_free(*options); - *options = trial_options; + set_options(trial_options); return 0; } @@ -632,18 +663,20 @@ option_reset(or_options_t *options, config_var_t *var) } } +/** Set options->DirServers to contain the default directory + * servers. */ static void -add_default_trusted_dirservers(void) +add_default_trusted_dirservers(or_options_t *options) { /* moria1 */ - parse_dir_server_line("18.244.0.188:9031 " - "FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441"); + options->DirServers = config_line_prepend(options->DirServers, "DirServer", + "18.244.0.188:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441"); /* moria2 */ - parse_dir_server_line("18.244.0.114:80 " - "719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF"); + options->DirServers = config_line_prepend(options->DirServers, "DirServer", + "18.244.0.114:80 719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF"); /* tor26 */ - parse_dir_server_line("62.116.124.106:9030 " - "847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D"); + options->DirServers = config_line_prepend(options->DirServers, "DirServer", + "62.116.124.106:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D"); } /** Print a usage message for tor. */ @@ -719,6 +752,8 @@ resolve_my_address(const char *address, uint32_t *addr) return 0; } +/** Called when we don't have a nickname set. Try to guess a good + * nickname based on the hostname, and return it. */ static char * get_default_nickname(void) { @@ -840,6 +875,9 @@ options_init(or_options_t *options) } } +/** Return 0 if every setting in options is reasonable. Else + * warn and return -1. Should have no side effects, except for + * normalizing the contents of options. */ static int options_validate(or_options_t *options) { @@ -875,6 +913,14 @@ options_validate(or_options_t *options) } } + if (normalize_log_options(options)) + return -1; + + /* Special case if no options are given. */ + if (!options->Logs) { + options->Logs = config_line_prepend(NULL, "Log", "notice-err stdout"); + } + if (server_mode(options)) { /* confirm that our address isn't broken, so we can complain now */ uint32_t tmp; @@ -1044,17 +1090,18 @@ options_validate(or_options_t *options) result = -1; } -/* XXX bug: this parsing shouldn't have side effects */ - clear_trusted_dir_servers(); if (!options->DirServers) { - add_default_trusted_dirservers(); + add_default_trusted_dirservers(options); } else { for (cl = options->DirServers; cl; cl = cl->next) { - if (parse_dir_server_line(cl->value)<0) + if (parse_dir_server_line(cl->value, 1)<0) result = -1; } } + if (rend_config_services(options, 1) < 0) + result = -1; + return result; } @@ -1085,6 +1132,8 @@ options_transition_allowed(or_options_t *old, or_options_t *new) { } #ifdef MS_WINDOWS +/** Return the directory on windows where we expect to find our application + * data. */ static char *get_windows_conf_root(void) { static int is_set = 0; @@ -1124,6 +1173,7 @@ static char *get_windows_conf_root(void) } #endif +/** Return the default location for our torrc file. */ static char * get_default_conf_file(void) { @@ -1278,12 +1328,6 @@ getconfig(int argc, char **argv) if (options_transition_allowed(oldoptions, newoptions) < 0) goto err; - /* XXX now act on options */ - if (rend_config_services(newoptions) < 0) - goto err; - - if(oldoptions) - options_free(oldoptions); set_options(newoptions); return 0; err: @@ -1291,6 +1335,12 @@ getconfig(int argc, char **argv) return -1; } +/** If range is of the form MIN-MAX, for MIN and MAX both + * recognized log severity levels, set *min_out to MIN and + * *max_out to MAX and return 0. Else, if range is of + * the form MIN, act as if MIN-err had been specified. Else, warn and + * return -1. + */ static int parse_log_severity_range(const char *range, int *min_out, int *max_out) { @@ -1337,6 +1387,9 @@ parse_log_severity_range(const char *range, int *min_out, int *max_out) return 0; } +/** Try to convert a pair of old-style logging options [LogLevel, and + * (LogFile/Syslog)] to a new-style option, and add the new option to + * options->Logs. */ static int convert_log_option(or_options_t *options, struct config_line_t *level_opt, struct config_line_t *file_opt, int isDaemon) @@ -1380,13 +1433,6 @@ config_init_logs(or_options_t *options) struct config_line_t *opt; int ok; smartlist_t *elts; - if (normalize_log_options(options)) - return -1; - - /* Special case if no options are given. */ - if (!options->Logs) { - options->Logs = config_line_prepend(NULL, "Log", "notice-err stdout"); - } ok = 1; elts = smartlist_create(); @@ -1440,6 +1486,7 @@ config_init_logs(or_options_t *options) return ok?0:-1; } +/** Add a single option of the form Log min-max [fname] to options. */ static int add_single_log_option(or_options_t *options, int minSeverity, int maxSeverity, const char *type, const char *fname) @@ -1461,6 +1508,8 @@ add_single_log_option(or_options_t *options, int minSeverity, int maxSeverity, return 0; } +/** Convert all old-style logging options to new-style Log options. Return 0 + * on success, -1 on faulure. */ static int normalize_log_options(or_options_t *options) { @@ -1555,7 +1604,9 @@ config_parse_exit_policy(struct config_line_t *cfg, smartlist_free(entries); } -void exit_policy_free(struct exit_policy_t *p) { +/** Release all storage held by p */ +void +exit_policy_free(struct exit_policy_t *p) { struct exit_policy_t *e; while (p) { @@ -1566,8 +1617,11 @@ void exit_policy_free(struct exit_policy_t *p) { } } -static int parse_redirect_line(or_options_t *options, - struct config_line_t *line) +/** Parse a single RedirectExit line's contents from line. If they are + * valid, add an element to options->RedirectExitList and return 0. + * Else return -1. */ +static int +parse_redirect_line(or_options_t *options, struct config_line_t *line) { smartlist_t *elements = NULL; exit_redirect_t *r; @@ -1614,7 +1668,12 @@ static int parse_redirect_line(or_options_t *options, } } -static int parse_dir_server_line(const char *line) +/** Read the contents of a DirServer line from line. Return 0 + * if the line is well-formed, and 0 if it isn't. If + * validate_only is 0, and the line is well-formed, then add + * the dirserver desribed in the line as a valid server. */ +static int +parse_dir_server_line(const char *line, int validate_only) { smartlist_t *items = NULL; int r; @@ -1650,9 +1709,11 @@ static int parse_dir_server_line(const char *line) goto err; } - log_fn(LOG_DEBUG, "Trusted dirserver at %s:%d (%s)", address, (int)port, - (char*)smartlist_get(items,1)); - add_trusted_dir_server(address, port, digest); + if (!validate_only) { + log_fn(LOG_DEBUG, "Trusted dirserver at %s:%d (%s)", address, (int)port, + (char*)smartlist_get(items,1)); + add_trusted_dir_server(address, port, digest); + } r = 0; goto done; @@ -1667,6 +1728,8 @@ static int parse_dir_server_line(const char *line) return r; } +/** Return the place where we are currently configured to store and read all + * of our persistant data. */ const char * get_data_directory(void) { diff --git a/src/or/or.h b/src/or/or.h index b519131248..fdebbeaaeb 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1092,7 +1092,7 @@ struct config_line_t { }; or_options_t *get_options(void); -void set_options(or_options_t *new); +void set_options(or_options_t *new_val); int config_get_lines(char *string, struct config_line_t **result); void config_free_lines(struct config_line_t *front); @@ -1462,7 +1462,7 @@ int rend_cache_store(const char *desc, size_t desc_len); /********************************* rendservice.c ***************************/ -int rend_config_services(or_options_t *options); +int rend_config_services(or_options_t *options, int validate_only); int rend_service_load_keys(void); void rend_services_init(void); void rend_services_introduce(void); diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 91feccfdba..ebbc618d1b 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -178,19 +178,27 @@ static rend_service_port_config_t *parse_port_config(const char *string) /** Set up rend_service_list, based on the values of HiddenServiceDir and * HiddenServicePort in options. Return 0 on success and -1 on - * failure. + * failure. (If validate_only is set, parse, warn and return as + * normal, but don't actually change the configured services.) */ -int rend_config_services(or_options_t *options) + +int rend_config_services(or_options_t *options, int validate_only) { struct config_line_t *line; rend_service_t *service = NULL; rend_service_port_config_t *portcfg; - rend_service_free_all(); + + if (!validate_only) + rend_service_free_all(); for (line = options->RendConfigLines; line; line = line->next) { if (!strcasecmp(line->key, "HiddenServiceDir")) { - if (service) - add_service(service); + if (service) { + if (validate_only) + rend_service_free(service); + else + add_service(service); + } service = tor_malloc_zero(sizeof(rend_service_t)); service->directory = tor_strdup(line->value); service->ports = smartlist_create(); @@ -225,8 +233,12 @@ int rend_config_services(or_options_t *options) service->intro_exclude_nodes = tor_strdup(line->value); } } - if (service) - add_service(service); + if (service) { + if (validate_only) + rend_service_free(service); + else + add_service(service); + } return 0; }