diff options
Diffstat (limited to 'src/lib/fs/conffile.c')
-rw-r--r-- | src/lib/fs/conffile.c | 165 |
1 files changed, 118 insertions, 47 deletions
diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c index 0d5d56b335..0d0bdf09a6 100644 --- a/src/lib/fs/conffile.c +++ b/src/lib/fs/conffile.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,8 +19,12 @@ #include "lib/fs/path.h" #include "lib/log/log.h" #include "lib/malloc/malloc.h" +#include "lib/sandbox/sandbox.h" #include "lib/string/printf.h" +#include <stdbool.h> +#include <errno.h> + static smartlist_t *config_get_file_list(const char *path, smartlist_t *opened_files); static int config_get_included_config(const char *path, int recursion_level, @@ -50,62 +54,121 @@ config_get_lines_include(const char *string, config_line_t **result, opened_lst, 1, NULL, config_process_include); } -/** Adds a list of configuration files present on <b>path</b> to - * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file, - * only that file will be added to <b>file_list</b>. If it is a directory, - * all paths for files on that directory root (no recursion) except for files - * whose name starts with a dot will be added to <b>file_list</b>. - * <b>opened_files</b> will have a list of files opened by this function - * if provided. Return 0 on success, -1 on failure. Ignores empty files. - */ +/** Return a list of paths obtained when expading globs in <b>pattern</b>. + * If <b>pattern</b> has no globs, return a list with <b>pattern</b> in it. + * If <b>opened_files</b> is provided, add paths opened by glob to it. + * Return NULL on failure. */ static smartlist_t * -config_get_file_list(const char *path, smartlist_t *opened_files) +expand_glob(const char *pattern, smartlist_t *opened_files) { - smartlist_t *file_list = smartlist_new(); + if (! has_glob(pattern)) { + smartlist_t *matches = smartlist_new(); + smartlist_add_strdup(matches, pattern); + return matches; + } - if (opened_files) { - smartlist_add_strdup(opened_files, path); + smartlist_t *matches = tor_glob(pattern); + if (!matches) { + if (errno == EPERM) { + log_err(LD_CONFIG, "Sandbox is active, but the configuration pattern " + "\"%s\" listed with %%include would access files or folders not " + "allowed by it. Cannot proceed.", pattern); + } + return NULL; } - file_status_t file_type = file_status(path); - if (file_type == FN_FILE) { - smartlist_add_strdup(file_list, path); - return file_list; - } else if (file_type == FN_DIR) { - smartlist_t *all_files = tor_listdir(path); - if (!all_files) { - smartlist_free(file_list); + if (opened_files) { + smartlist_t *glob_opened = get_glob_opened_files(pattern); + if (!glob_opened) { + SMARTLIST_FOREACH(matches, char *, f, tor_free(f)); + smartlist_free(matches); return NULL; } - smartlist_sort_strings(all_files); - SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { - if (f[0] == '.') { - tor_free(f); - continue; - } + smartlist_add_all(opened_files, glob_opened); + smartlist_free(glob_opened); + } + smartlist_sort_strings(matches); + return matches; +} + +/** Returns a list of configuration files present on paths that match + * <b>pattern</b>. The pattern is expanded and then all the paths are + * processed. A path can be a file or a directory. If it is a file, that file + * will be added to the list to be returned. If it is a directory, + * all paths for files on that directory root (no recursion) except for files + * whose name starts with a dot will be added to the list to be returned. + * <b>opened_files</b> will have a list of files opened by this function + * if provided. Return NULL on failure. Ignores empty files. + */ +static smartlist_t * +config_get_file_list(const char *pattern, smartlist_t *opened_files) +{ + smartlist_t *glob_matches = expand_glob(pattern, opened_files); + if (!glob_matches) { + return NULL; + } - char *fullname; - tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); - tor_free(f); + bool error_found = false; + smartlist_t *file_list = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(glob_matches, char *, path) { + if (opened_files) { + smartlist_add_strdup(opened_files, path); + } + if (sandbox_interned_string_is_missing(path)) { + log_err(LD_CONFIG, "Sandbox is active, but a new configuration " + "file \"%s\" has been listed with %%include. Cannot proceed.", + path); + error_found = true; + break; + } - if (opened_files) { - smartlist_add_strdup(opened_files, fullname); + file_status_t file_type = file_status(path); + if (file_type == FN_FILE) { + smartlist_add_strdup(file_list, path); + } else if (file_type == FN_DIR) { + smartlist_t *all_files = tor_listdir(path); + if (!all_files) { + error_found = true; + break; } - - if (file_status(fullname) != FN_FILE) { - tor_free(fullname); + smartlist_sort_strings(all_files); + SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { + if (f[0] == '.') { + continue; + } + + char *fullname; + tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); + + if (opened_files) { + smartlist_add_strdup(opened_files, fullname); + } + + if (file_status(fullname) != FN_FILE) { + tor_free(fullname); + continue; + } + smartlist_add(file_list, fullname); + } SMARTLIST_FOREACH_END(f); + SMARTLIST_FOREACH(all_files, char *, f, tor_free(f)); + smartlist_free(all_files); + } else if (file_type == FN_EMPTY) { continue; - } - smartlist_add(file_list, fullname); - } SMARTLIST_FOREACH_END(f); - smartlist_free(all_files); - return file_list; - } else if (file_type == FN_EMPTY) { - return file_list; - } else { + } else { + error_found = true; + break; + } + } SMARTLIST_FOREACH_END(path); + SMARTLIST_FOREACH(glob_matches, char *, f, tor_free(f)); + smartlist_free(glob_matches); + + if (error_found) { + SMARTLIST_FOREACH(file_list, char *, f, tor_free(f)); smartlist_free(file_list); - return NULL; + file_list = NULL; } + + return file_list; } /** Creates a list of config lines present on included <b>path</b>. @@ -133,25 +196,33 @@ config_get_included_config(const char *path, int recursion_level, int extended, return 0; } -/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the +/** Process an %include <b>pattern</b> in a config file. Set <b>list</b> to the * list of configuration settings obtained and <b>list_last</b> to the last * element of the same list. <b>opened_lst</b> will have a list of opened * files if provided. Return 0 on success, -1 on failure. */ static int -config_process_include(const char *path, int recursion_level, int extended, +config_process_include(const char *pattern, int recursion_level, int extended, config_line_t **list, config_line_t **list_last, smartlist_t *opened_lst) { config_line_t *ret_list = NULL; config_line_t **next = &ret_list; - smartlist_t *config_files = config_get_file_list(path, opened_lst); + smartlist_t *config_files = config_get_file_list(pattern, opened_lst); if (!config_files) { return -1; } int rv = -1; SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { + if (sandbox_interned_string_is_missing(config_file)) { + log_err(LD_CONFIG, "Sandbox is active, but a new configuration " + "file \"%s\" has been listed with %%include. Cannot proceed.", + config_file); + goto done; + } + + log_notice(LD_CONFIG, "Including configuration file \"%s\".", config_file); config_line_t *included_config = NULL; config_line_t *included_config_last = NULL; if (config_get_included_config(config_file, recursion_level, extended, |