diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index f81e835c2d..8f92ab8e59 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -9,8 +9,6 @@ #include "or.h" -extern or_options_t options; /* command-line and config-file options */ - /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ @@ -149,7 +147,7 @@ void circuit_rep_hist_note_result(circuit_t *circ) { */ return; } - if (server_mode()) { + if (server_mode(get_options())) { routerinfo_t *me = router_get_my_routerinfo(); tor_assert(me); prev_digest = me->identity_digest; @@ -354,7 +352,7 @@ circuit_deliver_create_cell(circuit_t *circ, char *payload) { * compare keys, not nicknames...but older servers will compare nicknames. * Should we check server version from the most recent directory? Hm. */ - circ_id_type = decide_circ_id_type(options.Nickname, + circ_id_type = decide_circ_id_type(get_options()->Nickname, circ->n_conn->nickname); circ->n_circ_id = get_unique_circ_id_by_conn(circ->n_conn, circ_id_type); if(!circ->n_circ_id) { @@ -830,9 +828,10 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) int n_best_support=0; smartlist_t *sl, *preferredexits, *preferredentries, *excludedexits; routerinfo_t *router; + or_options_t *options = get_options(); preferredentries = smartlist_create(); - add_nickname_list_to_smartlist(preferredentries,options.EntryNodes,1); + add_nickname_list_to_smartlist(preferredentries,options->EntryNodes,1); get_connection_array(&carray, &n_connections); @@ -871,7 +870,7 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) continue; /* skip routers that are known to be down */ } if(!router->is_verified && - (!(options._AllowUnverified & ALLOW_UNVERIFIED_EXIT) || + (!(options->_AllowUnverified & ALLOW_UNVERIFIED_EXIT) || router_is_unreliable_router(router, 1, 1))) { /* if it's unverified, and either we don't want it or it's unsuitable */ n_supported[i] = -1; @@ -923,10 +922,10 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) n_best_support, best_support, n_pending_connections); preferredexits = smartlist_create(); - add_nickname_list_to_smartlist(preferredexits,options.ExitNodes,1); + add_nickname_list_to_smartlist(preferredexits,options->ExitNodes,1); excludedexits = smartlist_create(); - add_nickname_list_to_smartlist(excludedexits,options.ExcludeNodes,0); + add_nickname_list_to_smartlist(excludedexits,options->ExcludeNodes,0); sl = smartlist_create(); @@ -938,7 +937,7 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) smartlist_add(sl, smartlist_get(dir->routers, i)); smartlist_subtract(sl,excludedexits); - if (options.StrictExitNodes || smartlist_overlap(sl,preferredexits)) + if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits)) smartlist_intersect(sl,preferredexits); router = routerlist_sl_choose_by_bandwidth(sl); } else { @@ -952,7 +951,7 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) smartlist_add(sl, smartlist_get(dir->routers, i)); smartlist_subtract(sl,excludedexits); - if (options.StrictExitNodes || smartlist_overlap(sl,preferredexits)) + if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits)) smartlist_intersect(sl,preferredexits); router = routerlist_sl_choose_by_bandwidth(sl); } @@ -966,7 +965,7 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) log_fn(LOG_INFO, "Chose exit server '%s'", router->nickname); return router; } - if (options.StrictExitNodes) + if (options->StrictExitNodes) log_fn(LOG_WARN, "No exit routers seem to be running; can't choose an exit."); return NULL; @@ -985,12 +984,13 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir) { routerinfo_t *r; + or_options_t *options = get_options(); switch(purpose) { case CIRCUIT_PURPOSE_C_GENERAL: return choose_good_exit_server_general(dir); case CIRCUIT_PURPOSE_C_ESTABLISH_REND: - r = router_choose_random_node(options.RendNodes, options.RendExcludeNodes, - NULL, 0, 1, options._AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0); + r = router_choose_random_node(options->RendNodes, options->RendExcludeNodes, + NULL, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0); return r; } log_fn(LOG_WARN,"Unhandled purpose %d", purpose); @@ -1008,10 +1008,11 @@ onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest) int r; cpath_build_state_t *info; routerinfo_t *exit; + router_get_routerlist(&rl); if (!rl) return NULL; - r = new_route_len(options.PathlenCoinWeight, purpose, rl->routers); + r = new_route_len(get_options()->PathlenCoinWeight, purpose, rl->routers); if (r < 1) /* must be at least 1 */ return NULL; info = tor_malloc_zero(sizeof(cpath_build_state_t)); @@ -1112,8 +1113,8 @@ static routerinfo_t *choose_good_middle_server(cpath_build_state_t *state, routerlist_add_family(excluded, r); } } - choice = router_choose_random_node(NULL, options.ExcludeNodes, excluded, - 0, 1, options._AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0); + choice = router_choose_random_node(NULL, get_options()->ExcludeNodes, excluded, + 0, 1, get_options()->_AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0); smartlist_free(excluded); return choice; } @@ -1122,6 +1123,7 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state) { routerinfo_t *r, *choice; smartlist_t *excluded = smartlist_create(); + or_options_t *options = get_options(); char buf[16]; if((r = router_get_by_digest(state->chosen_exit_digest))) { @@ -1132,7 +1134,7 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state) smartlist_add(excluded, r); routerlist_add_family(excluded, r); } - if(options.FascistFirewall) { + if(options->FascistFirewall) { /* exclude all ORs that listen on the wrong port */ routerlist_t *rl; int i; @@ -1144,13 +1146,13 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state) for(i=0; i < smartlist_len(rl->routers); i++) { r = smartlist_get(rl->routers, i); tor_snprintf(buf, sizeof(buf), "%d", r->or_port); - if (!smartlist_string_isin(options.FirewallPorts, buf)) + if (!smartlist_string_isin(options->FirewallPorts, buf)) smartlist_add(excluded, r); } } - choice = router_choose_random_node(options.EntryNodes, options.ExcludeNodes, - excluded, 0, 1, options._AllowUnverified & ALLOW_UNVERIFIED_ENTRY, - options.StrictEntryNodes); + choice = router_choose_random_node(options->EntryNodes, options->ExcludeNodes, + excluded, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY, + options->StrictEntryNodes); smartlist_free(excluded); return choice; } @@ -1188,7 +1190,7 @@ onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t state->desired_path_len); excludednodes = smartlist_create(); - add_nickname_list_to_smartlist(excludednodes,options.ExcludeNodes,0); + add_nickname_list_to_smartlist(excludednodes,get_options()->ExcludeNodes,0); if(cur_len == state->desired_path_len - 1) { /* Picking last node */ choice = router_get_by_digest(state->chosen_exit_digest); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index ad31d6f8ec..8519ce0c0a 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -9,8 +9,6 @@ #include "or.h" -extern or_options_t options; /* command-line and config-file options */ - /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ diff --git a/src/or/circuituse.c b/src/or/circuituse.c index ba4f65047f..7eb3376ad8 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -9,8 +9,6 @@ #include "or.h" -extern or_options_t options; /* command-line and config-file options */ - /********* START VARIABLES **********/ extern circuit_t *global_circuitlist; /* from circuitlist.c */ @@ -57,7 +55,7 @@ static int circuit_is_acceptable(circuit_t *circ, if(purpose == CIRCUIT_PURPOSE_C_GENERAL) if(circ->timestamp_dirty && - circ->timestamp_dirty+options.NewCircuitPeriod <= now) + circ->timestamp_dirty+get_options()->NewCircuitPeriod <= now) return 0; if(conn) { @@ -264,7 +262,7 @@ int circuit_stream_is_being_handled(connection_t *conn) { if(CIRCUIT_IS_ORIGIN(circ) && circ->state != CIRCUIT_STATE_OPEN && !circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && (!circ->timestamp_dirty || - circ->timestamp_dirty + options.NewCircuitPeriod < now)) { + circ->timestamp_dirty + get_options()->NewCircuitPeriod < now)) { exitrouter = router_get_by_digest(circ->build_state->chosen_exit_digest); if(exitrouter && connection_ap_can_use_exit(conn, exitrouter)) if(++num >= MIN_CIRCUITS_HANDLING_STREAM) @@ -297,12 +295,12 @@ void circuit_build_needed_circs(time_t now) { if(time_to_new_circuit < now) { circuit_reset_failure_count(1); - time_to_new_circuit = now + options.NewCircuitPeriod; - if(proxy_mode()) + time_to_new_circuit = now + get_options()->NewCircuitPeriod; + if(proxy_mode(get_options())) client_dns_clean(); circuit_expire_old_circuits(); - if(options.RunTesting && circ && + if(get_options()->RunTesting && circ && circ->timestamp_created + TESTING_CIRCUIT_INTERVAL < now) { log_fn(LOG_INFO,"Creating a new testing circuit."); circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL); @@ -452,7 +450,7 @@ circuit_expire_old_circuits(void) * on it, mark it for close. */ if (circ->timestamp_dirty && - circ->timestamp_dirty + options.NewCircuitPeriod < now && + circ->timestamp_dirty + get_options()->NewCircuitPeriod < now && !circ->p_conn && /* we're the origin */ !circ->p_streams /* nothing attached */ ) { log_fn(LOG_DEBUG,"Closing n_circ_id %d (dirty %d secs ago, purp %d)",circ->n_circ_id, diff --git a/src/or/command.c b/src/or/command.c index 8cd1ca91fe..0637330be2 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -15,8 +15,6 @@ #include "or.h" -extern or_options_t options; /* command-line and config-file options */ - /** Keep statistics about how many of each type of cell we've received. */ unsigned long stats_n_padding_cells_processed = 0; unsigned long stats_n_create_cells_processed = 0; diff --git a/src/or/config.c b/src/or/config.c index 3ab114ab51..e553dc9695 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -155,19 +155,16 @@ static config_var_t config_vars[] = { /** Largest allowed config line */ #define CONFIG_LINE_T_MAXLEN 4096 -static struct config_line_t *config_get_commandlines(int argc, char **argv); -static int config_get_lines(FILE *f, struct config_line_t **result); -static void config_free_lines(struct config_line_t *front); -static int config_assign_line(or_options_t *options, struct config_line_t *c, - int reset); -static int config_assign(or_options_t *options, struct config_line_t *list, - int reset); +static void option_reset(or_options_t *options, config_var_t *var); +static void options_free(or_options_t *options); +static or_options_t *options_dup(or_options_t *old); +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_redirect_line(or_options_t *options, struct config_line_t *line); -static const char *expand_abbrev(const char *option, int commandline_only); -static config_var_t *config_find_option(const char *key); -static void reset_option(or_options_t *options, config_var_t *var); static int parse_log_severity_range(const char *range, int *min_out, int *max_out); static int convert_log_option(or_options_t *options, @@ -178,6 +175,25 @@ static int add_single_log_option(or_options_t *options, int minSeverity, const char *type, const char *fname); static int normalize_log_options(or_options_t *options); +/* + * Functions to read and write the global options pointer. + */ + +/** Command-line and config-file options. */ +static or_options_t *global_options=NULL; + +or_options_t *get_options(void) { + tor_assert(global_options); + return global_options; +} +void set_options(or_options_t *new) { + global_options = new; +} + +/* + * Functions to parse config options + */ + /** If option is an official abbreviation for a longer option, * return the longer option. Otherwise return option. * If command_line is set, apply all abbreviations. Otherwise, only @@ -249,34 +265,34 @@ config_line_prepend(struct config_line_t *front, return newline; } -/** Helper: parse the config file and strdup into key/value - * strings. Set *result to the list, or NULL if parsing the file +/** Helper: parse the config string and strdup into key/value + * strings. Set *result to the list, or NULL if parsing the string * failed. Return 0 on success, -1 on failure. Warn and ignore any * misformatted lines. */ -static int -config_get_lines(FILE *f, struct config_line_t **result) +int +config_get_lines(char *string, struct config_line_t **result) { - struct config_line_t *front = NULL; - char line[CONFIG_LINE_T_MAXLEN]; - int r; - char *key, *value; + struct config_line_t *list = NULL; + char *k, *v; - while ((r = parse_line_from_file(line, sizeof(line), f, &key, &value)) > 0) { - front = config_line_prepend(front, key, value); - } + do { + string = parse_line_from_str(string, &k, &v); + if (!string) { + config_free_lines(list); + return -1; + } + if (k && v) + list = config_line_prepend(list, k, v); + } while (*string); - if (r < 0) { - *result = NULL; - return -1; - } - *result = front; + *result = list; return 0; } /** * Free all the configuration lines on the linked list front. */ -static void +void config_free_lines(struct config_line_t *front) { struct config_line_t *tmp; @@ -341,7 +357,7 @@ config_assign_line(or_options_t *options, struct config_line_t *c, int reset) } if (reset && !strlen(c->value)) { - reset_option(options, var); + option_reset(options, var); return 0; } @@ -351,9 +367,9 @@ config_assign_line(or_options_t *options, struct config_line_t *c, int reset) case CONFIG_TYPE_UINT: i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL); if (!ok) { - log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds. Skipping.", + log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.", c->key,c->value); - return 0; + return -1; } *(int *)lvalue = i; break; @@ -361,8 +377,8 @@ config_assign_line(or_options_t *options, struct config_line_t *c, int reset) case CONFIG_TYPE_BOOL: i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL); if (!ok) { - log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1. Skipping.", c->key); - return 0; + log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key); + return -1; } *(int *)lvalue = i; break; @@ -384,7 +400,6 @@ config_assign_line(or_options_t *options, struct config_line_t *c, int reset) SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); break; - case CONFIG_TYPE_LINELIST: case CONFIG_TYPE_LINELIST_S: /* Note: this reverses the order that the lines appear in. That's @@ -404,7 +419,6 @@ config_assign_line(or_options_t *options, struct config_line_t *c, int reset) tor_assert(0); break; } - return 0; } @@ -418,7 +432,7 @@ config_reset_line(or_options_t *options, const char *key) if (!var) return; /* give error on next pass. */ - reset_option(options, var); + option_reset(options, var); } /** Return a canonicalized list of the options assigned for key. @@ -465,6 +479,8 @@ config_get_assigned_option(or_options_t *options, const char *key) result->value = tor_strdup(value ? (char*)value : ""); break; case CONFIG_TYPE_UINT: + /* XXX This means every or_options_t uint or bool element + * needs to be an int. Not, say, a uint16_t or char. */ tor_snprintf(buf, sizeof(buf), "%d", *(int*)value); result->value = tor_strdup(buf); break; @@ -514,7 +530,7 @@ config_assign(or_options_t *options, struct config_line_t *list, int reset) } } - /* pass 2: if we're reading from a resetting souurce, clear all mentioned + /* pass 2: if we're reading from a resetting source, clear all mentioned * linelists. */ if (reset) { for (p = list; p; p = p->next) @@ -530,6 +546,89 @@ config_assign(or_options_t *options, struct config_line_t *list, int reset) return 0; } +/** Try assigning list to options. You do this by duping + * options, assigning list to the new one, then validating it. If it's + * ok, then through out the old one and stick with the new one. Else, + * revert to old and return failure. + */ +int +config_trial_assign(or_options_t **options, struct config_line_t *list, int reset) +{ + or_options_t *trial_options = options_dup(*options); + + if (config_assign(trial_options, list, reset) < 0) { + options_free(trial_options); + return -1; + } + + if (options_validate(trial_options) < 0) { + options_free(trial_options); + return -1; + } + + if (options_transition_allowed(*options, trial_options) < 0) { + options_free(trial_options); + return -1; + } + + /* XXX now act on options */ + + options_free(*options); + *options = trial_options; + return 0; +} + +/** Replace the option indexed by var in options with its + * default value. */ +static void +option_reset(or_options_t *options, config_var_t *var) +{ + struct config_line_t *c; + void *lvalue; + + lvalue = ((char*)options) + var->var_offset; + switch (var->type) { + case CONFIG_TYPE_STRING: + tor_free(*(char**)lvalue); + break; + case CONFIG_TYPE_DOUBLE: + *(double*)lvalue = 0.0; + break; + case CONFIG_TYPE_UINT: + case CONFIG_TYPE_BOOL: + *(int*)lvalue = 0; + break; + case CONFIG_TYPE_CSV: + if (*(smartlist_t**)lvalue) { + SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp)); + smartlist_free(*(smartlist_t **)lvalue); + *(smartlist_t **)lvalue = NULL; + } + break; + case CONFIG_TYPE_LINELIST: + case CONFIG_TYPE_LINELIST_S: + config_free_lines(*(struct config_line_t **)lvalue); + *(struct config_line_t **)lvalue = NULL; + break; + case CONFIG_TYPE_LINELIST_V: + /* handled by linelist_s. */ + break; + case CONFIG_TYPE_OBSOLETE: + break; + } + if (var->initvalue) { + c = tor_malloc(sizeof(struct config_line_t)); + c->key = tor_strdup(var->name); + c->value = tor_strdup(var->initvalue); + config_assign_line(options,c,0); + config_free_lines(c); + } +} + + + + + static void add_default_trusted_dirservers(void) { @@ -657,7 +756,7 @@ get_default_nickname(void) /** Release storage held by options */ static void -free_options(or_options_t *options) +options_free(or_options_t *options) { int i; void *lvalue; @@ -699,149 +798,47 @@ free_options(or_options_t *options) } } -/** Replace the option indexed by var in options with its - * default value. */ -static void -reset_option(or_options_t *options, config_var_t *var) +/** Copy storage held by old into a new or_options_t and return it. */ +static or_options_t * +options_dup(or_options_t *old) { - struct config_line_t *c; - void *lvalue; + or_options_t *new; + int i; + struct config_line_t *line; - lvalue = ((char*)options) + var->var_offset; - switch (var->type) { - case CONFIG_TYPE_STRING: - tor_free(*(char**)lvalue); - break; - case CONFIG_TYPE_DOUBLE: - *(double*)lvalue = 0.0; - break; - case CONFIG_TYPE_UINT: - case CONFIG_TYPE_BOOL: - *(int*)lvalue = 0; - break; - case CONFIG_TYPE_CSV: - if (*(smartlist_t**)lvalue) { - SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp)); - smartlist_free(*(smartlist_t **)lvalue); - *(smartlist_t **)lvalue = NULL; + new = tor_malloc_zero(sizeof(or_options_t)); + for (i=0; config_vars[i].name; ++i) { + line = config_get_assigned_option(old, config_vars[i].name); + if (line) { + if (config_assign(new, line, 0) < 0) { + log_fn(LOG_WARN,"Bug: config_get_assigned_option() generated " + "something we couldn't config_assign()."); + tor_assert(0); } - break; - case CONFIG_TYPE_LINELIST: - case CONFIG_TYPE_LINELIST_S: - config_free_lines(*(struct config_line_t **)lvalue); - *(struct config_line_t **)lvalue = NULL; - break; - case CONFIG_TYPE_LINELIST_V: - /* handled by linelist_s. */ - break; - case CONFIG_TYPE_OBSOLETE: - break; - } - if (var->initvalue) { - c = tor_malloc(sizeof(struct config_line_t)); - c->key = tor_strdup(var->name); - c->value = tor_strdup(var->initvalue); - config_assign_line(options,c,0); - config_free_lines(c); + } + config_free_lines(line); } + return new; } /** Set options to hold reasonable defaults for most options. * Each option defaults to zero. */ -static void -init_options(or_options_t *options) +void +options_init(or_options_t *options) { int i; config_var_t *var; - memset(options,0,sizeof(or_options_t)); for (i=0; config_vars[i].name; ++i) { var = &config_vars[i]; if(!var->initvalue) continue; /* defaults to NULL or 0 */ - reset_option(options, var); + option_reset(options, var); } } -#ifdef MS_WINDOWS -static char *get_windows_conf_root(void) -{ - static int is_set = 0; - static char path[MAX_PATH+1]; - - LPITEMIDLIST idl; - IMalloc *m; - HRESULT result; - - if (is_set) - return path; - - /* Find X:\documents and settings\username\applicatation data\ . - * We would use SHGetSpecialFolder path, but that wasn't added until IE4. - */ - if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, - &idl))) { - GetCurrentDirectory(MAX_PATH, path); - is_set = 1; - log_fn(LOG_WARN, "I couldn't find your application data folder: are you running an ancient version of Windows 95? Defaulting to '%s'", path); - return path; - } - /* Convert the path from an "ID List" (whatever that is!) to a path. */ - result = SHGetPathFromIDList(idl, path); - /* Now we need to free the */ - SHGetMalloc(&m); - if (m) { - m->lpVtbl->Free(m, idl); - m->lpVtbl->Release(m); - } - if (!SUCCEEDED(result)) { - return NULL; - } - strlcat(path,"\\tor",MAX_PATH); - is_set = 1; - return path; -} -#endif - -static char * -get_default_conf_file(void) -{ -#ifdef MS_WINDOWS - char *path = tor_malloc(MAX_PATH); - strlcpy(path, get_windows_conf_root(), MAX_PATH); - strlcat(path,"\\torrc",MAX_PATH); - return path; -#else - return tor_strdup(CONFDIR "/torrc"); -#endif -} - -/** Verify whether lst is a string containing valid-looking space-separated - * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure. - */ -static int check_nickname_list(const char *lst, const char *name) -{ - int r = 0; - smartlist_t *sl; - - if (!lst) - return 0; - sl = smartlist_create(); - smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH(sl, const char *, s, - { - if (!is_legal_nickname_or_hexdigest(s)) { - log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name); - r = -1; - } - }); - SMARTLIST_FOREACH(sl, char *, s, tor_free(s)); - smartlist_free(sl); - return r; -} - static int -validate_options(or_options_t *options) +options_validate(or_options_t *options) { int i; int result = 0; @@ -853,7 +850,7 @@ validate_options(or_options_t *options) } if (options->Nickname == NULL) { - if (server_mode()) { + if (server_mode(options)) { if (!(options->Nickname = get_default_nickname())) return -1; log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname); @@ -875,7 +872,7 @@ validate_options(or_options_t *options) } } - if (server_mode()) { + if (server_mode(options)) { /* confirm that our address isn't broken, so we can complain now */ uint32_t tmp; if (resolve_my_address(options->Address, &tmp) < 0) @@ -1031,14 +1028,20 @@ validate_options(or_options_t *options) result = -1; } - if (!options->RedirectExitList) - options->RedirectExitList = smartlist_create(); -/* XXX need to free the old one if it's there, else they just keep piling up */ + /* free options->RedirectExitList */ + if (options->RedirectExitList) { + SMARTLIST_FOREACH(options->RedirectExitList, + exit_redirect_t *, p, tor_free(p)); + smartlist_free(options->RedirectExitList); + } + + options->RedirectExitList = smartlist_create(); for (cl = options->RedirectExit; cl; cl = cl->next) { if (parse_redirect_line(options, cl)<0) result = -1; } +/* XXX bug: this parsing shouldn't have side effects */ clear_trusted_dir_servers(); if (!options->DirServers) { add_default_trusted_dirservers(); @@ -1052,23 +1055,125 @@ validate_options(or_options_t *options) return result; } +/** Check if any of the previous options have changed but aren't allowed to. */ +static int +options_transition_allowed(or_options_t *old, or_options_t *new) { + + if(!old) + return 0; + + if (old->PidFile && + (!new->PidFile || strcmp(old->PidFile,new->PidFile))) { + log_fn(LOG_WARN,"PidFile is not allowed to change. Failing."); + return -1; + } + + if (old->RunAsDaemon && !new->RunAsDaemon) { + log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing."); + return -1; + } + + if (old->ORPort != new->ORPort) { + log_fn(LOG_WARN,"During reload, changing ORPort is not allowed. Failing."); + return -1; + } + + return 0; +} + +#ifdef MS_WINDOWS +static char *get_windows_conf_root(void) +{ + static int is_set = 0; + static char path[MAX_PATH+1]; + + LPITEMIDLIST idl; + IMalloc *m; + HRESULT result; + + if (is_set) + return path; + + /* Find X:\documents and settings\username\applicatation data\ . + * We would use SHGetSpecialFolder path, but that wasn't added until IE4. + */ + if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, + &idl))) { + GetCurrentDirectory(MAX_PATH, path); + is_set = 1; + log_fn(LOG_WARN, "I couldn't find your application data folder: are you running an ancient version of Windows 95? Defaulting to '%s'", path); + return path; + } + /* Convert the path from an "ID List" (whatever that is!) to a path. */ + result = SHGetPathFromIDList(idl, path); + /* Now we need to free the */ + SHGetMalloc(&m); + if (m) { + m->lpVtbl->Free(m, idl); + m->lpVtbl->Release(m); + } + if (!SUCCEEDED(result)) { + return NULL; + } + strlcat(path,"\\tor",MAX_PATH); + is_set = 1; + return path; +} +#endif + +static char * +get_default_conf_file(void) +{ +#ifdef MS_WINDOWS + char *path = tor_malloc(MAX_PATH); + strlcpy(path, get_windows_conf_root(), MAX_PATH); + strlcat(path,"\\torrc",MAX_PATH); + return path; +#else + return tor_strdup(CONFDIR "/torrc"); +#endif +} + +/** Verify whether lst is a string containing valid-looking space-separated + * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure. + */ +static int check_nickname_list(const char *lst, const char *name) +{ + int r = 0; + smartlist_t *sl; + + if (!lst) + return 0; + sl = smartlist_create(); + smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH(sl, const char *, s, + { + if (!is_legal_nickname_or_hexdigest(s)) { + log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name); + r = -1; + } + }); + SMARTLIST_FOREACH(sl, char *, s, tor_free(s)); + smartlist_free(sl); + return r; +} + + /** Read a configuration file into options, finding the configuration * file location based on the command line. After loading the options, * validate them for consistency. Return 0 if success, <0 if failure. */ int -getconfig(int argc, char **argv, or_options_t *options) +getconfig(int argc, char **argv) { + or_options_t *oldoptions, *newoptions; struct config_line_t *cl; - FILE *cf; - char *fname; - int i; - int result = 0; + char *cf=NULL, *fname=NULL; + int i, retval; int using_default_torrc; static char **backup_argv; static int backup_argc; - char *previous_pidfile = NULL; - int previous_runasdaemon = 0; - int previous_orport = -1; + + oldoptions = global_options; if (argv) { /* first time we're called. save commandline args */ backup_argv = argv; @@ -1076,16 +1181,7 @@ getconfig(int argc, char **argv, or_options_t *options) } else { /* we're reloading. need to clean up old options first. */ argv = backup_argv; argc = backup_argc; - - /* record some previous values, so we can fail if they change */ - if (options->PidFile) - previous_pidfile = tor_strdup(options->PidFile); - previous_runasdaemon = options->RunAsDaemon; - previous_orport = options->ORPort; - free_options(options); } - init_options(options); - if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) { print_usage(); exit(0); @@ -1096,10 +1192,13 @@ getconfig(int argc, char **argv, or_options_t *options) exit(0); } + newoptions = tor_malloc_zero(sizeof(or_options_t)); + options_init(newoptions); + /* learn config file name, get config lines, assign them */ fname = NULL; using_default_torrc = 1; - options->command = CMD_RUN_TOR; + newoptions->command = CMD_RUN_TOR; for (i = 1; i < argc; ++i) { if (i < argc-1 && !strcmp(argv[i],"-f")) { if (fname) { @@ -1110,10 +1209,10 @@ getconfig(int argc, char **argv, or_options_t *options) using_default_torrc = 0; ++i; } else if (!strcmp(argv[i],"--list-fingerprint")) { - options->command = CMD_LIST_FINGERPRINT; + newoptions->command = CMD_LIST_FINGERPRINT; } else if (!strcmp(argv[i],"--hash-password")) { - options->command = CMD_HASH_PASSWORD; - options->command_arg = tor_strdup( (i < argc-1) ? argv[i+1] : ""); + newoptions->command = CMD_HASH_PASSWORD; + newoptions->command_arg = tor_strdup( (i < argc-1) ? argv[i+1] : ""); ++i; } } @@ -1138,7 +1237,7 @@ getconfig(int argc, char **argv, or_options_t *options) tor_assert(fname); log(LOG_DEBUG, "Opening config file '%s'", fname); - cf = fopen(fname, "r"); + cf = read_file_to_str(fname, 0); if (!cf) { if (using_default_torrc == 1) { log(LOG_NOTICE, "Configuration file '%s' not present, " @@ -1147,51 +1246,45 @@ getconfig(int argc, char **argv, or_options_t *options) } else { log(LOG_WARN, "Unable to open configuration file '%s'.", fname); tor_free(fname); - return -1; + goto err; } } else { /* it opened successfully. use it. */ tor_free(fname); - if (config_get_lines(cf, &cl)<0) - return -1; - if (config_assign(options,cl, 0) < 0) - return -1; + retval = config_get_lines(cf, &cl); + tor_free(cf); + if (retval < 0) + goto err; + retval = config_assign(newoptions, cl, 0); config_free_lines(cl); - fclose(cf); + if (retval < 0) + goto err; } /* go through command-line variables too */ cl = config_get_commandlines(argc,argv); - if (config_assign(options,cl,0) < 0) - return -1; + retval = config_assign(newoptions,cl,0); config_free_lines(cl); + if (retval < 0) + goto err; -/* Validate options */ +/* Validate newoptions */ + if (options_validate(newoptions) < 0) + goto err; - /* first check if any of the previous options have changed but aren't allowed to */ - if (previous_pidfile && strcmp(previous_pidfile,options->PidFile)) { - log_fn(LOG_WARN,"During reload, PidFile changed from %s to %s. Failing.", - previous_pidfile, options->PidFile); - return -1; - } - tor_free(previous_pidfile); + if (options_transition_allowed(oldoptions, newoptions) < 0) + goto err; - if (previous_runasdaemon && !options->RunAsDaemon) { - log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing."); - return -1; - } + /* XXX now act on options */ + if (rend_config_services(newoptions) < 0) + goto err; - if (previous_orport == 0 && options->ORPort > 0) { - log_fn(LOG_WARN,"During reload, change from ORPort=0 to >0 not allowed. Failing."); - return -1; - } - - if (validate_options(options) < 0) - result = -1; - - if (rend_config_services(options) < 0) { - result = -1; - } - return result; + if(oldoptions) + options_free(oldoptions); + set_options(newoptions); + return 0; + err: + options_free(newoptions); + return -1; } static int @@ -1282,6 +1375,7 @@ config_init_logs(or_options_t *options) { struct config_line_t *opt; int ok; + smartlist_t *elts; if (normalize_log_options(options)) return -1; @@ -1291,7 +1385,7 @@ config_init_logs(or_options_t *options) } ok = 1; - smartlist_t *elts = smartlist_create(); + elts = smartlist_create(); for (opt = options->Logs; opt; opt = opt->next) { int levelMin=LOG_DEBUG, levelMax=LOG_ERR; smartlist_split_string(elts, opt->value, " ", @@ -1496,7 +1590,7 @@ static int parse_redirect_line(or_options_t *options, } else { if (parse_addr_port(smartlist_get(elements,1),NULL,&r->addr_dest, &r->port_dest)) { - log_fn(LOG_WARN, "Error parseing dest address in RedirectExit line"); + log_fn(LOG_WARN, "Error parsing dest address in RedirectExit line"); goto err; } r->is_redirect = 1; @@ -1565,17 +1659,15 @@ static int parse_dir_server_line(const char *line) done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); - - if (address) - tor_free(address); - + tor_free(address); return r; } const char * -get_data_directory(or_options_t *options) +get_data_directory(void) { const char *d; + or_options_t *options = get_options(); if (options->DataDirectory) { d = options->DataDirectory; diff --git a/src/or/connection.c b/src/or/connection.c index 809e115733..e08c1d08cb 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -12,8 +12,6 @@ /********* START VARIABLES **********/ -extern or_options_t options; /* command-line and config-file options */ - /** Array of strings to make conn-\>type human-readable. */ const char *conn_type_to_string[] = { "", /* 0 */ @@ -488,6 +486,7 @@ static int connection_init_accepted_conn(connection_t *conn) { int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_t port) { int s; struct sockaddr_in dest_addr; + or_options_t *options = get_options(); s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); if (s < 0) { @@ -496,15 +495,15 @@ int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_ return -1; } - if (options.OutboundBindAddress) { + if (options->OutboundBindAddress) { struct sockaddr_in ext_addr; memset(&ext_addr, 0, sizeof(ext_addr)); ext_addr.sin_family = AF_INET; ext_addr.sin_port = 0; - if (!tor_inet_aton(options.OutboundBindAddress, &ext_addr.sin_addr)) { + if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) { log_fn(LOG_WARN,"Outbound bind address '%s' didn't parse. Ignoring.", - options.OutboundBindAddress); + options->OutboundBindAddress); } else { if(bind(s, (struct sockaddr*)&ext_addr, sizeof(ext_addr)) < 0) { log_fn(LOG_WARN,"Error binding network socket: %s", @@ -641,18 +640,19 @@ static int retry_listeners(int type, struct config_line_t *cfg, * connections for a given type. */ int retry_all_listeners(int force) { + or_options_t *options = get_options(); - if (retry_listeners(CONN_TYPE_OR_LISTENER, options.ORBindAddress, - options.ORPort, "0.0.0.0", force)<0) + if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORBindAddress, + options->ORPort, "0.0.0.0", force)<0) return -1; - if (retry_listeners(CONN_TYPE_DIR_LISTENER, options.DirBindAddress, - options.DirPort, "0.0.0.0", force)<0) + if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirBindAddress, + options->DirPort, "0.0.0.0", force)<0) return -1; - if (retry_listeners(CONN_TYPE_AP_LISTENER, options.SocksBindAddress, - options.SocksPort, "127.0.0.1", force)<0) + if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksBindAddress, + options->SocksPort, "127.0.0.1", force)<0) return -1; if (retry_listeners(CONN_TYPE_CONTROL_LISTENER, NULL, - options.ControlPort, "127.0.0.1", force)<0) + options->ControlPort, "127.0.0.1", force)<0) return -1; return 0; @@ -702,11 +702,12 @@ static void connection_read_bucket_decrement(connection_t *conn, int num_read) { } } -/** Initiatialize the global read bucket to options.BandwidthBurstBytes, +/** Initiatialize the global read bucket to options->BandwidthBurstBytes, * and current_time to the current time. */ void connection_bucket_init(void) { - global_read_bucket = options.BandwidthBurstBytes; /* start it at max traffic */ - global_write_bucket = options.BandwidthBurstBytes; /* start it at max traffic */ + or_options_t *options = get_options(); + global_read_bucket = options->BandwidthBurstBytes; /* start it at max traffic */ + global_write_bucket = options->BandwidthBurstBytes; /* start it at max traffic */ } /** A second has rolled over; increment buckets appropriately. */ @@ -714,14 +715,15 @@ void connection_bucket_refill(struct timeval *now) { int i, n; connection_t *conn; connection_t **carray; + or_options_t *options = get_options(); /* refill the global buckets */ - if(global_read_bucket < options.BandwidthBurstBytes) { - global_read_bucket += options.BandwidthRateBytes; + if(global_read_bucket < options->BandwidthBurstBytes) { + global_read_bucket += options->BandwidthRateBytes; log_fn(LOG_DEBUG,"global_read_bucket now %d.", global_read_bucket); } - if(global_write_bucket < options.BandwidthBurstBytes) { - global_write_bucket += options.BandwidthRateBytes; + if(global_write_bucket < options->BandwidthBurstBytes) { + global_write_bucket += options->BandwidthRateBytes; log_fn(LOG_DEBUG,"global_write_bucket now %d.", global_write_bucket); } diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 5d799c20ee..b9eaa7ddbc 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -10,8 +10,6 @@ #include "or.h" #include "tree.h" -extern or_options_t options; /* command-line and config-file options */ - static struct exit_policy_t *socks_policy = NULL; static int connection_ap_handshake_process_socks(connection_t *conn); @@ -245,6 +243,7 @@ void connection_ap_expire_beginning(void) { circuit_t *circ; int n, i; time_t now = time(NULL); + or_options_t *options = get_options(); get_connection_array(&carray, &n); @@ -293,7 +292,7 @@ void connection_ap_expire_beginning(void) { * current streams on it to survive if they can: make it * unattractive to use for new streams */ tor_assert(circ->timestamp_dirty); - circ->timestamp_dirty -= options.NewCircuitPeriod; + circ->timestamp_dirty -= options->NewCircuitPeriod; /* give our stream another 15 seconds to try */ conn->timestamp_lastread += 15; /* attaching to a dirty circuit is fine */ @@ -899,6 +898,7 @@ void connection_exit_connect(connection_t *conn) { unsigned char connected_payload[4]; uint32_t addr; uint16_t port; + or_options_t *options = get_options(); if (!connection_edge_is_rendezvous_stream(conn) && router_compare_to_my_exit_policy(conn) == ADDR_POLICY_REJECTED) { @@ -911,7 +911,7 @@ void connection_exit_connect(connection_t *conn) { addr = conn->addr; port = conn->port; - SMARTLIST_FOREACH(options.RedirectExitList, exit_redirect_t *, r, + SMARTLIST_FOREACH(options->RedirectExitList, exit_redirect_t *, r, { if ((addr&r->mask)==(r->addr&r->mask) && (r->port_min <= port) && (port <= r->port_max)) { @@ -1003,7 +1003,7 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit) /** A helper function for socks_policy_permits_address() below. * - * Parse options.SocksPolicy in the same way that the exit policy + * Parse options->SocksPolicy in the same way that the exit policy * is parsed, and put the processed version in &socks_policy. * Ignore port specifiers. */ @@ -1014,7 +1014,7 @@ static void parse_socks_policy(void) exit_policy_free(socks_policy); socks_policy = NULL; } - config_parse_exit_policy(options.SocksPolicy, &socks_policy); + config_parse_exit_policy(get_options()->SocksPolicy, &socks_policy); /* ports aren't used. */ for (n=socks_policy; n; n = n->next) { n->prt_min = 1; @@ -1028,7 +1028,8 @@ static void parse_socks_policy(void) int socks_policy_permits_address(uint32_t addr) { int a; - if (options.SocksPolicy && !socks_policy) + or_options_t *options = get_options(); + if (options->SocksPolicy && !socks_policy) parse_socks_policy(); if(!socks_policy) /* 'no socks policy' means 'accept' */ diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 4b01778b67..6b9975bae3 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -10,8 +10,6 @@ #include "or.h" -extern or_options_t options; /**< command-line and config-file options */ - static int connection_tls_finish_handshake(connection_t *conn); static int connection_or_process_cells_from_inbuf(connection_t *conn); @@ -121,10 +119,10 @@ connection_or_init_conn_from_address(connection_t *conn, uint32_t addr, uint16_t port, const char *id_digest) { - routerinfo_t *r; struct in_addr in; const char *n; - r = router_get_by_digest(id_digest); + or_options_t *options = get_options(); + routerinfo_t *r = router_get_by_digest(id_digest); if (r) { connection_or_init_conn_from_router(conn,r); return; @@ -132,7 +130,7 @@ connection_or_init_conn_from_address(connection_t *conn, conn->addr = addr; conn->port = port; /* This next part isn't really right, but it's good enough for now. */ - conn->receiver_bucket = conn->bandwidth = options.BandwidthBurstBytes; + conn->receiver_bucket = conn->bandwidth = options->BandwidthBurstBytes; memcpy(conn->identity_digest, id_digest, DIGEST_LEN); /* If we're an authoritative directory server, we may know a * nickname for this router. */ @@ -203,7 +201,7 @@ connection_t *connection_or_connect(uint32_t addr, uint16_t port, tor_assert(id_digest); - if(server_mode() && (me=router_get_my_routerinfo()) && + if(server_mode(get_options()) && (me=router_get_my_routerinfo()) && !memcmp(me->identity_digest, id_digest,DIGEST_LEN)) { log_fn(LOG_WARN,"Request to connect to myself! Failing."); return NULL; @@ -334,12 +332,13 @@ connection_tls_finish_handshake(connection_t *conn) { connection_t *c; crypto_pk_env_t *identity_rcvd=NULL; char digest_rcvd[DIGEST_LEN]; + or_options_t *options = get_options(); conn->state = OR_CONN_STATE_OPEN; connection_watch_events(conn, POLLIN); log_fn(LOG_DEBUG,"tls handshake done. verifying."); if (! tor_tls_peer_has_cert(conn->tls)) { /* It's an OP. */ - if (server_mode()) { /* I'm an OR; good. */ + if (server_mode(options)) { /* I'm an OR; good. */ conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP; return 0; } else { /* Neither side sent a certificate: ouch. */ @@ -376,7 +375,7 @@ connection_tls_finish_handshake(connection_t *conn) { if (connection_or_nonopen_was_started_here(conn)) { /* I initiated this connection. */ if (strcasecmp(conn->nickname, nickname)) { - log_fn(options.DirPort ? LOG_WARN : LOG_INFO, + log_fn(options->DirPort ? LOG_WARN : LOG_INFO, "Other side (%s:%d) is '%s', but we tried to connect to '%s'", conn->address, conn->port, nickname, conn->nickname); control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED); @@ -390,7 +389,7 @@ connection_tls_finish_handshake(connection_t *conn) { connection_or_init_conn_from_address(conn,conn->addr,conn->port,digest_rcvd); } - if (!server_mode()) { /* If I'm an OP... */ + if (!server_mode(options)) { /* If I'm an OP... */ conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP; } directory_set_dirty(); diff --git a/src/or/control.c b/src/or/control.c index 2b2232aed2..51068e59a3 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -43,8 +43,6 @@ static const char *CONTROL_COMMANDS[] = { "authenticate", }; -extern or_options_t options; - static uint32_t global_event_mask = 0; #define AUTHENTICATION_COOKIE_LEN 32 @@ -141,26 +139,25 @@ static int handle_control_setconf(connection_t *conn, uint16_t len, char *body) { - char *k, *v; - struct config_line_t *lines = NULL; + struct config_line_t *lines=NULL; + or_options_t *options = get_options(); - /* XXXX009 move this logic into config.c someplace. */ + if (config_get_lines(body, &lines) < 0) { + log_fn(LOG_WARN,"Controller gave us config lines we can't parse."); + send_control_error(conn, ERR_UNSPECIFIED, "Couldn't parse configuration"); + return 0; + } - do { - body = parse_line_from_str(body, &k, &v); - if (!body) { - goto err; - } - if (k && v) - lines = config_line_prepend(lines, k, v); - } while (*body); + if (config_trial_assign(&options, lines, 1) < 0) { + log_fn(LOG_WARN,"Controller gave us config lines that didn't validate."); + send_control_error(conn, ERR_UNSPECIFIED, "Configuration was invalid"); + config_free_lines(lines); + return 0; + } - /* XXXX009 NM */ - - return 0; - err: - send_control_error(conn, ERR_UNSPECIFIED, "Couldn't parse configuration"); - /* config_free_lines(lines); */ + set_options(options); /* put the new one into place */ + config_free_lines(lines); + send_control_done(conn); return 0; } @@ -172,6 +169,7 @@ handle_control_getconf(connection_t *conn, uint16_t body_len, smartlist_t *answers = NULL; char *msg = NULL; size_t msg_len; + or_options_t *options = get_options(); questions = smartlist_create(); smartlist_split_string(questions, body, "\n", @@ -179,7 +177,7 @@ handle_control_getconf(connection_t *conn, uint16_t body_len, answers = smartlist_create(); SMARTLIST_FOREACH(questions, const char *, q, { - struct config_line_t *answer = config_get_assigned_option(&options,q); + struct config_line_t *answer = config_get_assigned_option(options,q); if (!answer) { send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body); goto done; @@ -245,16 +243,17 @@ static int handle_control_setevents(connection_t *conn, uint16_t len, static int handle_control_authenticate(connection_t *conn, uint16_t len, const char *body) { + or_options_t *options = get_options(); if (len == AUTHENTICATION_COOKIE_LEN && authentication_cookie_is_set && !memcmp(authentication_cookie, body, len)) { goto ok; - } else if (options.HashedControlPassword) { + } else if (options->HashedControlPassword) { char expected[S2K_SPECIFIER_LEN+DIGEST_LEN]; char received[DIGEST_LEN]; if (base64_decode(expected,sizeof(expected), - options.HashedControlPassword, - strlen(options.HashedControlPassword))<0) { + options->HashedControlPassword, + strlen(options->HashedControlPassword))<0) { /* XXXX009 NM we should warn sooner. */ log_fn(LOG_WARN,"Couldn't decode HashedControlPassword: invalid base64"); goto err; @@ -448,7 +447,7 @@ int init_cookie_authentication(void) /* XXXX009 NM add config option to disable this. */ tor_snprintf(fname, sizeof(fname), "%s/control_auth_cookie", - get_data_directory(&options)); + get_data_directory()); crypto_rand(authentication_cookie, AUTHENTICATION_COOKIE_LEN); authentication_cookie_is_set = 1; if (write_bytes_to_file(fname, authentication_cookie, diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index c3d2aa329c..84f42d06f1 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -11,7 +11,6 @@ **/ #include "or.h" -extern or_options_t options; /* command-line and config-file options */ /** The maximum number of cpuworker processes we will keep around. */ #define MAX_CPUWORKERS 16 @@ -302,7 +301,7 @@ static int spawn_cpuworker(void) { * or kill idle ones. */ static void spawn_enough_cpuworkers(void) { - int num_cpuworkers_needed = options.NumCpus; + int num_cpuworkers_needed = get_options()->NumCpus; if(num_cpuworkers_needed < MIN_CPUWORKERS) num_cpuworkers_needed = MIN_CPUWORKERS; diff --git a/src/or/directory.c b/src/or/directory.c index 998e3539b8..c886abd6e4 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -46,8 +46,6 @@ static int directory_handle_command(connection_t *conn); /********* START VARIABLES **********/ -extern or_options_t options; /* command-line and config-file options */ - static struct exit_policy_t *dir_policy = NULL; #if 0 /* commented out for now, since for now what clients send is @@ -67,7 +65,7 @@ char rend_fetch_url[] = "/tor/rendezvous/"; /** A helper function for dir_policy_permits_address() below. * - * Parse options.DirPolicy in the same way that the exit policy + * Parse options->DirPolicy in the same way that the exit policy * is parsed, and put the processed version in &dir_policy. * Ignore port specifiers. */ @@ -78,7 +76,7 @@ static void parse_dir_policy(void) exit_policy_free(dir_policy); dir_policy = NULL; } - config_parse_exit_policy(options.DirPolicy, &dir_policy); + config_parse_exit_policy(get_options()->DirPolicy, &dir_policy); /* ports aren't used. */ for (n=dir_policy; n; n = n->next) { n->prt_min = 1; @@ -92,7 +90,7 @@ static void parse_dir_policy(void) int dir_policy_permits_address(uint32_t addr) { int a; - if (options.DirPolicy && !dir_policy) + if (get_options()->DirPolicy && !dir_policy) parse_dir_policy(); if(!dir_policy) /* 'no dir policy' means 'accept' */ @@ -129,10 +127,10 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload, /* Pay attention to fascistfirewall when we're uploading a * router descriptor, but not when uploading a service * descriptor -- those use Tor. */ - if (options.FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR && - !options.HttpProxy) { + if (get_options()->FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR && + !get_options()->HttpProxy) { tor_snprintf(buf,sizeof(buf),"%d",ds->dir_port); - if (!smartlist_string_isin(options.FirewallPorts, buf)) + if (!smartlist_string_isin(get_options()->FirewallPorts, buf)) continue; } directory_initiate_command_trusted_dir(ds, purpose, payload, payload_len); @@ -154,13 +152,13 @@ directory_get_from_dirserver(uint8_t purpose, const char *payload, if (purpose == DIR_PURPOSE_FETCH_DIR) { if (advertised_server_mode()) { /* only ask authdirservers, and don't ask myself */ - ds = router_pick_trusteddirserver(1, options.FascistFirewall); + ds = router_pick_trusteddirserver(1, get_options()->FascistFirewall); } else { /* anybody with a non-zero dirport will do */ - r = router_pick_directory_server(1, options.FascistFirewall); + r = router_pick_directory_server(1, get_options()->FascistFirewall); if (!r) { log_fn(LOG_INFO, "No router found for directory; falling back to dirserver list"); - ds = router_pick_trusteddirserver(1, options.FascistFirewall); + ds = router_pick_trusteddirserver(1, get_options()->FascistFirewall); } } } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC) @@ -241,9 +239,9 @@ directory_initiate_command(const char *address, uint32_t addr, conn->addr = addr; conn->port = dir_port; - if(options.HttpProxy) { - addr = options.HttpProxyAddr; - dir_port = options.HttpProxyPort; + if(get_options()->HttpProxy) { + addr = get_options()->HttpProxyAddr; + dir_port = get_options()->HttpProxyPort; } conn->address = tor_strdup(address); @@ -327,7 +325,7 @@ directory_send_command(connection_t *conn, const char *platform, } else { tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",conn->address, conn->port); } - if(options.HttpProxy) { + if(get_options()->HttpProxy) { tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring); } else { proxystring[0] = 0; @@ -768,7 +766,7 @@ directory_handle_command_get(connection_t *conn, char *headers, if(!strcmp(url,"/tor/running-routers")) { /* running-routers fetch */ tor_free(url); - if(!authdir_mode()) { + if(!authdir_mode(get_options())) { /* XXX008 for now, we don't cache running-routers. Reject. */ connection_write_to_buf(answer400, strlen(answer400), conn); return 0; @@ -793,7 +791,7 @@ directory_handle_command_get(connection_t *conn, char *headers, const char *descp; size_t desc_len; - if(!authdir_mode()) { + if(!authdir_mode(get_options())) { /* We don't hand out rend descs. In fact, it could be a security * risk, since rend_cache_lookup_desc() below would provide it * if we're gone to the site recently, and 404 if we haven't. @@ -845,7 +843,7 @@ directory_handle_command_post(connection_t *conn, char *headers, conn->state = DIR_CONN_STATE_SERVER_WRITING; - if(!authdir_mode()) { + if(!authdir_mode(get_options())) { /* we just provide cached directories; we don't want to * receive anything. */ connection_write_to_buf(answer400, strlen(answer400), conn); diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 56c1446f1a..8e2836aab2 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -14,8 +14,6 @@ /** How many seconds do we wait before regenerating the directory? */ #define DIR_REGEN_SLACK_TIME 10 -extern or_options_t options; /**< command-line and config-file options */ - /** Do we need to regenerate the directory when someone asks for it? */ static int the_directory_is_dirty = 1; static int runningrouters_is_dirty = 1; @@ -87,19 +85,29 @@ dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk) int dirserv_parse_fingerprint_file(const char *fname) { - FILE *file; - char line[FINGERPRINT_LEN+MAX_NICKNAME_LEN+20+1]; + char *cf; char *nickname, *fingerprint; smartlist_t *fingerprint_list_new; int i, result; fingerprint_entry_t *ent; + struct config_line_t *front=NULL, *list; - if(!(file = fopen(fname, "r"))) { + cf = read_file_to_str(fname, 0); + if (!cf) { log_fn(LOG_WARN, "Cannot open fingerprint file %s", fname); return -1; } + result = config_get_lines(cf, &front); + tor_free(cf); + if (result < 0) { + log_fn(LOG_WARN, "Error reading from fingerprint file"); + return -1; + } + fingerprint_list_new = smartlist_create(); - while( (result=parse_line_from_file(line, sizeof(line),file,&nickname,&fingerprint)) > 0) { + + for(list=front; list; list=list->next) { + nickname = list->key; fingerprint = list->value; if (strlen(nickname) > MAX_NICKNAME_LEN) { log(LOG_WARN, "Nickname %s too long in fingerprint file. Skipping.", nickname); continue; @@ -125,24 +133,13 @@ dirserv_parse_fingerprint_file(const char *fname) smartlist_add(fingerprint_list_new, ent); } } - fclose(file); - if(result == 0) { /* eof; replace the global fingerprints list. */ - dirserv_free_fingerprint_list(); - fingerprint_list = fingerprint_list_new; - /* Delete any routers whose fingerprints we no longer recognize */ - directory_remove_unrecognized(); - return 0; - } - /* error */ - log_fn(LOG_WARN, "Error reading from fingerprint file"); - for (i = 0; i < smartlist_len(fingerprint_list_new); ++i) { - ent = smartlist_get(fingerprint_list_new, i); - tor_free(ent->nickname); - tor_free(ent->fingerprint); - tor_free(ent); - } - smartlist_free(fingerprint_list_new); - return -1; + + config_free_lines(front); + dirserv_free_fingerprint_list(); + fingerprint_list = fingerprint_list_new; + /* Delete any routers whose fingerprints we no longer recognize */ + directory_remove_unrecognized(); + return 0; } /** Check whether router has a nickname/identity key combination that @@ -607,7 +604,7 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen, smartlist_t *versions; struct config_line_t *ln; versions = smartlist_create(); - for (ln = options.RecommendedVersions; ln; ln = ln->next) { + for (ln = get_options()->RecommendedVersions; ln; ln = ln->next) { smartlist_split_string(versions, ln->value, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); } @@ -644,7 +641,7 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen, */ if (strlcat(s, "directory-signature ", maxlen) >= maxlen) goto truncated; - if (strlcat(s, options.Nickname, maxlen) >= maxlen) + if (strlcat(s, get_options()->Nickname, maxlen) >= maxlen) goto truncated; if (strlcat(s, "\n", maxlen) >= maxlen) goto truncated; @@ -694,7 +691,7 @@ void dirserv_set_cached_directory(const char *directory, time_t when) { time_t now; char filename[512]; - tor_assert(!options.AuthoritativeDir); + tor_assert(!get_options()->AuthoritativeDir); now = time(NULL); if (when<=cached_directory_published) { log_fn(LOG_INFO, "Ignoring old directory; not caching."); @@ -713,8 +710,8 @@ void dirserv_set_cached_directory(const char *directory, time_t when) log_fn(LOG_WARN,"Error compressing cached directory"); } cached_directory_published = when; - if(get_data_directory(&options)) { - tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory(&options)); + if(get_data_directory()) { + tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory()); if(write_str_to_file(filename,cached_directory,0) < 0) { log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring."); } @@ -726,7 +723,7 @@ void dirserv_set_cached_directory(const char *directory, time_t when) * directory, generating a new one as necessary. */ size_t dirserv_get_directory(const char **directory, int compress) { - if (!options.AuthoritativeDir) { + if (!get_options()->AuthoritativeDir) { if (compress?cached_directory_z:cached_directory) { *directory = compress?cached_directory_z:cached_directory; return compress?cached_directory_z_len:cached_directory_len; @@ -835,7 +832,7 @@ static int generate_runningrouters(crypto_pk_env_t *private_key) "opt dir-signing-key %s\n" "directory-signature %s\n" "-----BEGIN SIGNATURE-----\n", - published, router_status, identity_pkey, options.Nickname); + published, router_status, identity_pkey, get_options()->Nickname); tor_free(router_status); tor_free(identity_pkey); if (router_get_runningrouters_hash(s,digest)) { diff --git a/src/or/dns.c b/src/or/dns.c index 913cb38892..f6379ac169 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -15,8 +15,6 @@ #include "or.h" #include "tree.h" -extern or_options_t options; /* command-line and config-file options */ - /** Longest hostname we're willing to resolve. */ #define MAX_ADDRESSLEN 256 diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 76ee82bb3d..f4efd89f6a 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -30,8 +30,6 @@ hibernating, phase 2: #define SHUTDOWN_WAIT_LENGTH 30 /* seconds */ -extern or_options_t options; - static int hibernate_state = HIBERNATE_STATE_LIVE; static time_t hibernate_timeout = 0; @@ -97,12 +95,12 @@ start_of_accounting_period_containing(time_t now) /* Only months are supported. */ tm = gmtime(&now); /* If this is before the Nth, we want the Nth of last month. */ - if (tm->tm_mday < options.AccountingStart) { + if (tm->tm_mday < get_options()->AccountingStart) { decr_month(tm, 1); } /* Otherwise, the month and year are correct.*/ - tm->tm_mday = options.AccountingStart; + tm->tm_mday = get_options()->AccountingStart; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; @@ -146,7 +144,7 @@ static void update_expected_bandwidth(void) { uint64_t used; - uint32_t max_configured = (options.BandwidthRateBytes * 60); + uint32_t max_configured = (get_options()->BandwidthRateBytes * 60); if (n_seconds_active_in_interval < 1800) { expected_bandwidth_usage = max_configured; @@ -183,7 +181,7 @@ static INLINE int time_to_record_bandwidth_usage(time_t now) static time_t last_time_noted = 0; /* ???? Maybe only do this if accountingmaxkb is set ? - if (!options.AccountingMaxKB) + if (!get_options()->AccountingMaxKB) return 0; */ @@ -233,7 +231,7 @@ accounting_set_wakeup_time(void) crypto_digest_get_digest(d, digest, DIGEST_LEN); crypto_free_digest_env(d); - n_days_to_exhaust_bw = (options.AccountingMaxKB/expected_bandwidth_usage) + n_days_to_exhaust_bw = (get_options()->AccountingMaxKB/expected_bandwidth_usage) /(24*60); tm = gmtime(&interval_start_time); @@ -272,7 +270,7 @@ static int record_bandwidth_usage(time_t now) (unsigned long)n_seconds_active_in_interval, (unsigned long)expected_bandwidth_usage); tor_snprintf(fname, sizeof(fname), "%s/bw_accounting", - get_data_directory(&options)); + get_data_directory()); return write_str_to_file(fname, buf, 0); } @@ -288,7 +286,7 @@ static int read_bandwidth_usage(void) int ok; tor_snprintf(fname, sizeof(fname), "%s/bw_accounting", - get_data_directory(&options)); + get_data_directory()); if (!(s = read_file_to_str(fname, 0))) { return 0; } @@ -356,7 +354,7 @@ static int read_bandwidth_usage(void) static int hibernate_hard_limit_reached(void) { - uint64_t hard_limit = options.AccountingMaxKB<<10; + uint64_t hard_limit = get_options()->AccountingMaxKB<<10; if (!hard_limit) return 0; return n_bytes_read_in_interval >= hard_limit @@ -365,7 +363,7 @@ static int hibernate_hard_limit_reached(void) static int hibernate_soft_limit_reached(void) { - uint64_t soft_limit = (uint64_t) ((options.AccountingMaxKB<<10) * .99); + uint64_t soft_limit = (uint64_t) ((get_options()->AccountingMaxKB<<10) * .99); if (!soft_limit) return 0; return n_bytes_read_in_interval >= soft_limit diff --git a/src/or/main.c b/src/or/main.c index 6be906048d..ec1b66c4ef 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -16,7 +16,6 @@ static int init_from_config(int argc, char **argv); /********* START VARIABLES **********/ -or_options_t options; /**< Command-line and config-file options. */ int global_read_bucket; /**< Max number of bytes I can read this second. */ int global_write_bucket; /**< Max number of bytes I can write this second. */ @@ -84,7 +83,7 @@ int connection_add(connection_t *conn) { tor_assert(conn); tor_assert(conn->s >= 0); - if(nfds >= options.MaxConn-1) { + if(nfds >= get_options()->MaxConn-1) { log_fn(LOG_WARN,"failing because nfds is too high."); return -1; } @@ -355,6 +354,7 @@ static void conn_close_if_marked(int i) { /** This function is called whenever we successfully pull down a directory */ void directory_has_arrived(time_t now) { + or_options_t *options = get_options(); log_fn(LOG_INFO, "A directory has arrived."); @@ -363,9 +363,9 @@ void directory_has_arrived(time_t now) { * seconds after the directory we had when we started. */ if (!time_to_fetch_directory) - time_to_fetch_directory = now + options.DirFetchPostPeriod; + time_to_fetch_directory = now + options->DirFetchPostPeriod; - if (server_mode() && + if (server_mode(options) && !we_are_hibernating()) { /* connect to the appropriate routers */ router_retry_connections(); } @@ -378,6 +378,7 @@ void directory_has_arrived(time_t now) { static void run_connection_housekeeping(int i, time_t now) { cell_t cell; connection_t *conn = connection_array[i]; + or_options_t *options = get_options(); /* Expire any directory connections that haven't sent anything for 5 min */ if(conn->type == CONN_TYPE_DIR && @@ -391,12 +392,12 @@ static void run_connection_housekeeping(int i, time_t now) { /* If we haven't written to an OR connection for a while, then either nuke the connection or send a keepalive, depending. */ if(connection_speaks_cells(conn) && - now >= conn->timestamp_lastwritten + options.KeepalivePeriod) { + now >= conn->timestamp_lastwritten + options->KeepalivePeriod) { routerinfo_t *router = router_get_by_digest(conn->identity_digest); if((!connection_state_is_open(conn)) || (we_are_hibernating() && !circuit_get_by_conn(conn)) || - (!clique_mode() && !circuit_get_by_conn(conn) && - (!router || !server_mode() || !router_is_clique_mode(router)))) { + (!clique_mode(options) && !circuit_get_by_conn(conn) && + (!router || !server_mode(options) || !router_is_clique_mode(router)))) { /* our handshake has expired; we're hibernating; * or we have no circuits and we're both either OPs or normal ORs, * then kill it. */ @@ -430,17 +431,18 @@ static void run_connection_housekeeping(int i, time_t now) { */ static int decide_if_publishable_server(time_t now) { int bw; + or_options_t *options = get_options(); bw = rep_hist_bandwidth_assess(); router_set_bandwidth_capacity(bw); - if(options.ClientOnly) + if(options->ClientOnly) return 0; - if(!options.ORPort) + if(!options->ORPort) return 0; /* XXX008 for now, you're only a server if you're a server */ - return server_mode(); + return server_mode(options); /* here, determine if we're reachable */ if(0) { /* we've recently failed to reach our IP/ORPort from the outside */ @@ -449,7 +451,7 @@ static int decide_if_publishable_server(time_t now) { if(bw < MIN_BW_TO_PUBLISH_DESC) return 0; - if(options.AuthoritativeDir) + if(options->AuthoritativeDir) return 1; if(stats_n_seconds_uptime < MIN_UPTIME_TO_PUBLISH_DESC) return 0; @@ -460,20 +462,20 @@ static int decide_if_publishable_server(time_t now) { /** Return true iff we believe ourselves to be an authoritative * directory server. */ -int authdir_mode(void) { - return (options.AuthoritativeDir != 0); +int authdir_mode(or_options_t *options) { + return options->AuthoritativeDir != 0; } /** Return true iff we try to stay connected to all ORs at once. */ -int clique_mode(void) { - return authdir_mode(); +int clique_mode(or_options_t *options) { + return authdir_mode(options); } /** Return true iff we are trying to be a server. */ -int server_mode(void) { - return (options.ORPort != 0 || options.ORBindAddress); +int server_mode(or_options_t *options) { + return (options->ORPort != 0 || options->ORBindAddress); } /** Remember if we've advertised ourselves to the dirservers. */ @@ -486,8 +488,8 @@ int advertised_server_mode(void) { } /** Return true iff we are trying to be a socks proxy. */ -int proxy_mode(void) { - return (options.SocksPort != 0 || options.SocksBindAddress); +int proxy_mode(or_options_t *options) { + return (options->SocksPort != 0 || options->SocksBindAddress); } /** Perform regular maintenance tasks. This function gets run once per @@ -497,6 +499,7 @@ static void run_scheduled_events(time_t now) { static time_t last_uploaded_services = 0; static time_t last_rotated_certificate = 0; static time_t time_to_check_listeners = 0; + or_options_t *options = get_options(); int i; /** 0. See if we've been asked to shut down and our timeout has @@ -509,7 +512,8 @@ static void run_scheduled_events(time_t now) { * shut down and restart all cpuworkers, and update the directory if * necessary. */ - if (server_mode() && get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) { + if (server_mode(options) && + get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) { log_fn(LOG_INFO,"Rotating onion key."); rotate_onion_key(); cpuworkers_rotate(); @@ -525,7 +529,7 @@ static void run_scheduled_events(time_t now) { last_rotated_certificate = now; if (last_rotated_certificate+MAX_SSL_KEY_LIFETIME < now) { log_fn(LOG_INFO,"Rotating tls context."); - if (tor_tls_context_new(get_identity_key(), 1, options.Nickname, + if (tor_tls_context_new(get_identity_key(), 1, get_options()->Nickname, MAX_SSL_KEY_LIFETIME) < 0) { log_fn(LOG_WARN, "Error reinitializing TLS context"); } @@ -553,11 +557,11 @@ static void run_scheduled_events(time_t now) { /* purge obsolete entries */ routerlist_remove_old_routers(ROUTER_MAX_AGE); - if(authdir_mode()) { + if(authdir_mode(options)) { /* We're a directory; dump any old descriptors. */ dirserv_remove_old_servers(ROUTER_MAX_AGE); } - if(server_mode() && !we_are_hibernating()) { + if(server_mode(options) && !we_are_hibernating()) { /* dirservers try to reconnect, in case connections have failed; * and normal servers try to reconnect to dirservers */ router_retry_connections(); @@ -572,7 +576,7 @@ static void run_scheduled_events(time_t now) { } rend_cache_clean(); /* should this go elsewhere? */ - time_to_fetch_directory = now + options.DirFetchPostPeriod; + time_to_fetch_directory = now + get_options()->DirFetchPostPeriod; } /** 3a. Every second, we examine pending circuits and prune the @@ -685,34 +689,38 @@ static int prepare_for_poll(void) { * configuration file. */ static int init_from_config(int argc, char **argv) { - /* read the configuration file. */ - if(getconfig(argc,argv,&options)) { + or_options_t *options; + + /* read the configuration file. init and assign options. */ + if(getconfig(argc,argv) < 0) { log_fn(LOG_ERR,"Reading config failed--see warnings above. For usage, try -h."); return -1; } + options = get_options(); + /* Setuid/setgid as appropriate */ - if(options.User || options.Group) { - if(switch_id(options.User, options.Group) != 0) { + if(options->User || options->Group) { + if(switch_id(options->User, options->Group) != 0) { return -1; } } /* Ensure data directory is private; create if possible. */ - if (get_data_directory(&options) && - check_private_dir(get_data_directory(&options), 1) != 0) { + if (get_data_directory() && + check_private_dir(get_data_directory(), 1) != 0) { log_fn(LOG_ERR, "Couldn't access/create private data directory %s", - get_data_directory(&options)); + get_data_directory()); return -1; } /* Bail out at this point if we're not going to be a server: we want * to not fork, and to log stuff to stderr. */ - if (options.command != CMD_RUN_TOR) + if (options->command != CMD_RUN_TOR) return 0; /* Configure the log(s) */ - if (config_init_logs(&options)<0) + if (config_init_logs(options)<0) return -1; /* Close the temporary log we used while starting up, if it isn't already * gone. */ @@ -720,8 +728,8 @@ static int init_from_config(int argc, char **argv) { add_callback_log(LOG_WARN, LOG_ERR, control_event_logmsg); /* Start backgrounding the process, if requested. */ - if (options.RunAsDaemon) { - start_daemon(get_data_directory(&options)); + if (options->RunAsDaemon) { + start_daemon(get_data_directory()); } /* Set up our buckets */ @@ -730,15 +738,15 @@ static int init_from_config(int argc, char **argv) { stats_prev_global_write_bucket = global_write_bucket; /* Finish backgrounding the process */ - if(options.RunAsDaemon) { + if(options->RunAsDaemon) { /* XXXX Can we delay this any more? */ finish_daemon(); } /* Write our pid to the pid file. If we do not have write permissions we * will log a warning */ - if(options.PidFile) - write_pidfile(options.PidFile); + if(options->PidFile) + write_pidfile(options->PidFile); return 0; } @@ -765,9 +773,9 @@ static int do_hup(void) { log_fn(LOG_ERR,"Failed to bind one of the listener ports."); return -1; } - if(authdir_mode()) { + if(authdir_mode(get_options())) { /* reload the approved-routers file */ - tor_snprintf(keydir,sizeof(keydir),"%s/approved-routers", get_data_directory(&options)); + tor_snprintf(keydir,sizeof(keydir),"%s/approved-routers", get_data_directory()); log_fn(LOG_INFO,"Reloading approved fingerprints from %s...",keydir); if(dirserv_parse_fingerprint_file(keydir) < 0) { log_fn(LOG_WARN, "Error reloading fingerprints. Continuing with old list."); @@ -775,14 +783,14 @@ static int do_hup(void) { } /* Fetch a new directory. Even authdirservers do this. */ directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0); - if(server_mode()) { + if(server_mode(get_options())) { /* Restart cpuworker and dnsworker processes, so they get up-to-date * configuration options. */ cpuworkers_rotate(); dnsworkers_rotate(); /* Rebuild fresh descriptor as needed. */ router_rebuild_descriptor(); - tor_snprintf(keydir,sizeof(keydir),"%s/router.desc", get_data_directory(&options)); + tor_snprintf(keydir,sizeof(keydir),"%s/router.desc", get_data_directory()); log_fn(LOG_INFO,"Dumping descriptor to %s...",keydir); if (write_str_to_file(keydir, router_get_my_descriptor(), 0)) { return -1; @@ -817,12 +825,12 @@ static int do_main_loop(void) { return -1; } - if(authdir_mode()) { + if(authdir_mode(get_options())) { /* the directory is already here, run startup things */ router_retry_connections(); } - if(server_mode()) { + if(server_mode(get_options())) { /* launch cpuworkers. Need to do this *after* we've read the onion key. */ cpu_init(); } @@ -841,7 +849,7 @@ static int do_main_loop(void) { #endif #ifndef MS_WINDOWS /* do signal stuff only on unix */ if(please_shutdown) { - if(!server_mode()) { /* do it now */ + if(!server_mode(get_options())) { /* do it now */ log(LOG_NOTICE,"Interrupt: exiting cleanly."); tor_cleanup(); exit(0); @@ -1074,16 +1082,16 @@ static int tor_init(int argc, char *argv[]) { log_fn(LOG_WARN,"You are running Tor as root. You don't need to, and you probably shouldn't."); #endif - if(server_mode()) { /* only spawn dns handlers if we're a router */ + if(server_mode(get_options())) { /* only spawn dns handlers if we're a router */ dns_init(); /* initialize the dns resolve tree, and spawn workers */ } - if(proxy_mode()) { + if(proxy_mode(get_options())) { client_dns_init(); /* init the client dns cache */ } handle_signals(1); - if (set_max_file_descriptors(options.MaxConn) < 0) + if (set_max_file_descriptors(get_options()->MaxConn) < 0) return -1; crypto_global_init(); @@ -1093,10 +1101,11 @@ static int tor_init(int argc, char *argv[]) { /** Do whatever cleanup is necessary before shutting Tor down. */ void tor_cleanup(void) { + or_options_t *options = get_options(); /* Remove our pid file. We don't care if there was an error when we * unlink, nothing we could do about it anyways. */ - if(options.PidFile && options.command == CMD_RUN_TOR) - unlink(options.PidFile); + if(options->PidFile && options->command == CMD_RUN_TOR) + unlink(options->PidFile); crypto_global_cleanup(); } @@ -1117,8 +1126,7 @@ static void do_list_fingerprint(void) log_fn(LOG_ERR, "Error computing fingerprint"); return; } - /*XXX is options.Nickname for-sure defined yet here? */ - printf("%s %s\n", options.Nickname, buf); + printf("%s %s\n", get_options()->Nickname, buf); } /** DOCDOC **/ @@ -1131,7 +1139,7 @@ static void do_hash_password(void) crypto_rand(key, S2K_SPECIFIER_LEN-1); key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */ secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN, - options.command_arg, strlen(options.command_arg), + get_options()->command_arg, strlen(get_options()->command_arg), key); if (base64_encode(output, sizeof(output), key, sizeof(key))<0) { log_fn(LOG_ERR, "Unable to compute base64"); @@ -1209,7 +1217,7 @@ int tor_main(int argc, char *argv[]) { #else if (tor_init(argc, argv)<0) return -1; - switch (options.command) { + switch (get_options()->command) { case CMD_RUN_TOR: do_main_loop(); break; @@ -1221,7 +1229,7 @@ int tor_main(int argc, char *argv[]) { break; default: log_fn(LOG_ERR, "Illegal command number %d: internal error.", - options.command); + get_options()->command); } tor_cleanup(); return -1; diff --git a/src/or/onion.c b/src/or/onion.c index c5431e0fdc..9def03cd27 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -10,8 +10,6 @@ #include "or.h" -extern or_options_t options; /**< command-line and config-file options */ - struct onion_queue_t { circuit_t *circ; struct onion_queue_t *next; @@ -44,7 +42,7 @@ int onion_pending_add(circuit_t *circ) { tor_assert(ol_list); tor_assert(!ol_tail->next); - if(ol_length >= options.MaxOnionsPending) { + if(ol_length >= get_options()->MaxOnionsPending) { log_fn(LOG_WARN,"Already have %d onions queued. Closing.", ol_length); tor_free(tmp); return -1; diff --git a/src/or/or.h b/src/or/or.h index ae6620c467..35fb477c47 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1089,14 +1089,20 @@ struct config_line_t { struct config_line_t *next; }; -int config_assign_default_dirservers(void); +or_options_t *get_options(void); +void set_options(or_options_t *new); + +int config_get_lines(char *string, struct config_line_t **result); +void config_free_lines(struct config_line_t *front); +int config_trial_assign(or_options_t **options, struct config_line_t *list, int reset); int resolve_my_address(const char *address, uint32_t *addr); -int getconfig(int argc, char **argv, or_options_t *options); +void options_init(or_options_t *options); +int getconfig(int argc, char **argv); int config_init_logs(or_options_t *options); void config_parse_exit_policy(struct config_line_t *cfg, struct exit_policy_t **dest); void exit_policy_free(struct exit_policy_t *p); -const char *get_data_directory(or_options_t *options); +const char *get_data_directory(void); struct config_line_t *config_get_assigned_option(or_options_t *options, const char *key); struct config_line_t *config_line_prepend(struct config_line_t *front, @@ -1330,11 +1336,11 @@ void connection_stop_writing(connection_t *conn); void connection_start_writing(connection_t *conn); void directory_has_arrived(time_t now); -int authdir_mode(void); -int clique_mode(void); -int server_mode(void); +int authdir_mode(or_options_t *options); +int clique_mode(or_options_t *options); +int server_mode(or_options_t *options); int advertised_server_mode(void); -int proxy_mode(void); +int proxy_mode(or_options_t *options); void handle_signals(int is_parent); void tor_cleanup(void); diff --git a/src/or/relay.c b/src/or/relay.c index 2c256548c1..73c5db0f5d 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -10,8 +10,6 @@ #include "or.h" -extern or_options_t options; /* command-line and config-file options */ - static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction, crypt_path_t **layer_hint, char *recognized); static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction); @@ -546,7 +544,7 @@ connection_edge_process_relay_cell_not_open( conn->state = AP_CONN_STATE_CIRCUIT_WAIT; circuit_detach_stream(circ,conn); tor_assert(circ->timestamp_dirty); - circ->timestamp_dirty -= options.NewCircuitPeriod; + circ->timestamp_dirty -= get_options()->NewCircuitPeriod; /* make sure not to expire/retry the stream quite yet */ conn->timestamp_lastread = time(NULL); if(connection_ap_handshake_attach_circuit(conn) >= 0) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index b056679d6c..88a2e64456 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -9,8 +9,6 @@ #include "or.h" -extern or_options_t options; /* command-line and config-file options */ - static circuit_t *find_intro_circuit(routerinfo_t *router, const char *pk_digest); /** Represents the mapping from a virtual port of a rendezvous service to @@ -846,7 +844,7 @@ void rend_services_introduce(void) { for (j=prev_intro_nodes; j < NUM_INTRO_POINTS; ++j) { router = router_choose_random_node(service->intro_prefer_nodes, service->intro_exclude_nodes, exclude_routers, 1, 0, - options._AllowUnverified & ALLOW_UNVERIFIED_INTRODUCTION, 0); + get_options()->_AllowUnverified & ALLOW_UNVERIFIED_INTRODUCTION, 0); if (!router) { log_fn(LOG_WARN, "Could only establish %d introduction points for %s", smartlist_len(service->intro_nodes), service->service_id); diff --git a/src/or/router.c b/src/or/router.c index b8fd748f22..f7e3eec4c4 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -10,7 +10,6 @@ * and uploading server descriptors, retrying OR connections. **/ -extern or_options_t options; /* command-line and config-file options */ extern long stats_n_seconds_uptime; /** Exposed for test.c. */ void get_platform_str(char *platform, size_t len); @@ -102,9 +101,9 @@ void rotate_onion_key(void) char fname_prev[512]; crypto_pk_env_t *prkey; tor_snprintf(fname,sizeof(fname), - "%s/keys/secret_onion_key",get_data_directory(&options)); + "%s/keys/secret_onion_key",get_data_directory()); tor_snprintf(fname_prev,sizeof(fname_prev), - "%s/keys/secret_onion_key.old",get_data_directory(&options)); + "%s/keys/secret_onion_key.old",get_data_directory()); if (!(prkey = crypto_new_pk_env())) { log(LOG_ERR, "Error creating crypto environment."); goto error; @@ -231,13 +230,14 @@ int init_keys(void) { const char *tmp, *mydesc, *datadir; crypto_pk_env_t *prkey; char digest[20]; + or_options_t *options = get_options(); if (!key_lock) key_lock = tor_mutex_new(); /* OP's don't need persistant keys; just make up an identity and * initialize the TLS context. */ - if (!server_mode()) { + if (!server_mode(options)) { if (!(prkey = crypto_new_pk_env())) return -1; if (crypto_pk_generate_key(prkey)) @@ -245,8 +245,8 @@ int init_keys(void) { set_identity_key(prkey); /* XXX NM: do we have a convention for what client's Nickname is? * No. Let me propose one: */ - if (tor_tls_context_new(get_identity_key(), 1, - options.Nickname ? options.Nickname : "client", + if (tor_tls_context_new(get_identity_key(), 1, + options->Nickname ? options->Nickname : "client", MAX_SSL_KEY_LIFETIME) < 0) { log_fn(LOG_ERR, "Error creating TLS context for OP."); return -1; @@ -254,7 +254,7 @@ int init_keys(void) { return 0; } /* Make sure DataDirectory exists, and is private. */ - datadir = get_data_directory(&options); + datadir = get_data_directory(); tor_assert(datadir); if (strlen(datadir) > (512-128)) { log_fn(LOG_ERR, "DataDirectory is too long."); @@ -292,7 +292,7 @@ int init_keys(void) { } /* 3. Initialize link key and TLS context. */ - if (tor_tls_context_new(get_identity_key(), 1, options.Nickname, + if (tor_tls_context_new(get_identity_key(), 1, options->Nickname, MAX_SSL_KEY_LIFETIME) < 0) { log_fn(LOG_ERR, "Error initializing TLS context"); return -1; @@ -304,9 +304,9 @@ int init_keys(void) { log_fn(LOG_ERR, "Error initializing descriptor."); return -1; } - if(authdir_mode()) { + if(authdir_mode(options)) { /* We need to add our own fingerprint so it gets recognized. */ - if (dirserv_add_own_fingerprint(options.Nickname, get_identity_key())) { + if (dirserv_add_own_fingerprint(options->Nickname, get_identity_key())) { log_fn(LOG_ERR, "Error adding own fingerprint to approved set"); return -1; } @@ -324,8 +324,8 @@ int init_keys(void) { /* 5. Dump fingerprint to 'fingerprint' */ tor_snprintf(keydir,sizeof(keydir),"%s/fingerprint", datadir); log_fn(LOG_INFO,"Dumping fingerprint to %s...",keydir); - tor_assert(strlen(options.Nickname) <= MAX_NICKNAME_LEN); - strlcpy(fingerprint, options.Nickname, sizeof(fingerprint)); + tor_assert(strlen(options->Nickname) <= MAX_NICKNAME_LEN); + strlcpy(fingerprint, options->Nickname, sizeof(fingerprint)); strlcat(fingerprint, " ", sizeof(fingerprint)); if (crypto_pk_get_fingerprint(get_identity_key(), fingerprint+strlen(fingerprint), 1)<0) { @@ -335,7 +335,7 @@ int init_keys(void) { strlcat(fingerprint, "\n", sizeof(fingerprint)); if (write_str_to_file(keydir, fingerprint, 0)) return -1; - if(!authdir_mode()) + if(!authdir_mode(options)) return 0; /* 6. [authdirserver only] load approved-routers file */ tor_snprintf(keydir,sizeof(keydir),"%s/approved-routers", datadir); @@ -347,7 +347,7 @@ int init_keys(void) { /* 6b. [authdirserver only] add own key to approved directories. */ crypto_pk_get_digest(get_identity_key(), digest); if (!router_digest_is_trusted_dir(digest)) { - add_trusted_dir_server(options.Address, (uint16_t)options.DirPort, digest); + add_trusted_dir_server(options->Address, (uint16_t)options->DirPort, digest); } /* 7. [authdirserver only] load old directory, if it's there */ tor_snprintf(keydir,sizeof(keydir),"%s/cached-directory", datadir); @@ -380,8 +380,9 @@ void router_retry_connections(void) { int i; routerinfo_t *router; routerlist_t *rl; + or_options_t *options = get_options(); - tor_assert(server_mode()); + tor_assert(server_mode(options)); router_get_routerlist(&rl); if (!rl) return; @@ -389,7 +390,7 @@ void router_retry_connections(void) { router = smartlist_get(rl->routers, i); if(router_is_me(router)) continue; - if(!clique_mode() && !router_is_clique_mode(router)) + if(!clique_mode(options) && !router_is_clique_mode(router)) continue; if(!connection_get_by_identity_digest(router->identity_digest, CONN_TYPE_OR)) { @@ -438,7 +439,7 @@ void router_upload_dir_desc_to_dirservers(void) { static void router_add_exit_policy_from_config(routerinfo_t *router) { struct exit_policy_t *ep; struct config_line_t default_policy; - config_parse_exit_policy(options.ExitPolicy, &router->exit_policy); + config_parse_exit_policy(get_options()->ExitPolicy, &router->exit_policy); for (ep = router->exit_policy; ep; ep = ep->next) { if (ep->msk == 0 && ep->prt_min <= 1 && ep->prt_max >= 65535) { @@ -487,7 +488,7 @@ int router_is_me(routerinfo_t *router) * necessary. Return NULL on error, or if called on an OP. */ routerinfo_t *router_get_my_routerinfo(void) { - if (!server_mode()) + if (!server_mode(get_options())) return NULL; if (!desc_routerinfo) { @@ -517,20 +518,21 @@ int router_rebuild_descriptor(void) { uint32_t addr; char platform[256]; struct in_addr in; + or_options_t *options = get_options(); - if(resolve_my_address(options.Address, &addr) < 0) { - log_fn(LOG_WARN,"options.Address didn't resolve into an IP."); + if(resolve_my_address(options->Address, &addr) < 0) { + log_fn(LOG_WARN,"options->Address didn't resolve into an IP."); return -1; } ri = tor_malloc_zero(sizeof(routerinfo_t)); in.s_addr = htonl(addr); ri->address = tor_strdup(inet_ntoa(in)); - ri->nickname = tor_strdup(options.Nickname); + ri->nickname = tor_strdup(options->Nickname); ri->addr = addr; - ri->or_port = options.ORPort; - ri->socks_port = options.SocksPort; - ri->dir_port = options.DirPort; + ri->or_port = options->ORPort; + ri->socks_port = options->SocksPort; + ri->dir_port = options->DirPort; ri->published_on = time(NULL); ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from main thread */ ri->identity_pkey = crypto_pk_dup_key(get_identity_key()); @@ -540,15 +542,15 @@ int router_rebuild_descriptor(void) { } get_platform_str(platform, sizeof(platform)); ri->platform = tor_strdup(platform); - ri->bandwidthrate = options.BandwidthRateBytes; - ri->bandwidthburst = options.BandwidthBurstBytes; + ri->bandwidthrate = options->BandwidthRateBytes; + ri->bandwidthburst = options->BandwidthBurstBytes; ri->bandwidthcapacity = router_get_bandwidth_capacity(); router_add_exit_policy_from_config(ri); if(desc_routerinfo) /* inherit values */ ri->is_verified = desc_routerinfo->is_verified; - if (options.MyFamily) { + if (options->MyFamily) { ri->declared_family = smartlist_create(); - smartlist_split_string(ri->declared_family, options.MyFamily, ",", + smartlist_split_string(ri->declared_family, options->MyFamily, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); } @@ -686,9 +688,9 @@ int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, /* From now on, we use 'written' to remember the current length of 's'. */ written = result; - if (options.ContactInfo && strlen(options.ContactInfo)) { + if (get_options()->ContactInfo && strlen(get_options()->ContactInfo)) { result = tor_snprintf(s+written,maxlen-written, "opt contact %s\n", - options.ContactInfo); + get_options()->ContactInfo); if (result<0 || result+written > maxlen) return -1; written += result; diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 2ed8d1b6a8..ffdeb65f65 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -14,10 +14,6 @@ /****************************************************************************/ -extern or_options_t options; /**< command-line and config-file options */ - -/* ********************************************************************** */ - static smartlist_t *trusted_dir_servers = NULL; /* static function prototypes */ @@ -50,9 +46,9 @@ int router_reload_router_list(void) char filename[512]; int is_recent; struct stat st; - if (get_data_directory(&options)) { + if (get_data_directory()) { char *s; - tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory(&options)); + tor_snprintf(filename,sizeof(filename),"%s/cached-directory", get_data_directory()); if (stat(filename, &st)) { log_fn(LOG_WARN, "Unable to check status for '%s': %s", filename, strerror(errno)); @@ -114,7 +110,7 @@ routerinfo_t *router_pick_directory_server(int requireothers, return choice; log_fn(LOG_INFO,"Still no %s router entries. Reloading and trying again.", - options.FascistFirewall ? "reachable" : "known"); + get_options()->FascistFirewall ? "reachable" : "known"); has_fetched_directory=0; /* reset it */ if(router_reload_router_list()) { return NULL; @@ -141,7 +137,7 @@ trusted_dir_server_t *router_pick_trusteddirserver(int requireothers, return choice; log_fn(LOG_WARN,"Still no dirservers %s. Reloading and trying again.", - options.FascistFirewall ? "reachable" : "known"); + get_options()->FascistFirewall ? "reachable" : "known"); has_fetched_directory=0; /* reset it */ if(router_reload_router_list()) { return NULL; @@ -165,7 +161,7 @@ router_pick_directory_server_impl(int requireothers, int fascistfirewall) if(!routerlist) return NULL; - if(options.HttpProxy) + if(get_options()->HttpProxy) fascistfirewall = 0; /* Find all the running dirservers we know about. */ @@ -178,7 +174,7 @@ router_pick_directory_server_impl(int requireothers, int fascistfirewall) continue; if(fascistfirewall) { tor_snprintf(buf,sizeof(buf),"%d",router->dir_port); - if (!smartlist_string_isin(options.FirewallPorts, buf)) + if (!smartlist_string_isin(get_options()->FirewallPorts, buf)) continue; } smartlist_add(sl, router); @@ -202,7 +198,7 @@ router_pick_trusteddirserver_impl(int requireother, int fascistfirewall) if (!trusted_dir_servers) return NULL; - if(options.HttpProxy) + if(get_options()->HttpProxy) fascistfirewall = 0; SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d, @@ -213,7 +209,7 @@ router_pick_trusteddirserver_impl(int requireother, int fascistfirewall) continue; if (fascistfirewall) { tor_snprintf(buf,sizeof(buf),"%d",d->dir_port); - if (!smartlist_string_isin(options.FirewallPorts, buf)) + if (!smartlist_string_isin(get_options()->FirewallPorts, buf)) continue; } smartlist_add(sl, d); @@ -276,7 +272,7 @@ void routerlist_add_family(smartlist_t *sl, routerinfo_t *router) { }); - for (cl = options.NodeFamilies; cl; cl = cl->next) { + for (cl = get_options()->NodeFamilies; cl; cl = cl->next) { if (router_nickname_is_in_list(router, cl->value)) { add_nickname_list_to_smartlist(sl, cl->value, 0); } @@ -867,7 +863,7 @@ int router_load_routerlist_from_directory(const char *s, log_fn(LOG_WARN, "Error resolving routerlist"); return -1; } - if (options.AuthoritativeDir) { + if (get_options()->AuthoritativeDir) { /* Learn about the descriptors in the directory. */ dirserv_load_from_directory_string(s); } diff --git a/src/or/routerparse.c b/src/or/routerparse.c index eb02167660..2b99c72a74 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -12,8 +12,6 @@ /****************************************************************************/ -extern or_options_t options; /* command-line and config-file options */ - /** Enumeration of possible token types. The ones starting with K_ * correspond to directory 'keywords'. _UNRECOGNIZED is for an * unrecognized keyword; _ERR is an error in the tokenizing process, @@ -351,7 +349,7 @@ router_parse_routerlist_from_directory(const char *str, /* Now that we know the signature is okay, check the version. */ if (check_version) - check_software_version_against_directory(str, options.IgnoreVersion); + check_software_version_against_directory(str, get_options()->IgnoreVersion); /* Now try to parse the first part of the directory. */ if ((end = strstr(str,"\nrouter "))) { diff --git a/src/or/test.c b/src/or/test.c index f1d1d6545f..f627307e11 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -16,8 +16,6 @@ #include "../common/test.h" #include "../common/torgzip.h" -extern or_options_t options; - int have_failed = 0; /* These functions are file-local, but are exposed so we can test. */ @@ -1094,7 +1092,7 @@ test_dir_format(void) test_assert(router_dump_router_to_string(buf, 2048, &r2, pk1)>0); cp = buf; test_eq(dirserv_add_descriptor((const char**)&cp), 1); - options.Nickname = tor_strdup("DirServer"); + get_options()->Nickname = tor_strdup("DirServer"); test_assert(!dirserv_dump_directory_to_string(buf,8192,pk3)); cp = buf; test_assert(!router_parse_routerlist_from_directory(buf, &dir1, pk3, 1)); @@ -1202,12 +1200,9 @@ test_rend_fns(void) int main(int c, char**v){ -#if 0 - or_options_t options; /* command-line and config-file options */ - - if(getconfig(c,v,&options)) - exit(1); -#endif + or_options_t *options = tor_malloc_zero(sizeof(or_options_t)); + options_init(options); + set_options(options); crypto_seed_rng(); setup_directory();