1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
10 * \brief Read configuration files from disk, with full `%include` support.
13 #include "lib/fs/conffile.h"
15 #include "lib/container/smartlist.h"
16 #include "lib/encoding/confline.h"
17 #include "lib/fs/dir.h"
18 #include "lib/fs/files.h"
19 #include "lib/fs/path.h"
20 #include "lib/log/log.h"
21 #include "lib/malloc/malloc.h"
22 #include "lib/sandbox/sandbox.h"
23 #include "lib/string/printf.h"
28 static smartlist_t
*config_get_file_list(const char *path
,
29 smartlist_t
*opened_files
);
30 static int config_get_included_config(const char *path
, int recursion_level
,
31 int extended
, config_line_t
**config
,
32 config_line_t
**config_last
,
33 smartlist_t
*opened_lst
);
34 static int config_process_include(const char *path
, int recursion_level
,
35 int extended
, config_line_t
**list
,
36 config_line_t
**list_last
,
37 smartlist_t
*opened_lst
);
39 /** Helper: parse the config string and strdup into key/value
40 * strings. Set *result to the list, or NULL if parsing the string
41 * failed. Set *has_include to 1 if <b>result</b> has values from
42 * %included files. <b>opened_lst</b> will have a list of opened files if
43 * provided. Return 0 on success, -1 on failure. Warn and ignore any
46 * If <b>extended</b> is set, then treat keys beginning with / and with + as
47 * indicating "clear" and "append" respectively. */
49 config_get_lines_include(const char *string
, config_line_t
**result
,
50 int extended
, int *has_include
,
51 smartlist_t
*opened_lst
)
53 return config_get_lines_aux(string
, result
, extended
, 1, has_include
,
54 opened_lst
, 1, NULL
, config_process_include
);
57 /** Return a list of paths obtained when expading globs in <b>pattern</b>.
58 * If <b>pattern</b> has no globs, return a list with <b>pattern</b> in it.
59 * If <b>opened_files</b> is provided, add paths opened by glob to it.
60 * Return NULL on failure. */
62 expand_glob(const char *pattern
, smartlist_t
*opened_files
)
64 if (! has_glob(pattern
)) {
65 smartlist_t
*matches
= smartlist_new();
66 smartlist_add_strdup(matches
, pattern
);
70 smartlist_t
*matches
= tor_glob(pattern
);
73 log_err(LD_CONFIG
, "Sandbox is active, but the configuration pattern "
74 "\"%s\" listed with %%include would access files or folders not "
75 "allowed by it. Cannot proceed.", pattern
);
81 smartlist_t
*glob_opened
= get_glob_opened_files(pattern
);
83 SMARTLIST_FOREACH(matches
, char *, f
, tor_free(f
));
84 smartlist_free(matches
);
87 smartlist_add_all(opened_files
, glob_opened
);
88 smartlist_free(glob_opened
);
90 smartlist_sort_strings(matches
);
94 /** Returns a list of configuration files present on paths that match
95 * <b>pattern</b>. The pattern is expanded and then all the paths are
96 * processed. A path can be a file or a directory. If it is a file, that file
97 * will be added to the list to be returned. If it is a directory,
98 * all paths for files on that directory root (no recursion) except for files
99 * whose name starts with a dot will be added to the list to be returned.
100 * <b>opened_files</b> will have a list of files opened by this function
101 * if provided. Return NULL on failure. Ignores empty files.
104 config_get_file_list(const char *pattern
, smartlist_t
*opened_files
)
106 smartlist_t
*glob_matches
= expand_glob(pattern
, opened_files
);
111 bool error_found
= false;
112 smartlist_t
*file_list
= smartlist_new();
113 SMARTLIST_FOREACH_BEGIN(glob_matches
, char *, path
) {
115 smartlist_add_strdup(opened_files
, path
);
117 if (sandbox_interned_string_is_missing(path
)) {
118 log_err(LD_CONFIG
, "Sandbox is active, but a new configuration "
119 "file \"%s\" has been listed with %%include. Cannot proceed.",
125 file_status_t file_type
= file_status(path
);
126 if (file_type
== FN_FILE
) {
127 smartlist_add_strdup(file_list
, path
);
128 } else if (file_type
== FN_DIR
) {
129 smartlist_t
*all_files
= tor_listdir(path
);
134 smartlist_sort_strings(all_files
);
135 SMARTLIST_FOREACH_BEGIN(all_files
, char *, f
) {
141 tor_asprintf(&fullname
, "%s"PATH_SEPARATOR
"%s", path
, f
);
144 smartlist_add_strdup(opened_files
, fullname
);
147 if (file_status(fullname
) != FN_FILE
) {
151 smartlist_add(file_list
, fullname
);
152 } SMARTLIST_FOREACH_END(f
);
153 SMARTLIST_FOREACH(all_files
, char *, f
, tor_free(f
));
154 smartlist_free(all_files
);
155 } else if (file_type
== FN_EMPTY
) {
161 } SMARTLIST_FOREACH_END(path
);
162 SMARTLIST_FOREACH(glob_matches
, char *, f
, tor_free(f
));
163 smartlist_free(glob_matches
);
166 SMARTLIST_FOREACH(file_list
, char *, f
, tor_free(f
));
167 smartlist_free(file_list
);
174 /** Creates a list of config lines present on included <b>path</b>.
175 * Set <b>config</b> to the list and <b>config_last</b> to the last element of
176 * <b>config</b>. <b>opened_lst</b> will have a list of opened files if
177 * provided. Return 0 on success, -1 on failure. */
179 config_get_included_config(const char *path
, int recursion_level
, int extended
,
180 config_line_t
**config
, config_line_t
**config_last
,
181 smartlist_t
*opened_lst
)
183 char *included_conf
= read_file_to_str(path
, 0, NULL
);
184 if (!included_conf
) {
188 if (config_get_lines_aux(included_conf
, config
, extended
, 1, NULL
,
189 opened_lst
, recursion_level
+1, config_last
,
190 config_process_include
) < 0) {
191 tor_free(included_conf
);
195 tor_free(included_conf
);
199 /** Process an %include <b>pattern</b> in a config file. Set <b>list</b> to the
200 * list of configuration settings obtained and <b>list_last</b> to the last
201 * element of the same list. <b>opened_lst</b> will have a list of opened
202 * files if provided. Return 0 on success, -1 on failure. */
204 config_process_include(const char *pattern
, int recursion_level
, int extended
,
205 config_line_t
**list
, config_line_t
**list_last
,
206 smartlist_t
*opened_lst
)
208 config_line_t
*ret_list
= NULL
;
209 config_line_t
**next
= &ret_list
;
211 smartlist_t
*config_files
= config_get_file_list(pattern
, opened_lst
);
217 SMARTLIST_FOREACH_BEGIN(config_files
, const char *, config_file
) {
218 if (sandbox_interned_string_is_missing(config_file
)) {
219 log_err(LD_CONFIG
, "Sandbox is active, but a new configuration "
220 "file \"%s\" has been listed with %%include. Cannot proceed.",
225 log_notice(LD_CONFIG
, "Including configuration file \"%s\".", config_file
);
226 config_line_t
*included_config
= NULL
;
227 config_line_t
*included_config_last
= NULL
;
228 if (config_get_included_config(config_file
, recursion_level
, extended
,
229 &included_config
, &included_config_last
,
234 *next
= included_config
;
235 if (included_config_last
) {
236 next
= &included_config_last
->next
;
237 *list_last
= included_config_last
;
239 } SMARTLIST_FOREACH_END(config_file
);
244 SMARTLIST_FOREACH(config_files
, char *, f
, tor_free(f
));
245 smartlist_free(config_files
);