Tor  0.4.7.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 
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"
24 
25 #include <stdbool.h>
26 #include <errno.h>
27 
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);
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. */
48 int
49 config_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. */
61 static smartlist_t *
62 expand_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  }
90  smartlist_sort_strings(matches);
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  */
103 static smartlist_t *
104 config_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. */
178 static int
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)
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. */
203 static int
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)
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:52
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)
smartlist_t * smartlist_new(void)
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)