From 192be006919c0bef04b7fce9e53c88ec1fcf4219 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 15:54:36 -0500 Subject: [PATCH 01/11] Make the DataDirectory option immutable. By convention, the torrc options that the user sets are unchangeable. If we need to change them, we should be using a copy that's stored in another field To avoid trouble, I'm keeping DataDirectory as the name for the field that the rest of Tor uses, and using DataDirectory_option for the confparse-controlled field. This commit also modernizes some older string handling code in the DataDirectory normalization function. --- src/or/config.c | 41 ++++++++++++++++++++--------------------- src/or/or.h | 4 +++- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index b0a140d23b..ad5c3143f3 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -286,7 +286,7 @@ static config_var_t option_vars_[] = { V(CookieAuthFileGroupReadable, BOOL, "0"), V(CookieAuthFile, STRING, NULL), V(CountPrivateBandwidth, BOOL, "0"), - V(DataDirectory, FILENAME, NULL), + VAR("DataDirectory", FILENAME, DataDirectory_option, NULL), V(DataDirectoryGroupReadable, BOOL, "0"), V(DisableOOSCheck, BOOL, "1"), V(DisableNetwork, BOOL, "0"), @@ -941,6 +941,7 @@ or_options_free(or_options_t *options) SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, tor_free(f)); smartlist_free(options->FilesOpenedByIncludes); } + tor_free(options->DataDirectory); tor_free(options->BridgePassword_AuthDigest_); tor_free(options->command_arg); tor_free(options->master_key_fname); @@ -7682,31 +7683,29 @@ port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h, check_wildcard); } -/** Adjust the value of options->DataDirectory, or fill it in if it's - * absent. Return 0 on success, -1 on failure. */ -static int -normalize_data_directory(or_options_t *options) +/** Allocate and return a good value for the DataDirectory based on + * val, which may be NULL. Return NULL on failure. */ +static char * +get_data_directory(const char *val) { #ifdef _WIN32 - char *p; - if (options->DataDirectory) - return 0; /* all set */ - p = tor_malloc(MAX_PATH); - strlcpy(p,get_windows_conf_root(),MAX_PATH); - options->DataDirectory = p; - return 0; + if (val) { + return tor_strdup(val); + } else { + return tor_strdup(get_windows_conf_root()); + } #else /* !(defined(_WIN32)) */ - const char *d = options->DataDirectory; + const char *d = val; if (!d) d = "~/.tor"; - if (strncmp(d,"~/",2) == 0) { + if (!strcmpstart(d, "~/")) { char *fn = expand_filename(d); if (!fn) { log_warn(LD_CONFIG,"Failed to expand filename \"%s\".", d); - return -1; + return NULL; } - if (!options->DataDirectory && !strcmp(fn,"/.tor")) { + if (!val && !strcmp(fn,"/.tor")) { /* If our homedir is /, we probably don't want to use it. */ /* Default to LOCALSTATEDIR/tor which is probably closer to what we * want. */ @@ -7717,10 +7716,9 @@ normalize_data_directory(or_options_t *options) tor_free(fn); fn = tor_strdup(LOCALSTATEDIR PATH_SEPARATOR "tor"); } - tor_free(options->DataDirectory); - options->DataDirectory = fn; + return fn; } - return 0; + return tor_strdup(d); #endif /* defined(_WIN32) */ } @@ -7729,9 +7727,10 @@ normalize_data_directory(or_options_t *options) static int validate_data_directory(or_options_t *options) { - if (normalize_data_directory(options) < 0) + tor_free(options->DataDirectory); + options->DataDirectory = get_data_directory(options->DataDirectory_option); + if (!options->DataDirectory) return -1; - tor_assert(options->DataDirectory); if (strlen(options->DataDirectory) > (512-128)) { log_warn(LD_CONFIG, "DataDirectory is too long."); return -1; diff --git a/src/or/or.h b/src/or/or.h index fa5268ac59..61e8d0b445 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3641,7 +3641,9 @@ typedef struct { char *SyslogIdentityTag; /**< Identity tag to add for syslog logging. */ char *DebugLogFile; /**< Where to send verbose log messages. */ - char *DataDirectory; /**< OR only: where to store long-term data. */ + char *DataDirectory_option; /**< Where to store long-term data, as + * configured by the user. */ + char *DataDirectory; /**< Where to store long-term data, as modified. */ int DataDirectoryGroupReadable; /**< Boolean: Is the DataDirectory g+r? */ char *Nickname; /**< OR only: nickname of this onion router. */ char *Address; /**< OR only: configured address for this onion router. */ From 6aeabd454e67a370d9b5793a488bdf6d83c61ec7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 15:56:25 -0500 Subject: [PATCH 02/11] Reindent the body of get_data_directory() I don't know why it wasn't indented properly, but we may as well fix it now. --- src/or/config.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index ad5c3143f3..0cbf2954ff 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -7700,25 +7700,25 @@ get_data_directory(const char *val) d = "~/.tor"; if (!strcmpstart(d, "~/")) { - char *fn = expand_filename(d); - if (!fn) { - log_warn(LD_CONFIG,"Failed to expand filename \"%s\".", d); - return NULL; - } - if (!val && !strcmp(fn,"/.tor")) { - /* If our homedir is /, we probably don't want to use it. */ - /* Default to LOCALSTATEDIR/tor which is probably closer to what we - * want. */ - log_warn(LD_CONFIG, - "Default DataDirectory is \"~/.tor\". This expands to " - "\"%s\", which is probably not what you want. Using " - "\"%s"PATH_SEPARATOR"tor\" instead", fn, LOCALSTATEDIR); - tor_free(fn); - fn = tor_strdup(LOCALSTATEDIR PATH_SEPARATOR "tor"); - } - return fn; - } - return tor_strdup(d); + char *fn = expand_filename(d); + if (!fn) { + log_warn(LD_CONFIG,"Failed to expand filename \"%s\".", d); + return NULL; + } + if (!val && !strcmp(fn,"/.tor")) { + /* If our homedir is /, we probably don't want to use it. */ + /* Default to LOCALSTATEDIR/tor which is probably closer to what we + * want. */ + log_warn(LD_CONFIG, + "Default DataDirectory is \"~/.tor\". This expands to " + "\"%s\", which is probably not what you want. Using " + "\"%s"PATH_SEPARATOR"tor\" instead", fn, LOCALSTATEDIR); + tor_free(fn); + fn = tor_strdup(LOCALSTATEDIR PATH_SEPARATOR "tor"); + } + return fn; + } + return tor_strdup(d); #endif /* defined(_WIN32) */ } From 36779df4c4617f3116faaee2aa5079537eed0822 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 16:03:25 -0500 Subject: [PATCH 03/11] Extract the code that creates the datadir into a separate function. --- src/or/config.c | 68 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index 0cbf2954ff..f024764f8a 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1250,6 +1250,45 @@ consider_adding_dir_servers(const or_options_t *options, return 0; } +/** + * Make sure that directory exists, with appropriate ownership and + * permissions (as modified by group_readable). If create, + * create the directory if it is missing. Return 0 on success. + * On failure, return -1 and set *msg_out. + */ +static int +check_and_create_data_directory(int create, + const char *directory, + int group_readable, + const char *owner, + char **msg_out) +{ + cpd_check_t cpd_opts = create ? CPD_CREATE : CPD_CHECK; + if (group_readable) + cpd_opts |= CPD_GROUP_READ; + if (check_private_dir(directory, + cpd_opts, + owner) < 0) { + tor_asprintf(msg_out, + "Couldn't %s private data directory \"%s\"", + create ? "create" : "access", + directory); + return -1; + } + +#ifndef _WIN32 + if (group_readable) { + /* Only new dirs created get new opts, also enforce group read. */ + if (chmod(directory, 0750)) { + log_warn(LD_FS,"Unable to make %s group-readable: %s", + directory, strerror(errno)); + } + } +#endif /* !defined(_WIN32) */ + + return 0; +} + /* Helps determine flags to pass to switch_id. */ static int have_low_ports = -1; @@ -1404,30 +1443,17 @@ options_act_reversible(const or_options_t *old_options, char **msg) } /* Ensure data directory is private; create if possible. */ - cpd_check_t cpd_opts = running_tor ? CPD_CREATE : CPD_CHECK; - if (options->DataDirectoryGroupReadable) - cpd_opts |= CPD_GROUP_READ; - if (check_private_dir(options->DataDirectory, - cpd_opts, - options->User)<0) { - tor_asprintf(msg, - "Couldn't access/create private data directory \"%s\"", - options->DataDirectory); - + /* It's okay to do this in "options_act_reversible()" even though it isn't + * actually reversible, since you can't change the DataDirectory while + * Tor is running. */ + if (check_and_create_data_directory(running_tor /* create */, + options->DataDirectory, + options->DataDirectoryGroupReadable, + options->User, + msg) < 0) { goto done; - /* No need to roll back, since you can't change the value. */ } -#ifndef _WIN32 - if (options->DataDirectoryGroupReadable) { - /* Only new dirs created get new opts, also enforce group read. */ - if (chmod(options->DataDirectory, 0750)) { - log_warn(LD_FS,"Unable to make %s group-readable: %s", - options->DataDirectory, strerror(errno)); - } - } -#endif /* !defined(_WIN32) */ - /* Bail out at this point if we're not going to be a client or server: * we don't run Tor itself. */ if (!running_tor) From 2e872f6b32edaace096180c249934c620cd3ce35 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 16:10:12 -0500 Subject: [PATCH 04/11] Use get_datadir_fname() accessor in networkstatus.c --- src/or/networkstatus.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index a7aa01f787..ff32476685 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -2260,7 +2260,6 @@ void networkstatus_dump_bridge_status_to_file(time_t now) { char *status = networkstatus_getinfo_by_purpose("bridge", now); - const or_options_t *options = get_options(); char *fname = NULL; char *thresholds = NULL; char *published_thresholds_and_status = NULL; @@ -2282,8 +2281,7 @@ networkstatus_dump_bridge_status_to_file(time_t now) "published %s\nflag-thresholds %s\n%s%s", published, thresholds, fingerprint_line ? fingerprint_line : "", status); - tor_asprintf(&fname, "%s"PATH_SEPARATOR"networkstatus-bridges", - options->DataDirectory); + fname = get_datadir_fname("networkstatus-bridges"); write_str_to_file(fname,published_thresholds_and_status,0); tor_free(thresholds); tor_free(published_thresholds_and_status); From 7b34ab3e384b5c72e938d11e5e05c72b9d529bb8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 16:18:53 -0500 Subject: [PATCH 05/11] Extract common code for creating the keys directory. This had somehow gotten duplicated between router.c and routerkeys.c --- src/or/config.c | 26 ++++++++++++++++++++++++++ src/or/config.h | 6 ++++++ src/or/router.c | 17 ++--------------- src/or/routerkeys.c | 19 ++++--------------- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index f024764f8a..d149a144d2 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1289,6 +1289,32 @@ check_and_create_data_directory(int create, return 0; } +/** + * Ensure that our keys directory exists, with appropriate permissions. + * Return 0 on success, -1 on failure. + */ +int +create_keys_directory(const or_options_t *options) +{ + /* Make sure DataDirectory exists, and is private. */ + cpd_check_t cpd_opts = CPD_CREATE; + if (options->DataDirectoryGroupReadable) + cpd_opts |= CPD_GROUP_READ; + if (check_private_dir(options->DataDirectory, cpd_opts, options->User)) { + log_err(LD_OR, "Can't create/check datadirectory %s", + options->DataDirectory); + return -1; + } + /* Check the key directory. */ + char *keydir = options_get_datadir_fname(options, "keys"); + if (check_private_dir(keydir, CPD_CREATE, options->User)) { + tor_free(keydir); + return -1; + } + tor_free(keydir); + return 0; +} + /* Helps determine flags to pass to switch_id. */ static int have_low_ports = -1; diff --git a/src/or/config.h b/src/or/config.h index efdd8c59b0..de9858a25b 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -72,6 +72,10 @@ MOCK_DECL(char *, * get_datadir_fname2_suffix. */ #define get_datadir_fname2(sub1,sub2) \ get_datadir_fname2_suffix((sub1), (sub2), NULL) +/** Return a newly allocated string containing datadir/sub1 relative to + * opts. See get_datadir_fname2_suffix. */ +#define options_get_datadir_fname(opts,sub1) \ + options_get_datadir_fname2_suffix((opts),(sub1), NULL, NULL) /** Return a newly allocated string containing datadir/sub1/sub2 relative to * opts. See get_datadir_fname2_suffix. */ #define options_get_datadir_fname2(opts,sub1,sub2) \ @@ -83,6 +87,8 @@ MOCK_DECL(char *, int using_default_dir_authorities(const or_options_t *options); +int create_keys_directory(const or_options_t *options); + int check_or_create_data_subdir(const char *subdir); int write_to_data_subdir(const char* subdir, const char* fname, const char* str, const char* descr); diff --git a/src/or/router.c b/src/or/router.c index 8ad5d038ef..fb8596a8d9 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -932,22 +932,9 @@ init_keys(void) } if (init_keys_common() < 0) return -1; - /* Make sure DataDirectory exists, and is private. */ - cpd_check_t cpd_opts = CPD_CREATE; - if (options->DataDirectoryGroupReadable) - cpd_opts |= CPD_GROUP_READ; - if (check_private_dir(options->DataDirectory, cpd_opts, options->User)) { - log_err(LD_OR, "Can't create/check datadirectory %s", - options->DataDirectory); + + if (create_keys_directory(options) < 0) return -1; - } - /* Check the key directory. */ - keydir = get_datadir_fname("keys"); - if (check_private_dir(keydir, CPD_CREATE, options->User)) { - tor_free(keydir); - return -1; - } - tor_free(keydir); /* 1a. Read v3 directory authority key/cert information. */ memset(v3_digest, 0, sizeof(v3_digest)); diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c index 7295c19653..c6c689ecd5 100644 --- a/src/or/routerkeys.c +++ b/src/or/routerkeys.c @@ -813,21 +813,10 @@ load_ed_keys(const or_options_t *options, time_t now) flags |= INIT_ED_KEY_TRY_ENCRYPTED; /* Check/Create the key directory */ - cpd_check_t cpd_opts = CPD_CREATE; - if (options->DataDirectoryGroupReadable) - cpd_opts |= CPD_GROUP_READ; - if (check_private_dir(options->DataDirectory, cpd_opts, options->User)) { - log_err(LD_OR, "Can't create/check datadirectory %s", - options->DataDirectory); - goto err; - } - char *fname = get_datadir_fname("keys"); - if (check_private_dir(fname, CPD_CREATE, options->User) < 0) { - log_err(LD_OR, "Problem creating/checking key directory %s", fname); - tor_free(fname); - goto err; - } - tor_free(fname); + if (create_keys_directory(options) < 0) + return -1; + + char *fname; if (options->master_key_fname) { fname = tor_strdup(options->master_key_fname); flags |= INIT_ED_KEY_EXPLICIT_FNAME; From 3907faf2fdc28a0c9f85279a58f2059c9a44f9b4 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 16:49:41 -0500 Subject: [PATCH 06/11] New accessors for keydir/cachedir access This patch is a result of auditing all of our uses of get_datadir_fname() and its kin, and dividing them into cache vs keys vs other data. The new get_keydir_fname() and get_cachedir_fname() functions don't actually do anything new yet. --- src/or/config.h | 21 ++++-- src/or/conscache.c | 2 +- src/or/control.c | 2 +- src/or/main.c | 153 +++++++++++++++++++++++++---------------- src/or/microdesc.c | 4 +- src/or/networkstatus.c | 14 ++-- src/or/router.c | 26 +++---- src/or/routerkeys.c | 12 ++-- src/or/routerlist.c | 16 ++--- 9 files changed, 148 insertions(+), 102 deletions(-) diff --git a/src/or/config.h b/src/or/config.h index de9858a25b..4e9bb0f6fe 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -72,6 +72,11 @@ MOCK_DECL(char *, * get_datadir_fname2_suffix. */ #define get_datadir_fname2(sub1,sub2) \ get_datadir_fname2_suffix((sub1), (sub2), NULL) +/** Return a newly allocated string containing datadir/sub1suffix. See + * get_datadir_fname2_suffix. */ +#define get_datadir_fname_suffix(sub1, suffix) \ + get_datadir_fname2_suffix((sub1), NULL, (suffix)) + /** Return a newly allocated string containing datadir/sub1 relative to * opts. See get_datadir_fname2_suffix. */ #define options_get_datadir_fname(opts,sub1) \ @@ -80,10 +85,18 @@ MOCK_DECL(char *, * opts. See get_datadir_fname2_suffix. */ #define options_get_datadir_fname2(opts,sub1,sub2) \ options_get_datadir_fname2_suffix((opts),(sub1), (sub2), NULL) -/** Return a newly allocated string containing datadir/sub1suffix. See - * get_datadir_fname2_suffix. */ -#define get_datadir_fname_suffix(sub1, suffix) \ - get_datadir_fname2_suffix((sub1), NULL, (suffix)) + +/** DOCDOC */ +#define get_keydir_fname(sub1) \ + get_datadir_fname2("keys", (sub1)) +#define options_get_keydir_fname(options, sub1) \ + options_get_datadir_fname2((options), "keys", (sub1)) +#define get_keydir_fname_suffix(sub1, suffix) \ + get_datadir_fname2_suffix("keys", (sub1), (suffix)) + +#define get_cachedir_fname(sub1) get_datadir_fname((sub1)) +#define get_cachedir_fname_suffix(sub1, suffix) \ + get_datadir_fname_suffix((sub1), (suffix)) int using_default_dir_authorities(const or_options_t *options); diff --git a/src/or/conscache.c b/src/or/conscache.c index 0f3e453eaf..1407d0f0b9 100644 --- a/src/or/conscache.c +++ b/src/or/conscache.c @@ -79,7 +79,7 @@ consensus_cache_open(const char *subdir, int max_entries) { int storagedir_max_entries; consensus_cache_t *cache = tor_malloc_zero(sizeof(consensus_cache_t)); - char *directory = get_datadir_fname(subdir); + char *directory = get_cachedir_fname(subdir); cache->max_entries = max_entries; #ifdef MUST_UNMAP_TO_UNLINK diff --git a/src/or/control.c b/src/or/control.c index 0d462b2d7d..e17e923650 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2115,7 +2115,7 @@ getinfo_helper_dir(control_connection_t *control_conn, *answer = tor_strdup(consensus->dir); } if (!*answer) { /* try loading it from disk */ - char *filename = get_datadir_fname("cached-consensus"); + char *filename = get_cachedir_fname("cached-consensus"); *answer = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); tor_free(filename); if (!*answer) { /* generate an error */ diff --git a/src/or/main.c b/src/or/main.c index e349703918..c0bdbd7603 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -3550,7 +3550,7 @@ sandbox_init_filter(void) int i; sandbox_cfg_allow_openat_filename(&cfg, - get_datadir_fname("cached-status")); + get_cachedir_fname("cached-status")); #define OPEN(name) \ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name)) @@ -3571,21 +3571,37 @@ sandbox_init_filter(void) OPEN_DATADIR2(name, name2 suffix); \ } while (0) +#define OPEN_KEY_DIRECTORY() OPEN_DATADIR("keys") +#define OPEN_CACHEDIR(name) \ + sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name)) +#define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \ + OPEN_CACHEDIR(name); \ + OPEN_CACHEDIR(name suffix); \ + } while (0) +#define OPEN_KEYDIR(name) \ + sandbox_cfg_allow_open_filename(&cfg, get_keydir_fname(name)) +#define OPEN_KEYDIR_SUFFIX(name, suffix) do { \ + OPEN_KEYDIR(name); \ + OPEN_KEYDIR(name suffix); \ + } while (0) + OPEN(options->DataDirectory); - OPEN_DATADIR("keys"); - OPEN_DATADIR_SUFFIX("cached-certs", ".tmp"); - OPEN_DATADIR_SUFFIX("cached-consensus", ".tmp"); - OPEN_DATADIR_SUFFIX("unverified-consensus", ".tmp"); - OPEN_DATADIR_SUFFIX("unverified-microdesc-consensus", ".tmp"); - OPEN_DATADIR_SUFFIX("cached-microdesc-consensus", ".tmp"); - OPEN_DATADIR_SUFFIX("cached-microdescs", ".tmp"); - OPEN_DATADIR_SUFFIX("cached-microdescs.new", ".tmp"); - OPEN_DATADIR_SUFFIX("cached-descriptors", ".tmp"); - OPEN_DATADIR_SUFFIX("cached-descriptors.new", ".tmp"); - OPEN_DATADIR("cached-descriptors.tmp.tmp"); - OPEN_DATADIR_SUFFIX("cached-extrainfo", ".tmp"); - OPEN_DATADIR_SUFFIX("cached-extrainfo.new", ".tmp"); - OPEN_DATADIR("cached-extrainfo.tmp.tmp"); + OPEN_KEY_DIRECTORY(); + + OPEN_CACHEDIR_SUFFIX("cached-certs", ".tmp"); + OPEN_CACHEDIR_SUFFIX("cached-consensus", ".tmp"); + OPEN_CACHEDIR_SUFFIX("unverified-consensus", ".tmp"); + OPEN_CACHEDIR_SUFFIX("unverified-microdesc-consensus", ".tmp"); + OPEN_CACHEDIR_SUFFIX("cached-microdesc-consensus", ".tmp"); + OPEN_CACHEDIR_SUFFIX("cached-microdescs", ".tmp"); + OPEN_CACHEDIR_SUFFIX("cached-microdescs.new", ".tmp"); + OPEN_CACHEDIR_SUFFIX("cached-descriptors", ".tmp"); + OPEN_CACHEDIR_SUFFIX("cached-descriptors.new", ".tmp"); + OPEN_CACHEDIR("cached-descriptors.tmp.tmp"); + OPEN_CACHEDIR_SUFFIX("cached-extrainfo", ".tmp"); + OPEN_CACHEDIR_SUFFIX("cached-extrainfo.new", ".tmp"); + OPEN_CACHEDIR("cached-extrainfo.tmp.tmp"); + OPEN_DATADIR_SUFFIX("state", ".tmp"); OPEN_DATADIR_SUFFIX("sr-state", ".tmp"); OPEN_DATADIR_SUFFIX("unparseable-desc", ".tmp"); @@ -3629,20 +3645,31 @@ sandbox_init_filter(void) get_datadir_fname2(prefix, name suffix), \ get_datadir_fname2(prefix, name)) - RENAME_SUFFIX("cached-certs", ".tmp"); - RENAME_SUFFIX("cached-consensus", ".tmp"); - RENAME_SUFFIX("unverified-consensus", ".tmp"); - RENAME_SUFFIX("unverified-microdesc-consensus", ".tmp"); - RENAME_SUFFIX("cached-microdesc-consensus", ".tmp"); - RENAME_SUFFIX("cached-microdescs", ".tmp"); - RENAME_SUFFIX("cached-microdescs", ".new"); - RENAME_SUFFIX("cached-microdescs.new", ".tmp"); - RENAME_SUFFIX("cached-descriptors", ".tmp"); - RENAME_SUFFIX("cached-descriptors", ".new"); - RENAME_SUFFIX("cached-descriptors.new", ".tmp"); - RENAME_SUFFIX("cached-extrainfo", ".tmp"); - RENAME_SUFFIX("cached-extrainfo", ".new"); - RENAME_SUFFIX("cached-extrainfo.new", ".tmp"); +#define RENAME_CACHEDIR_SUFFIX(name, suffix) \ + sandbox_cfg_allow_rename(&cfg, \ + get_cachedir_fname(name suffix), \ + get_cachedir_fname(name)) + +#define RENAME_KEYDIR_SUFFIX(name, suffix) \ + sandbox_cfg_allow_rename(&cfg, \ + get_keydir_fname(name suffix), \ + get_keydir_fname(name)) + + RENAME_CACHEDIR_SUFFIX("cached-certs", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-consensus", ".tmp"); + RENAME_CACHEDIR_SUFFIX("unverified-consensus", ".tmp"); + RENAME_CACHEDIR_SUFFIX("unverified-microdesc-consensus", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-microdesc-consensus", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-microdescs", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-microdescs", ".new"); + RENAME_CACHEDIR_SUFFIX("cached-microdescs.new", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-descriptors", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-descriptors", ".new"); + RENAME_CACHEDIR_SUFFIX("cached-descriptors.new", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-extrainfo", ".tmp"); + RENAME_CACHEDIR_SUFFIX("cached-extrainfo", ".new"); + RENAME_CACHEDIR_SUFFIX("cached-extrainfo.new", ".tmp"); + RENAME_SUFFIX("state", ".tmp"); RENAME_SUFFIX("sr-state", ".tmp"); RENAME_SUFFIX("unparseable-desc", ".tmp"); @@ -3654,14 +3681,20 @@ sandbox_init_filter(void) #define STAT_DATADIR(name) \ sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname(name)) +#define STAT_CACHEDIR(name) \ + sandbox_cfg_allow_stat_filename(&cfg, get_cachedir_fname(name)) + #define STAT_DATADIR2(name, name2) \ sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname2((name), (name2))) +#define STAT_KEY_DIRECTORY() STAT_DATADIR("keys") + STAT_DATADIR(NULL); STAT_DATADIR("lock"); STAT_DATADIR("state"); STAT_DATADIR("router-stability"); - STAT_DATADIR("cached-extrainfo.new"); + + STAT_CACHEDIR("cached-extrainfo.new"); { smartlist_t *files = smartlist_new(); @@ -3726,22 +3759,20 @@ sandbox_init_filter(void) // orport if (server_mode(get_options())) { - OPEN_DATADIR2_SUFFIX("keys", "secret_id_key", ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key", ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key_ntor", ".tmp"); - OPEN_DATADIR2("keys", "secret_id_key.old"); - OPEN_DATADIR2("keys", "secret_onion_key.old"); - OPEN_DATADIR2("keys", "secret_onion_key_ntor.old"); + OPEN_KEYDIR_SUFFIX("secret_id_key", ".tmp"); + OPEN_KEYDIR_SUFFIX("secret_onion_key", ".tmp"); + OPEN_KEYDIR_SUFFIX("secret_onion_key_ntor", ".tmp"); + OPEN_KEYDIR("secret_id_key.old"); + OPEN_KEYDIR("secret_onion_key.old"); + OPEN_KEYDIR("secret_onion_key_ntor.old"); - OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_secret_key", ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_secret_key_encrypted", - ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_public_key", ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_secret_key", ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_secret_key_encrypted", - ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_public_key", ".tmp"); - OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_cert", ".tmp"); + OPEN_KEYDIR_SUFFIX("ed25519_master_id_secret_key", ".tmp"); + OPEN_KEYDIR_SUFFIX("ed25519_master_id_secret_key_encrypted", ".tmp"); + OPEN_KEYDIR_SUFFIX("ed25519_master_id_public_key", ".tmp"); + OPEN_KEYDIR_SUFFIX("ed25519_signing_secret_key", ".tmp"); + OPEN_KEYDIR_SUFFIX("ed25519_signing_secret_key_encrypted", ".tmp"); + OPEN_KEYDIR_SUFFIX("ed25519_signing_public_key", ".tmp"); + OPEN_KEYDIR_SUFFIX("ed25519_signing_cert", ".tmp"); OPEN_DATADIR2_SUFFIX("stats", "bridge-stats", ".tmp"); OPEN_DATADIR2_SUFFIX("stats", "dirreq-stats", ".tmp"); @@ -3760,11 +3791,13 @@ sandbox_init_filter(void) OPEN("/etc/resolv.conf"); RENAME_SUFFIX("fingerprint", ".tmp"); - RENAME_SUFFIX2("keys", "secret_onion_key_ntor", ".tmp"); - RENAME_SUFFIX2("keys", "secret_id_key", ".tmp"); - RENAME_SUFFIX2("keys", "secret_id_key.old", ".tmp"); - RENAME_SUFFIX2("keys", "secret_onion_key", ".tmp"); - RENAME_SUFFIX2("keys", "secret_onion_key.old", ".tmp"); + RENAME_KEYDIR_SUFFIX("secret_onion_key_ntor", ".tmp"); + + RENAME_KEYDIR_SUFFIX("secret_id_key", ".tmp"); + RENAME_KEYDIR_SUFFIX("secret_id_key.old", ".tmp"); + RENAME_KEYDIR_SUFFIX("secret_onion_key", ".tmp"); + RENAME_KEYDIR_SUFFIX("secret_onion_key.old", ".tmp"); + RENAME_SUFFIX2("stats", "bridge-stats", ".tmp"); RENAME_SUFFIX2("stats", "dirreq-stats", ".tmp"); RENAME_SUFFIX2("stats", "entry-stats", ".tmp"); @@ -3775,20 +3808,20 @@ sandbox_init_filter(void) RENAME_SUFFIX("hashed-fingerprint", ".tmp"); RENAME_SUFFIX("router-stability", ".tmp"); - RENAME_SUFFIX2("keys", "ed25519_master_id_secret_key", ".tmp"); - RENAME_SUFFIX2("keys", "ed25519_master_id_secret_key_encrypted", ".tmp"); - RENAME_SUFFIX2("keys", "ed25519_master_id_public_key", ".tmp"); - RENAME_SUFFIX2("keys", "ed25519_signing_secret_key", ".tmp"); - RENAME_SUFFIX2("keys", "ed25519_signing_cert", ".tmp"); + RENAME_KEYDIR_SUFFIX("ed25519_master_id_secret_key", ".tmp"); + RENAME_KEYDIR_SUFFIX("ed25519_master_id_secret_key_encrypted", ".tmp"); + RENAME_KEYDIR_SUFFIX("ed25519_master_id_public_key", ".tmp"); + RENAME_KEYDIR_SUFFIX("ed25519_signing_secret_key", ".tmp"); + RENAME_KEYDIR_SUFFIX("ed25519_signing_cert", ".tmp"); sandbox_cfg_allow_rename(&cfg, - get_datadir_fname2("keys", "secret_onion_key"), - get_datadir_fname2("keys", "secret_onion_key.old")); + get_keydir_fname("secret_onion_key"), + get_keydir_fname("secret_onion_key.old")); sandbox_cfg_allow_rename(&cfg, - get_datadir_fname2("keys", "secret_onion_key_ntor"), - get_datadir_fname2("keys", "secret_onion_key_ntor.old")); + get_keydir_fname("secret_onion_key_ntor"), + get_keydir_fname("secret_onion_key_ntor.old")); - STAT_DATADIR("keys"); + STAT_KEY_DIRECTORY(); OPEN_DATADIR("stats"); STAT_DATADIR("stats"); STAT_DATADIR2("stats", "dirreq-stats"); diff --git a/src/or/microdesc.c b/src/or/microdesc.c index 18a6fbded7..3fe5e933d0 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -142,8 +142,8 @@ get_microdesc_cache_noload(void) if (PREDICT_UNLIKELY(the_microdesc_cache==NULL)) { microdesc_cache_t *cache = tor_malloc_zero(sizeof(*cache)); HT_INIT(microdesc_map, &cache->map); - cache->cache_fname = get_datadir_fname("cached-microdescs"); - cache->journal_fname = get_datadir_fname("cached-microdescs.new"); + cache->cache_fname = get_cachedir_fname("cached-microdescs"); + cache->journal_fname = get_cachedir_fname("cached-microdescs.new"); the_microdesc_cache = cache; } return the_microdesc_cache; diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index ff32476685..d382cc8033 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -197,7 +197,7 @@ networkstatus_read_cached_consensus_impl(int flav, tor_snprintf(buf, sizeof(buf), "%s-%s-consensus", prefix, flavorname); } - char *filename = get_datadir_fname(buf); + char *filename = get_cachedir_fname(buf); char *result = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); tor_free(filename); return result; @@ -1794,15 +1794,15 @@ networkstatus_set_current_consensus(const char *consensus, } if (!strcmp(flavor, "ns")) { - consensus_fname = get_datadir_fname("cached-consensus"); - unverified_fname = get_datadir_fname("unverified-consensus"); + consensus_fname = get_cachedir_fname("cached-consensus"); + unverified_fname = get_cachedir_fname("unverified-consensus"); if (current_ns_consensus) { current_digests = ¤t_ns_consensus->digests; current_valid_after = current_ns_consensus->valid_after; } } else if (!strcmp(flavor, "microdesc")) { - consensus_fname = get_datadir_fname("cached-microdesc-consensus"); - unverified_fname = get_datadir_fname("unverified-microdesc-consensus"); + consensus_fname = get_cachedir_fname("cached-microdesc-consensus"); + unverified_fname = get_cachedir_fname("unverified-microdesc-consensus"); if (current_md_consensus) { current_digests = ¤t_md_consensus->digests; current_valid_after = current_md_consensus->valid_after; @@ -1811,9 +1811,9 @@ networkstatus_set_current_consensus(const char *consensus, cached_dir_t *cur; char buf[128]; tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor); - consensus_fname = get_datadir_fname(buf); + consensus_fname = get_cachedir_fname(buf); tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor); - unverified_fname = get_datadir_fname(buf); + unverified_fname = get_cachedir_fname(buf); cur = dirserv_get_consensus(flavor); if (cur) { current_digests = &cur->digests; diff --git a/src/or/router.c b/src/or/router.c index fb8596a8d9..64bd9fdfcd 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -174,7 +174,7 @@ expire_old_onion_keys(void) tor_mutex_release(key_lock); - fname = get_datadir_fname2("keys", "secret_onion_key.old"); + fname = get_keydir_fname("secret_onion_key.old"); if (file_status(fname) == FN_FILE) { if (tor_unlink(fname) != 0) { log_warn(LD_FS, "Couldn't unlink old onion key file %s: %s", @@ -183,7 +183,7 @@ expire_old_onion_keys(void) } tor_free(fname); - fname = get_datadir_fname2("keys", "secret_onion_key_ntor.old"); + fname = get_keydir_fname("secret_onion_key_ntor.old"); if (file_status(fname) == FN_FILE) { if (tor_unlink(fname) != 0) { log_warn(LD_FS, "Couldn't unlink old ntor onion key file %s: %s", @@ -378,8 +378,8 @@ rotate_onion_key(void) or_state_t *state = get_or_state(); curve25519_keypair_t new_curve25519_keypair; time_t now; - fname = get_datadir_fname2("keys", "secret_onion_key"); - fname_prev = get_datadir_fname2("keys", "secret_onion_key.old"); + fname = get_keydir_fname("secret_onion_key"); + fname_prev = get_keydir_fname("secret_onion_key.old"); /* There isn't much point replacing an old key with an empty file */ if (file_status(fname) == FN_FILE) { if (replace_file(fname, fname_prev)) @@ -399,8 +399,8 @@ rotate_onion_key(void) } tor_free(fname); tor_free(fname_prev); - fname = get_datadir_fname2("keys", "secret_onion_key_ntor"); - fname_prev = get_datadir_fname2("keys", "secret_onion_key_ntor.old"); + fname = get_keydir_fname("secret_onion_key_ntor"); + fname_prev = get_keydir_fname("secret_onion_key_ntor.old"); if (curve25519_keypair_generate(&new_curve25519_keypair, 1) < 0) goto error; /* There isn't much point replacing an old key with an empty file */ @@ -624,7 +624,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out, crypto_pk_t *signing_key = NULL; authority_cert_t *parsed = NULL; - fname = get_datadir_fname2("keys", + fname = get_keydir_fname( legacy ? "legacy_signing_key" : "authority_signing_key"); signing_key = init_key_from_file(fname, 0, LOG_ERR, 0); if (!signing_key) { @@ -632,7 +632,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out, goto done; } tor_free(fname); - fname = get_datadir_fname2("keys", + fname = get_keydir_fname( legacy ? "legacy_certificate" : "authority_certificate"); cert = read_file_to_str(fname, 0, NULL); if (!cert) { @@ -958,7 +958,7 @@ init_keys(void) } /* 1b. Read identity key. Make it if none is found. */ - keydir = get_datadir_fname2("keys", "secret_id_key"); + keydir = get_keydir_fname("secret_id_key"); log_info(LD_GENERAL,"Reading/making identity key \"%s\"...",keydir); prkey = init_key_from_file(keydir, 1, LOG_ERR, 1); tor_free(keydir); @@ -986,7 +986,7 @@ init_keys(void) return -1; /* 2. Read onion key. Make it if none is found. */ - keydir = get_datadir_fname2("keys", "secret_onion_key"); + keydir = get_keydir_fname("secret_onion_key"); log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir); prkey = init_key_from_file(keydir, 1, LOG_ERR, 1); tor_free(keydir); @@ -1011,7 +1011,7 @@ init_keys(void) } } - keydir = get_datadir_fname2("keys", "secret_onion_key.old"); + keydir = get_keydir_fname("secret_onion_key.old"); if (!lastonionkey && file_status(keydir) == FN_FILE) { /* Load keys from non-empty files only. * Missing old keys won't be replaced with freshly generated keys. */ @@ -1024,14 +1024,14 @@ init_keys(void) { /* 2b. Load curve25519 onion keys. */ int r; - keydir = get_datadir_fname2("keys", "secret_onion_key_ntor"); + keydir = get_keydir_fname("secret_onion_key_ntor"); r = init_curve25519_keypair_from_file(&curve25519_onion_key, keydir, 1, LOG_ERR, "onion"); tor_free(keydir); if (r<0) return -1; - keydir = get_datadir_fname2("keys", "secret_onion_key_ntor.old"); + keydir = get_keydir_fname("secret_onion_key_ntor.old"); if (tor_mem_is_zero((const char *) last_curve25519_onion_key.pubkey.public_key, CURVE25519_PUBKEY_LEN) && diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c index c6c689ecd5..af230f07bf 100644 --- a/src/or/routerkeys.c +++ b/src/or/routerkeys.c @@ -718,7 +718,7 @@ load_ed_keys(const or_options_t *options, time_t now) /* First try to get the signing key to see how it is. */ { char *fname = - options_get_datadir_fname2(options, "keys", "ed25519_signing"); + options_get_keydir_fname(options, "ed25519_signing"); sign = ed_key_init_from_file( fname, INIT_ED_KEY_NEEDCERT| @@ -821,7 +821,7 @@ load_ed_keys(const or_options_t *options, time_t now) fname = tor_strdup(options->master_key_fname); flags |= INIT_ED_KEY_EXPLICIT_FNAME; } else { - fname = options_get_datadir_fname2(options, "keys", "ed25519_master_id"); + fname = options_get_keydir_fname(options, "ed25519_master_id"); } id = ed_key_init_from_file( fname, @@ -841,8 +841,8 @@ load_ed_keys(const or_options_t *options, time_t now) id = tor_malloc_zero(sizeof(*id)); memcpy(&id->pubkey, &check_signing_cert->signing_key, sizeof(ed25519_public_key_t)); - fname = options_get_datadir_fname2(options, "keys", - "ed25519_master_id_public_key"); + fname = options_get_keydir_fname(options, + "ed25519_master_id_public_key"); if (ed25519_pubkey_write_to_file(&id->pubkey, fname, "type0") < 0) { log_warn(LD_OR, "Error while attempting to write master public key " "to disk"); @@ -883,7 +883,7 @@ load_ed_keys(const or_options_t *options, time_t now) INIT_ED_KEY_NEEDCERT| INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT); char *fname = - options_get_datadir_fname2(options, "keys", "ed25519_signing"); + options_get_keydir_fname(options, "ed25519_signing"); ed25519_keypair_free(sign); tor_cert_free(sign_cert); sign = ed_key_init_from_file(fname, @@ -1174,7 +1174,7 @@ log_master_signing_key_cert_expiration(const or_options_t *options) int failed = 0; time_t now = approx_time(); - fn = options_get_datadir_fname2(options, "keys", "ed25519_signing_cert"); + fn = options_get_keydir_fname(options, "ed25519_signing_cert"); /* Try to grab our cached copy of the key. */ signing_key = get_master_signing_key_cert(); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index fb8225e0d6..bd200a783d 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -473,7 +473,7 @@ trusted_dirs_reload_certs(void) char *contents; int r; - filename = get_datadir_fname("cached-certs"); + filename = get_cachedir_fname("cached-certs"); contents = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); tor_free(filename); if (!contents) @@ -662,7 +662,7 @@ trusted_dirs_flush_certs_to_disk(void) }); } DIGESTMAP_FOREACH_END; - filename = get_datadir_fname("cached-certs"); + filename = get_cachedir_fname("cached-certs"); if (write_chunks_to_file(filename, chunks, 0, 0)) { log_warn(LD_FS, "Error writing certificates to disk."); } @@ -1339,7 +1339,7 @@ static int signed_desc_append_to_journal(signed_descriptor_t *desc, desc_store_t *store) { - char *fname = get_datadir_fname_suffix(store->fname_base, ".new"); + char *fname = get_cachedir_fname_suffix(store->fname_base, ".new"); const char *body = signed_descriptor_get_body_impl(desc,1); size_t len = desc->signed_descriptor_len + desc->annotations_len; @@ -1410,8 +1410,8 @@ router_rebuild_store(int flags, desc_store_t *store) log_info(LD_DIR, "Rebuilding %s cache", store->description); - fname = get_datadir_fname(store->fname_base); - fname_tmp = get_datadir_fname_suffix(store->fname_base, ".tmp"); + fname = get_cachedir_fname(store->fname_base); + fname_tmp = get_cachedir_fname_suffix(store->fname_base, ".tmp"); chunk_list = smartlist_new(); @@ -1508,7 +1508,7 @@ router_rebuild_store(int flags, desc_store_t *store) } SMARTLIST_FOREACH_END(sd); tor_free(fname); - fname = get_datadir_fname_suffix(store->fname_base, ".new"); + fname = get_cachedir_fname_suffix(store->fname_base, ".new"); write_str_to_file(fname, "", 1); r = 0; @@ -1538,7 +1538,7 @@ router_reload_router_list_impl(desc_store_t *store) int extrainfo = (store->type == EXTRAINFO_STORE); store->journal_len = store->store_len = 0; - fname = get_datadir_fname(store->fname_base); + fname = get_cachedir_fname(store->fname_base); if (store->mmap) { /* get rid of it first */ @@ -1565,7 +1565,7 @@ router_reload_router_list_impl(desc_store_t *store) } tor_free(fname); - fname = get_datadir_fname_suffix(store->fname_base, ".new"); + fname = get_cachedir_fname_suffix(store->fname_base, ".new"); /* don't load empty files - we wouldn't get any data, even if we tried */ if (file_status(fname) == FN_FILE) contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); From 39a780e85a0a8cb42f817d0d948ce8fb97662bd3 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 16:54:20 -0500 Subject: [PATCH 07/11] Clean up a needlessly complex get_datadir_fname use --- src/or/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/or/main.c b/src/or/main.c index c0bdbd7603..2234e7cdb8 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -3274,7 +3274,7 @@ try_locking(const or_options_t *options, int err_if_locked) if (lockfile) return 0; else { - char *fname = options_get_datadir_fname2_suffix(options, "lock",NULL,NULL); + char *fname = options_get_datadir_fname(options, "lock"); int already_locked = 0; tor_lockfile_t *lf = tor_lockfile_lock(fname, 0, &already_locked); tor_free(fname); From a9806af2610904308642518990fc82c71d567d4a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 17:07:40 -0500 Subject: [PATCH 08/11] Create a CacheDirectory and KeyDirectory options. They work the same as DataDirectory, but default slightly different. Tor is not actually updated to use them yet. --- src/or/config.c | 75 +++++++++++++++++++++++++++++++++++++++++++------ src/or/main.c | 6 ++-- src/or/or.h | 11 ++++++++ 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index d149a144d2..a5007d03fe 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -253,6 +253,8 @@ static config_var_t option_vars_[] = { V(BridgeRecordUsageByCountry, BOOL, "1"), V(BridgeRelay, BOOL, "0"), V(BridgeDistribution, STRING, NULL), + VAR("CacheDirectory", FILENAME, CacheDirectory_option, NULL), + V(CacheDirectoryGroupReadable, BOOL, "0"), V(CellStatistics, BOOL, "0"), V(PaddingStatistics, BOOL, "1"), V(LearnCircuitBuildTimeout, BOOL, "1"), @@ -392,6 +394,8 @@ static config_var_t option_vars_[] = { V(Socks5Proxy, STRING, NULL), V(Socks5ProxyUsername, STRING, NULL), V(Socks5ProxyPassword, STRING, NULL), + VAR("KeyDirectory", FILENAME, KeyDirectory_option, NULL), + V(KeyDirectoryGroupReadable, BOOL, "0"), V(KeepalivePeriod, INTERVAL, "5 minutes"), V(KeepBindCapabilities, AUTOBOOL, "auto"), VAR("Log", LINELIST, Logs, NULL), @@ -733,7 +737,7 @@ static int parse_ports(or_options_t *options, int validate_only, static int check_server_ports(const smartlist_t *ports, const or_options_t *options, int *num_low_ports_out); -static int validate_data_directory(or_options_t *options); +static int validate_data_directories(or_options_t *options); static int write_configuration_file(const char *fname, const or_options_t *options); static int options_init_logs(const or_options_t *old_options, @@ -942,6 +946,8 @@ or_options_free(or_options_t *options) smartlist_free(options->FilesOpenedByIncludes); } tor_free(options->DataDirectory); + tor_free(options->CacheDirectory); + tor_free(options->KeyDirectory); tor_free(options->BridgePassword_AuthDigest_); tor_free(options->command_arg); tor_free(options->master_key_fname); @@ -1305,13 +1311,11 @@ create_keys_directory(const or_options_t *options) options->DataDirectory); return -1; } + /* Check the key directory. */ - char *keydir = options_get_datadir_fname(options, "keys"); - if (check_private_dir(keydir, CPD_CREATE, options->User)) { - tor_free(keydir); + if (check_private_dir(options->KeyDirectory, CPD_CREATE, options->User)) { return -1; } - tor_free(keydir); return 0; } @@ -1479,6 +1483,20 @@ options_act_reversible(const or_options_t *old_options, char **msg) msg) < 0) { goto done; } + if (check_and_create_data_directory(running_tor /* create */, + options->KeyDirectory, + options->KeyDirectoryGroupReadable, + options->User, + msg) < 0) { + goto done; + } + if (check_and_create_data_directory(running_tor /* create */, + options->CacheDirectory, + options->CacheDirectoryGroupReadable, + options->User, + msg) < 0) { + goto done; + } /* Bail out at this point if we're not going to be a client or server: * we don't run Tor itself. */ @@ -3240,7 +3258,7 @@ options_validate(or_options_t *old_options, or_options_t *options, if (parse_outbound_addresses(options, 1, msg) < 0) return -1; - if (validate_data_directory(options)<0) + if (validate_data_directories(options)<0) REJECT("Invalid DataDirectory"); if (options->Nickname == NULL) { @@ -4638,6 +4656,22 @@ options_transition_allowed(const or_options_t *old, return -1; } + if (!opt_streq(old->KeyDirectory, new_val->KeyDirectory)) { + tor_asprintf(msg, + "While Tor is running, changing KeyDirectory " + "(\"%s\"->\"%s\") is not allowed.", + old->KeyDirectory, new_val->KeyDirectory); + return -1; + } + + if (!opt_streq(old->CacheDirectory, new_val->CacheDirectory)) { + tor_asprintf(msg, + "While Tor is running, changing CacheDirectory " + "(\"%s\"->\"%s\") is not allowed.", + old->CacheDirectory, new_val->CacheDirectory); + return -1; + } + if (!opt_streq(old->User, new_val->User)) { *msg = tor_strdup("While Tor is running, changing User is not allowed."); return -1; @@ -7774,10 +7808,10 @@ get_data_directory(const char *val) #endif /* defined(_WIN32) */ } -/** Check and normalize the value of options->DataDirectory; return 0 if it - * is sane, -1 otherwise. */ +/** Check and normalize the values of options->{Key,Data,Cache}Directory; + * return 0 if it is sane, -1 otherwise. */ static int -validate_data_directory(or_options_t *options) +validate_data_directories(or_options_t *options) { tor_free(options->DataDirectory); options->DataDirectory = get_data_directory(options->DataDirectory_option); @@ -7787,6 +7821,29 @@ validate_data_directory(or_options_t *options) log_warn(LD_CONFIG, "DataDirectory is too long."); return -1; } + + tor_free(options->KeyDirectory); + if (options->KeyDirectory_option) { + options->KeyDirectory = get_data_directory(options->KeyDirectory_option); + if (!options->KeyDirectory) + return -1; + } else { + /* Default to the data directory's keys subdir */ + tor_asprintf(&options->KeyDirectory, "%s"PATH_SEPARATOR"keys", + options->DataDirectory); + } + + tor_free(options->CacheDirectory); + if (options->CacheDirectory_option) { + options->CacheDirectory = get_data_directory( + options->CacheDirectory_option); + if (!options->CacheDirectory) + return -1; + } else { + /* Default to the data directory. */ + options->CacheDirectory = tor_strdup(options->DataDirectory); + } + return 0; } diff --git a/src/or/main.c b/src/or/main.c index 2234e7cdb8..b70f47abeb 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -3571,7 +3571,8 @@ sandbox_init_filter(void) OPEN_DATADIR2(name, name2 suffix); \ } while (0) -#define OPEN_KEY_DIRECTORY() OPEN_DATADIR("keys") +#define OPEN_KEY_DIRECTORY() \ + sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory)) #define OPEN_CACHEDIR(name) \ sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name)) #define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \ @@ -3687,7 +3688,8 @@ sandbox_init_filter(void) #define STAT_DATADIR2(name, name2) \ sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname2((name), (name2))) -#define STAT_KEY_DIRECTORY() STAT_DATADIR("keys") +#define STAT_KEY_DIRECTORY() \ + sandbox_cfg_allow_stat_filename(&cfg, tor_strdup(options->KeyDirectory)) STAT_DATADIR(NULL); STAT_DATADIR("lock"); diff --git a/src/or/or.h b/src/or/or.h index 61e8d0b445..e10decf734 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3645,6 +3645,17 @@ typedef struct { * configured by the user. */ char *DataDirectory; /**< Where to store long-term data, as modified. */ int DataDirectoryGroupReadable; /**< Boolean: Is the DataDirectory g+r? */ + + char *KeyDirectory_option; /**< Where to store keys, as + * configured by the user. */ + char *KeyDirectory; /**< Where to store keys data, as modified. */ + int KeyDirectoryGroupReadable; /**< Boolean: Is the KeyDirectory g+r? */ + + char *CacheDirectory_option; /**< Where to store cached data, as + * configured by the user. */ + char *CacheDirectory; /**< Where to store cached data, as modified. */ + int CacheDirectoryGroupReadable; /**< Boolean: Is the CacheDirectory g+r? */ + char *Nickname; /**< OR only: nickname of this onion router. */ char *Address; /**< OR only: configured address for this onion router. */ char *PidFile; /**< Where to store PID of Tor process. */ From a57bcffcc7972419418b18d9a720a32471408ca5 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 18:14:08 -0500 Subject: [PATCH 09/11] Implement the various get_foodir_*() functions. --- src/or/config.c | 75 ++++++++++++++++--------------- src/or/config.h | 81 ++++++++++++++++++++++------------ src/test/test_conscache.c | 12 ++--- src/test/test_consdiffmgr.c | 8 ++-- src/test/test_dir.c | 6 ++- src/test/test_dir_handle_get.c | 1 + src/test/test_microdesc.c | 36 +++++++-------- src/test/test_routerkeys.c | 9 ++-- src/test/testing_common.c | 3 ++ 9 files changed, 135 insertions(+), 96 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index a5007d03fe..16e6445616 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -7984,53 +7984,56 @@ init_libevent(const or_options_t *options) suppress_libevent_log_msg(NULL); } -/** Return a newly allocated string holding a filename relative to the data - * directory. If sub1 is present, it is the first path component after +/** Return a newly allocated string holding a filename relative to the + * directory in options specified by roottype. + * If sub1 is present, it is the first path component after * the data directory. If sub2 is also present, it is the second path * component after the data directory. If suffix is present, it * is appended to the filename. * - * Examples: - * get_datadir_fname2_suffix("a", NULL, NULL) -> $DATADIR/a - * get_datadir_fname2_suffix("a", NULL, ".tmp") -> $DATADIR/a.tmp - * get_datadir_fname2_suffix("a", "b", ".tmp") -> $DATADIR/a/b/.tmp - * get_datadir_fname2_suffix("a", "b", NULL) -> $DATADIR/a/b - * - * Note: Consider using the get_datadir_fname* macros in or.h. + * Note: Consider using macros in config.h that wrap this function; + * you should probably never need to call it as-is. */ MOCK_IMPL(char *, -options_get_datadir_fname2_suffix,(const or_options_t *options, - const char *sub1, const char *sub2, - const char *suffix)) +options_get_dir_fname2_suffix,(const or_options_t *options, + directory_root_t roottype, + const char *sub1, const char *sub2, + const char *suffix)) { - char *fname = NULL; - size_t len; tor_assert(options); - tor_assert(options->DataDirectory); - tor_assert(sub1 || !sub2); /* If sub2 is present, sub1 must be present. */ - len = strlen(options->DataDirectory); - if (sub1) { - len += strlen(sub1)+1; - if (sub2) - len += strlen(sub2)+1; + + const char *rootdir = NULL; + switch (roottype) { + case DIRROOT_DATADIR: + rootdir = options->DataDirectory; + break; + case DIRROOT_CACHEDIR: + rootdir = options->CacheDirectory; + break; + case DIRROOT_KEYDIR: + rootdir = options->KeyDirectory; + break; + default: + tor_assert_unreached(); + break; } - if (suffix) - len += strlen(suffix); - len++; - fname = tor_malloc(len); - if (sub1) { - if (sub2) { - tor_snprintf(fname, len, "%s"PATH_SEPARATOR"%s"PATH_SEPARATOR"%s", - options->DataDirectory, sub1, sub2); - } else { - tor_snprintf(fname, len, "%s"PATH_SEPARATOR"%s", - options->DataDirectory, sub1); - } + tor_assert(rootdir); + + if (!suffix) + suffix = ""; + + char *fname = NULL; + + if (sub1 == NULL) { + tor_asprintf(&fname, "%s%s", rootdir, suffix); + tor_assert(!sub2); /* If sub2 is present, sub1 must be present. */ + } else if (sub2 == NULL) { + tor_asprintf(&fname, "%s"PATH_SEPARATOR"%s%s", rootdir, sub1, suffix); } else { - strlcpy(fname, options->DataDirectory, len); + tor_asprintf(&fname, "%s"PATH_SEPARATOR"%s"PATH_SEPARATOR"%s%s", + rootdir, sub1, sub2, suffix); } - if (suffix) - strlcat(fname, suffix, len); + return fname; } diff --git a/src/or/config.h b/src/or/config.h index 4e9bb0f6fe..1e4239b6d7 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -58,45 +58,72 @@ config_line_t *option_get_assignment(const or_options_t *options, const char *key); int options_save_current(void); const char *get_torrc_fname(int defaults_fname); +typedef enum { + DIRROOT_DATADIR, + DIRROOT_CACHEDIR, + DIRROOT_KEYDIR +} directory_root_t; + MOCK_DECL(char *, - options_get_datadir_fname2_suffix, + options_get_dir_fname2_suffix, (const or_options_t *options, + directory_root_t roottype, const char *sub1, const char *sub2, const char *suffix)); -#define get_datadir_fname2_suffix(sub1, sub2, suffix) \ - options_get_datadir_fname2_suffix(get_options(), (sub1), (sub2), (suffix)) -/** Return a newly allocated string containing datadir/sub1. See - * get_datadir_fname2_suffix. */ -#define get_datadir_fname(sub1) get_datadir_fname2_suffix((sub1), NULL, NULL) -/** Return a newly allocated string containing datadir/sub1/sub2. See - * get_datadir_fname2_suffix. */ -#define get_datadir_fname2(sub1,sub2) \ - get_datadir_fname2_suffix((sub1), (sub2), NULL) -/** Return a newly allocated string containing datadir/sub1suffix. See - * get_datadir_fname2_suffix. */ -#define get_datadir_fname_suffix(sub1, suffix) \ - get_datadir_fname2_suffix((sub1), NULL, (suffix)) -/** Return a newly allocated string containing datadir/sub1 relative to - * opts. See get_datadir_fname2_suffix. */ +/* These macros wrap options_get_dir_fname2_suffix to provide a more + * convenient API for finding filenames that Tor uses inside its storage + * They are named according to a pattern: + * (options_)?get_(cache|key|data)dir_fname(2)?(_suffix)? + * + * Macros that begin with options_ take an options argument; the others + * work with respect to the global options. + * + * Each macro works relative to the data directory, the key directory, + * or the cache directory, as determined by which one is mentioned. + * + * Macro variants with "2" in their name take two path components; others + * take one. + * + * Macro variants with "_suffix" at the end take an additional suffix + * that gets appended to the end of the file + */ +#define options_get_datadir_fname2_suffix(options, sub1, sub2, suffix) \ + options_get_dir_fname2_suffix((options), DIRROOT_DATADIR, \ + (sub1), (sub2), (suffix)) +#define options_get_cachedir_fname2_suffix(options, sub1, sub2, suffix) \ + options_get_dir_fname2_suffix((options), DIRROOT_CACHEDIR, \ + (sub1), (sub2), (suffix)) +#define options_get_keydir_fname2_suffix(options, sub1, sub2, suffix) \ + options_get_dir_fname2_suffix((options), DIRROOT_KEYDIR, \ + (sub1), (sub2), (suffix)) + #define options_get_datadir_fname(opts,sub1) \ options_get_datadir_fname2_suffix((opts),(sub1), NULL, NULL) -/** Return a newly allocated string containing datadir/sub1/sub2 relative to - * opts. See get_datadir_fname2_suffix. */ #define options_get_datadir_fname2(opts,sub1,sub2) \ options_get_datadir_fname2_suffix((opts),(sub1), (sub2), NULL) -/** DOCDOC */ -#define get_keydir_fname(sub1) \ - get_datadir_fname2("keys", (sub1)) -#define options_get_keydir_fname(options, sub1) \ - options_get_datadir_fname2((options), "keys", (sub1)) -#define get_keydir_fname_suffix(sub1, suffix) \ - get_datadir_fname2_suffix("keys", (sub1), (suffix)) +#define get_datadir_fname2_suffix(sub1, sub2, suffix) \ + options_get_datadir_fname2_suffix(get_options(), (sub1), (sub2), (suffix)) +#define get_datadir_fname(sub1) \ + get_datadir_fname2_suffix((sub1), NULL, NULL) +#define get_datadir_fname2(sub1,sub2) \ + get_datadir_fname2_suffix((sub1), (sub2), NULL) +#define get_datadir_fname_suffix(sub1, suffix) \ + get_datadir_fname2_suffix((sub1), NULL, (suffix)) -#define get_cachedir_fname(sub1) get_datadir_fname((sub1)) +/** DOCDOC */ +#define options_get_keydir_fname(options, sub1) \ + options_get_keydir_fname2_suffix((options), (sub1), NULL, NULL) +#define get_keydir_fname_suffix(sub1, suffix) \ + options_get_keydir_fname2_suffix(get_options(), (sub1), NULL, suffix) +#define get_keydir_fname(sub1) \ + options_get_keydir_fname2_suffix(get_options(), (sub1), NULL, NULL) + +#define get_cachedir_fname(sub1) \ + options_get_cachedir_fname2_suffix(get_options(), (sub1), NULL, NULL) #define get_cachedir_fname_suffix(sub1, suffix) \ - get_datadir_fname_suffix((sub1), (suffix)) + options_get_cachedir_fname2_suffix(get_options(), (sub1), NULL, (suffix)) int using_default_dir_authorities(const or_options_t *options); diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c index ddb1bc53c1..ffec3149b0 100644 --- a/src/test/test_conscache.c +++ b/src/test/test_conscache.c @@ -31,8 +31,8 @@ test_conscache_simple_usage(void *arg) /* Make a temporary datadir for these tests */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = tor_strdup(ddir_fname); + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname); check_private_dir(ddir_fname, CPD_CREATE, NULL); consensus_cache_t *cache = consensus_cache_open("cons", 128); @@ -124,8 +124,8 @@ test_conscache_cleanup(void *arg) /* Make a temporary datadir for these tests */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = tor_strdup(ddir_fname); + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname); check_private_dir(ddir_fname, CPD_CREATE, NULL); consensus_cache_t *cache = consensus_cache_open("cons", 128); @@ -267,8 +267,8 @@ test_conscache_filter(void *arg) /* Make a temporary datadir for these tests */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = tor_strdup(ddir_fname); + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname); check_private_dir(ddir_fname, CPD_CREATE, NULL); consensus_cache_t *cache = consensus_cache_open("cons", 128); diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c index 80d3f943ab..a9a4b6a98e 100644 --- a/src/test/test_consdiffmgr.c +++ b/src/test/test_consdiffmgr.c @@ -24,8 +24,8 @@ consdiffmgr_test_setup(const struct testcase_t *arg) { (void)arg; char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cdm")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = ddir_fname; // now owns the pointer. + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = ddir_fname; // now owns the pointer. check_private_dir(ddir_fname, CPD_CREATE, NULL); consdiff_cfg_t consdiff_cfg = { 300 }; @@ -215,8 +215,8 @@ test_consdiffmgr_init_failure(void *arg) /* As in ...test_setup, but do not create the datadir. The missing directory * will cause a failure. */ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cdm")); - tor_free(get_options_mutable()->DataDirectory); - get_options_mutable()->DataDirectory = ddir_fname; // now owns the pointer. + tor_free(get_options_mutable()->CacheDirectory); + get_options_mutable()->CacheDirectory = ddir_fname; // now owns the pointer. consdiff_cfg_t consdiff_cfg = { 7200, 300 }; diff --git a/src/test/test_dir.c b/src/test/test_dir.c index ee4a9780b1..83734ccfd9 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -4874,9 +4874,11 @@ mock_check_private_dir(const char *dirname, cpd_check_t check, static char * mock_get_datadir_fname(const or_options_t *options, + directory_root_t roottype, const char *sub1, const char *sub2, const char *suffix) { + (void) roottype; char *rv = NULL; /* @@ -5033,7 +5035,7 @@ test_dir_dump_unparseable_descriptors(void *data) mock_options->MaxUnparseableDescSizeToLog = 1536; MOCK(get_options, mock_get_options); MOCK(check_private_dir, mock_check_private_dir); - MOCK(options_get_datadir_fname2_suffix, + MOCK(options_get_dir_fname2_suffix, mock_get_datadir_fname); /* @@ -5551,7 +5553,7 @@ test_dir_dump_unparseable_descriptors(void *data) mock_unlink_reset(); UNMOCK(write_str_to_file); mock_write_str_to_file_reset(); - UNMOCK(options_get_datadir_fname2_suffix); + UNMOCK(options_get_dir_fname2_suffix); UNMOCK(check_private_dir); UNMOCK(get_options); tor_free(mock_options); diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index fe26657ad8..28ecc14c49 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -469,6 +469,7 @@ init_mock_options(void) memset(mock_options, 0, sizeof(or_options_t)); mock_options->TestingTorNetwork = 1; mock_options->DataDirectory = tor_strdup(get_fname_rnd("datadir_tmp")); + mock_options->CacheDirectory = tor_strdup(mock_options->DataDirectory); check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL); } diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 4f0ecd778b..59b28f7580 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -69,12 +69,12 @@ test_md_cache(void *data) time3 = time(NULL) - 15*24*60*60; /* Possibly, turn this into a test setup/cleanup pair */ - tor_free(options->DataDirectory); - options->DataDirectory = tor_strdup(get_fname("md_datadir_test")); + tor_free(options->CacheDirectory); + options->CacheDirectory = tor_strdup(get_fname("md_datadir_test")); #ifdef _WIN32 - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory)); #else - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700)); #endif tt_assert(!strcmpstart(test_md3_noannotation, "onion-key")); @@ -152,7 +152,7 @@ test_md_cache(void *data) strlen(test_md3_noannotation)); tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new", - options->DataDirectory); + options->CacheDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_assert(s); tt_mem_op(md1->body, OP_EQ, s + md1->off, md1->bodylen); @@ -180,7 +180,7 @@ test_md_cache(void *data) /* read the cache. */ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs", - options->DataDirectory); + options->CacheDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1)); tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2)); @@ -234,7 +234,7 @@ test_md_cache(void *data) done: if (options) - tor_free(options->DataDirectory); + tor_free(options->CacheDirectory); microdesc_free_all(); smartlist_free(added); @@ -266,17 +266,17 @@ test_md_cache_broken(void *data) options = get_options_mutable(); tt_assert(options); - tor_free(options->DataDirectory); - options->DataDirectory = tor_strdup(get_fname("md_datadir_test2")); + tor_free(options->CacheDirectory); + options->CacheDirectory = tor_strdup(get_fname("md_datadir_test2")); #ifdef _WIN32 - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory)); #else - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700)); #endif tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs", - options->DataDirectory); + options->CacheDirectory); write_str_to_file(fn, truncated_md, 1); @@ -285,7 +285,7 @@ test_md_cache_broken(void *data) done: if (options) - tor_free(options->DataDirectory); + tor_free(options->CacheDirectory); tor_free(fn); microdesc_free_all(); } @@ -754,8 +754,8 @@ test_md_reject_cache(void *arg) or_options_t *options = get_options_mutable(); char buf[DIGEST256_LEN]; - tor_free(options->DataDirectory); - options->DataDirectory = tor_strdup(get_fname("md_datadir_test_rej")); + tor_free(options->CacheDirectory); + options->CacheDirectory = tor_strdup(get_fname("md_datadir_test_rej")); mock_rgsbd_val_a = tor_malloc_zero(sizeof(routerstatus_t)); mock_rgsbd_val_b = tor_malloc_zero(sizeof(routerstatus_t)); mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t)); @@ -765,9 +765,9 @@ test_md_reject_cache(void *arg) mock_ns_val->flavor = FLAV_MICRODESC; #ifdef _WIN32 - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory)); #else - tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700)); + tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700)); #endif MOCK(router_get_mutable_consensus_status_by_descriptor_digest, @@ -802,7 +802,7 @@ test_md_reject_cache(void *arg) done: UNMOCK(networkstatus_get_latest_consensus_by_flavor); UNMOCK(router_get_mutable_consensus_status_by_descriptor_digest); - tor_free(options->DataDirectory); + tor_free(options->CacheDirectory); microdesc_free_all(); smartlist_free(added); SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp)); diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index d8b72651a0..e4abcdb92d 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -421,6 +421,7 @@ test_routerkeys_ed_keys_init_all(void *arg) { (void)arg; char *dir = tor_strdup(get_fname("test_ed_keys_init_all")); + char *keydir = tor_strdup(get_fname("test_ed_keys_init_all/KEYS")); or_options_t *options = tor_malloc_zero(sizeof(or_options_t)); time_t now = time(NULL); ed25519_public_key_t id; @@ -445,13 +446,14 @@ test_routerkeys_ed_keys_init_all(void *arg) #ifdef _WIN32 mkdir(dir); - mkdir(get_fname("test_ed_keys_init_all/keys")); + mkdir(keydir); #else mkdir(dir, 0700); - mkdir(get_fname("test_ed_keys_init_all/keys"), 0700); + mkdir(keydir, 0700); #endif /* defined(_WIN32) */ options->DataDirectory = dir; + options->KeyDirectory = keydir; tt_int_op(1, OP_EQ, load_ed_keys(options, now)); tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0)); @@ -521,7 +523,7 @@ test_routerkeys_ed_keys_init_all(void *arg) /* Demonstrate that we can start up with no secret identity key */ routerkeys_free_all(); - unlink(get_fname("test_ed_keys_init_all/keys/" + unlink(get_fname("test_ed_keys_init_all/KEYS/" "ed25519_master_id_secret_key")); tt_int_op(1, OP_EQ, load_ed_keys(options, now)); tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0)); @@ -542,6 +544,7 @@ test_routerkeys_ed_keys_init_all(void *arg) done: tor_free(dir); + tor_free(keydir); tor_free(options); tor_cert_free(link_cert); routerkeys_free_all(); diff --git a/src/test/testing_common.c b/src/test/testing_common.c index e43fa46c84..142c681079 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -293,6 +293,9 @@ main(int c, const char **v) setup_directory(); options_init(options); options->DataDirectory = tor_strdup(temp_dir); + tor_asprintf(&options->KeyDirectory, "%s"PATH_SEPARATOR"keys", + options->DataDirectory); + options->CacheDirectory = tor_strdup(temp_dir); options->EntryStatistics = 1; if (set_options(options, &errmsg) < 0) { printf("Failed to set initial options: %s\n", errmsg); From 02cbf2ffc18d4babbc9ed15b87cf040595bb2285 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 18:24:15 -0500 Subject: [PATCH 10/11] Update the manpage to describe {Cache,Key}Directory Also, explain which files should be put in which. --- doc/tor.1.txt | 71 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 725baaa643..17bdaeb0df 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -415,6 +415,16 @@ GENERAL OPTIONS DataDirectory. If the option is set to 1, make the DataDirectory readable by the default GID. (Default: 0) +[[CacheDirectory]] **CacheDirectory** __DIR__:: + Store cached directory data in DIR. Can not be changed while tor is + running. + (Default: uses the value of DataDirectory.) + +[[CacheDirectoryGroupReadable]] **CacheDirectoryGroupReadable** **0**|**1**:: + If this option is set to 0, don't allow the filesystem group to read the + CacheDirectory. If the option is set to 1, make the CacheDirectory readable + by the default GID. (Default: 0) + [[FallbackDir]] **FallbackDir** __ipv4address__:__port__ orport=__port__ id=__fingerprint__ [weight=__num__] [ipv6=**[**__ipv6address__**]**:__orport__]:: When we're unable to connect to any directory cache for directory info (usually because we don't know about any yet) we try a directory authority. @@ -2219,6 +2229,17 @@ is non-zero): ed25519 master identity key, as well as the corresponding temporary signing keys and certificates. (Default: 0) +[[KeyDirectory]] **KeyDirectory** __DIR__:: + Store secret keys in DIR. Can not be changed while tor is + running. + (Default: the "keys" subdirectory of DataDirectory.) + +[[KeyDirectoryGroupReadable]] **KeyDirectoryGroupReadable** **0**|**1**:: + If this option is set to 0, don't allow the filesystem group to read the + KeywDirectory. If the option is set to 1, make the KeyDirectory readable + by the default GID. (Default: 0) + + DIRECTORY SERVER OPTIONS ------------------------ @@ -2883,40 +2904,35 @@ FILES **@LOCALSTATEDIR@/lib/tor/**:: The tor process stores keys and other data here. -__DataDirectory__**/cached-status/**:: - The most recently downloaded network status document for each authority. - Each file holds one such document; the filenames are the hexadecimal - identity key fingerprints of the directory authorities. Obsolete; - no longer in use. -__DataDirectory__**/cached-certs**:: +__CacheDirectory__**/cached-certs**:: This file holds downloaded directory key certificates that are used to verify authenticity of documents generated by Tor directory authorities. -__DataDirectory__**/cached-consensus** and/or **cached-microdesc-consensus**:: +__CacheDirectory__**/cached-consensus** and/or **cached-microdesc-consensus**:: The most recent consensus network status document we've downloaded. -__DataDirectory__**/cached-descriptors** and **cached-descriptors.new**:: +__CacheDirectory__**/cached-descriptors** and **cached-descriptors.new**:: These files hold downloaded router statuses. Some routers may appear more than once; if so, the most recently published descriptor is used. Lines beginning with @-signs are annotations that contain more information about a given router. The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-descriptors file. -__DataDirectory__**/cached-extrainfo** and **cached-extrainfo.new**:: +__CacheDirectory__**/cached-extrainfo** and **cached-extrainfo.new**:: As "cached-descriptors", but holds optionally-downloaded "extra-info" documents. Relays use these documents to send inessential information about statistics, bandwidth history, and network health to the authorities. They aren't fetched by default; see the DownloadExtraInfo option for more info. -__DataDirectory__**/cached-microdescs** and **cached-microdescs.new**:: +__CacheDirectory__**/cached-microdescs** and **cached-microdescs.new**:: These files hold downloaded microdescriptors. Lines beginning with @-signs are annotations that contain more information about a given router. The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-microdescs file. -__DataDirectory__**/cached-routers** and **cached-routers.new**:: +__CacheDirectory__**/cached-routers** and **cached-routers.new**:: Obsolete versions of cached-descriptors and cached-descriptors.new. When Tor can't find the newer files, it looks here instead. @@ -2934,7 +2950,7 @@ __DataDirectory__**/sr-state**:: Authority only. State file used to record information about the current status of the shared-random-value voting state. -__DataDirectory__**/diff-cache**:: +__CacheDirectory__**/diff-cache**:: Directory cache only. Holds older consensuses, and diffs from older consensuses to the most recent consensus of each type, compressed in various ways. Each file contains a set of key-value arguments @@ -2964,63 +2980,60 @@ __DataDirectory__**/key-pinning-journal**:: or factoring the RSA1024 key will no longer let an attacker impersonate the relay. -__DataDirectory__**/keys/***:: - Only used by servers. Holds identity keys and onion keys. - -__DataDirectory__**/keys/authority_identity_key**:: +__KeyDirectory__**/authority_identity_key**:: A v3 directory authority's master identity key, used to authenticate its signing key. Tor doesn't use this while it's running. The tor-gencert program uses this. If you're running an authority, you should keep this key offline, and not actually put it here. -__DataDirectory__**/keys/authority_certificate**:: +__KeyDirectory__**/authority_certificate**:: A v3 directory authority's certificate, which authenticates the authority's current vote- and consensus-signing key using its master identity key. Only directory authorities use this file. -__DataDirectory__**/keys/authority_signing_key**:: +__KeyDirectory__**/authority_signing_key**:: A v3 directory authority's signing key, used to sign votes and consensuses. Only directory authorities use this file. Corresponds to the **authority_certificate** cert. -__DataDirectory__**/keys/legacy_certificate**:: +__KeyDirectory__**/legacy_certificate**:: As authority_certificate: used only when V3AuthUseLegacyKey is set. See documentation for V3AuthUseLegacyKey. -__DataDirectory__**/keys/legacy_signing_key**:: +__KeyDirectory__**/legacy_signing_key**:: As authority_signing_key: used only when V3AuthUseLegacyKey is set. See documentation for V3AuthUseLegacyKey. -__DataDirectory__**/keys/secret_id_key**:: +__KeyDirectory__**/secret_id_key**:: A relay's RSA1024 permanent identity key, including private and public components. Used to sign router descriptors, and to sign other keys. -__DataDirectory__**/keys/ed25519_master_id_public_key**:: +__KeyDirectory__**/ed25519_master_id_public_key**:: The public part of a relay's Ed25519 permanent identity key. -__DataDirectory__**/keys/ed25519_master_id_secret_key**:: +__KeyDirectory__**/ed25519_master_id_secret_key**:: The private part of a relay's Ed25519 permanent identity key. This key is used to sign the medium-term ed25519 signing key. This file can be kept offline, or kept encrypted. If so, Tor will not be able to generate new signing keys itself; you'll need to use tor --keygen yourself to do so. -__DataDirectory__**/keys/ed25519_signing_secret_key**:: +__KeyDirectory__**/ed25519_signing_secret_key**:: The private and public components of a relay's medium-term Ed25519 signing key. This key is authenticated by the Ed25519 master key, in turn authenticates other keys (and router descriptors). -__DataDirectory__**/keys/ed25519_signing_cert**:: +__KeyDirectory__**/ed25519_signing_cert**:: The certificate which authenticates "ed25519_signing_secret_key" as having been signed by the Ed25519 master key. -__DataDirectory__**/keys/secret_onion_key** and **secret_onion_key.old**:: +__KeyDirectory__**/secret_onion_key** and **secret_onion_key.old**:: A relay's RSA1024 short-term onion key. Used to decrypt old-style ("TAP") circuit extension requests. The ".old" file holds the previously generated key, which the relay uses to handle any requests that were made by clients that didn't have the new one. -__DataDirectory__**/keys/secret_onion_key_ntor** and **secret_onion_key_ntor.old**:: +__KeyDirectory__**/secret_onion_key_ntor** and **secret_onion_key_ntor.old**:: A relay's Curve25519 short-term onion key. Used to handle modern ("ntor") circuit extension requests. The ".old" file holds the previously generated key, which the relay uses to handle any requests that were @@ -3047,11 +3060,11 @@ __DataDirectory__**/v3-status-votes**:: Only for v3 authoritative directory servers. This file contains status votes from all the authoritative directory servers. -__DataDirectory__**/unverified-consensus**:: +__CacheDirectory__**/unverified-consensus**:: This file contains a network consensus document that has been downloaded, but which we didn't have the right certificates to check yet. -__DataDirectory__**/unverified-microdesc-consensus**:: +__CacheDirectory__**/unverified-microdesc-consensus**:: This file contains a microdescriptor-flavored network consensus document that has been downloaded, but which we didn't have the right certificates to check yet. From 46f167886a44bef90021fb54e4687200cdd8b5a2 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 Nov 2017 18:27:18 -0500 Subject: [PATCH 11/11] add a changes file --- changes/ticket22703 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket22703 diff --git a/changes/ticket22703 b/changes/ticket22703 new file mode 100644 index 0000000000..c1eda615f5 --- /dev/null +++ b/changes/ticket22703 @@ -0,0 +1,6 @@ + o Major features (storage): + - Users can choose to store cached directory documents somewhere other + than the DataDirectory by using the CacheDirectory option. + Similarly, the storage location for relay's keys can be overridden + with the KeyDirectory option. + Closes ticket 22703.