Tor 0.4.9.0-alpha-dev
conffile.c
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 */
6
7/**
8 * \file conffile.h
9 *
10 * \brief Read configuration files from disk, with full `%include` support.
11 **/
12
13#include "lib/fs/conffile.h"
14
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"
24
25#include <stdbool.h>
26#include <errno.h>
27
28static smartlist_t *config_get_file_list(const char *path,
29 smartlist_t *opened_files);
30static 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);
34static 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);
38
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
44 * misformatted lines.
45 *
46 * If <b>extended</b> is set, then treat keys beginning with / and with + as
47 * indicating "clear" and "append" respectively. */
48int
49config_get_lines_include(const char *string, config_line_t **result,
50 int extended, int *has_include,
51 smartlist_t *opened_lst)
52{
53 return config_get_lines_aux(string, result, extended, 1, has_include,
54 opened_lst, 1, NULL, config_process_include);
55}
56
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. */
61static smartlist_t *
62expand_glob(const char *pattern, smartlist_t *opened_files)
63{
64 if (! has_glob(pattern)) {
65 smartlist_t *matches = smartlist_new();
66 smartlist_add_strdup(matches, pattern);
67 return matches;
68 }
69
70 smartlist_t *matches = tor_glob(pattern);
71 if (!matches) {
72 if (errno == EPERM) {
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);
76 }
77 return NULL;
78 }
79
80 if (opened_files) {
81 smartlist_t *glob_opened = get_glob_opened_files(pattern);
82 if (!glob_opened) {
83 SMARTLIST_FOREACH(matches, char *, f, tor_free(f));
84 smartlist_free(matches);
85 return NULL;
86 }
87 smartlist_add_all(opened_files, glob_opened);
88 smartlist_free(glob_opened);
89 }
91 return matches;
92}
93
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.
102 */
103static smartlist_t *
104config_get_file_list(const char *pattern, smartlist_t *opened_files)
105{
106 smartlist_t *glob_matches = expand_glob(pattern, opened_files);
107 if (!glob_matches) {
108 return NULL;
109 }
110
111 bool error_found = false;
112 smartlist_t *file_list = smartlist_new();
113 SMARTLIST_FOREACH_BEGIN(glob_matches, char *, path) {
114 if (opened_files) {
115 smartlist_add_strdup(opened_files, path);
116 }
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.",
120 path);
121 error_found = true;
122 break;
123 }
124
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);
130 if (!all_files) {
131 error_found = true;
132 break;
133 }
134 smartlist_sort_strings(all_files);
135 SMARTLIST_FOREACH_BEGIN(all_files, char *, f) {
136 if (f[0] == '.') {
137 continue;
138 }
139
140 char *fullname;
141 tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
142
143 if (opened_files) {
144 smartlist_add_strdup(opened_files, fullname);
145 }
146
147 if (file_status(fullname) != FN_FILE) {
148 tor_free(fullname);
149 continue;
150 }
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) {
156 continue;
157 } else {
158 error_found = true;
159 break;
160 }
161 } SMARTLIST_FOREACH_END(path);
162 SMARTLIST_FOREACH(glob_matches, char *, f, tor_free(f));
163 smartlist_free(glob_matches);
164
165 if (error_found) {
166 SMARTLIST_FOREACH(file_list, char *, f, tor_free(f));
167 smartlist_free(file_list);
168 file_list = NULL;
169 }
170
171 return file_list;
172}
173
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. */
178static int
179config_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)
182{
183 char *included_conf = read_file_to_str(path, 0, NULL);
184 if (!included_conf) {
185 return -1;
186 }
187
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);
192 return -1;
193 }
194
195 tor_free(included_conf);
196 return 0;
197}
198
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. */
203static int
204config_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)
207{
208 config_line_t *ret_list = NULL;
209 config_line_t **next = &ret_list;
210
211 smartlist_t *config_files = config_get_file_list(pattern, opened_lst);
212 if (!config_files) {
213 return -1;
214 }
215
216 int rv = -1;
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.",
221 config_file);
222 goto done;
223 }
224
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,
230 opened_lst) < 0) {
231 goto done;
232 }
233
234 *next = included_config;
235 if (included_config_last) {
236 next = &included_config_last->next;
237 *list_last = included_config_last;
238 }
239 } SMARTLIST_FOREACH_END(config_file);
240 *list = ret_list;
241 rv = 0;
242
243 done:
244 SMARTLIST_FOREACH(config_files, char *, f, tor_free(f));
245 smartlist_free(config_files);
246 return rv;
247}
Read configuration files from disk, with full include support.
int config_get_lines_include(const char *string, struct config_line_t **result, int extended, int *has_include, struct smartlist_t *opened_lst)
Definition: conffile.c:49
int config_get_lines_aux(const char *string, config_line_t **result, int extended, int allow_include, int *has_include, struct smartlist_t *opened_lst, int recursion_level, config_line_t **last, include_handler_fn handle_include)
Definition: confline.c:104
Header for confline.c.
smartlist_t * tor_listdir(const char *dirname)
Definition: dir.c:307
Header for dir.c.
Wrappers for reading and writing data to files on disk.
file_status_t file_status(const char *filename)
Definition: files.c:212
file_status_t
Definition: files.h:55
Headers for log.c.
#define LD_CONFIG
Definition: log.h:68
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
struct smartlist_t * tor_glob(const char *pattern)
Definition: path.c:597
bool has_glob(const char *s)
Definition: path.c:667
struct smartlist_t * get_glob_opened_files(const char *pattern)
Definition: path.c:710
Header for path.c.
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
Header for printf.c.
Header file for sandbox.c.
void smartlist_sort_strings(smartlist_t *sl)
Definition: smartlist.c:549
Header for smartlist.c.
void smartlist_add_all(smartlist_t *s1, const smartlist_t *s2)
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)