Line data Source code
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 confmgt.c
9 : *
10 : * \brief Back-end for parsing and generating key-value files, used to
11 : * implement the torrc file format and the state file.
12 : *
13 : * This module is used by config.c to parse and encode torrc
14 : * configuration files, and by statefile.c to parse and encode the
15 : * $DATADIR/state file.
16 : *
17 : * To use this module, its callers provide an instance of
18 : * config_format_t to describe the mappings from a set of configuration
19 : * options to a number of fields in a C structure. With this mapping,
20 : * the functions here can convert back and forth between the C structure
21 : * specified, and a linked list of key-value pairs.
22 : */
23 :
24 : #define CONFMGT_PRIVATE
25 : #include "orconfig.h"
26 : #include "lib/confmgt/confmgt.h"
27 :
28 : #include "lib/confmgt/structvar.h"
29 : #include "lib/confmgt/unitparse.h"
30 : #include "lib/container/bitarray.h"
31 : #include "lib/container/smartlist.h"
32 : #include "lib/encoding/confline.h"
33 : #include "lib/log/escape.h"
34 : #include "lib/log/log.h"
35 : #include "lib/log/util_bug.h"
36 : #include "lib/string/compat_ctype.h"
37 : #include "lib/string/printf.h"
38 : #include "lib/string/util_string.h"
39 :
40 : #include "ext/siphash.h"
41 :
42 : /**
43 : * A managed_var_t is an internal wrapper around a config_var_t in
44 : * a config_format_t structure. It is used by config_mgr_t to
45 : * keep track of which option goes with which structure. */
46 : typedef struct managed_var_t {
47 : /**
48 : * A pointer to the config_var_t for this option.
49 : */
50 : const config_var_t *cvar;
51 : /**
52 : * The index of the object in which this option is stored. It is
53 : * IDX_TOPLEVEL to indicate that the object is the top-level object.
54 : **/
55 : int object_idx;
56 : } managed_var_t;
57 :
58 : static void config_reset(const config_mgr_t *fmt, void *options,
59 : const managed_var_t *var, int use_defaults);
60 : static void config_mgr_register_fmt(config_mgr_t *mgr,
61 : const config_format_t *fmt,
62 : int object_idx);
63 :
64 : /** Release all storage held in a managed_var_t. */
65 : static void
66 104654 : managed_var_free_(managed_var_t *mv)
67 : {
68 104654 : if (!mv)
69 : return;
70 104654 : tor_free(mv);
71 : }
72 : #define managed_var_free(mv) \
73 : FREE_AND_NULL(managed_var_t, managed_var_free_, (mv))
74 :
75 : struct config_suite_t {
76 : /** A list of configuration objects managed by a given configuration
77 : * manager. They are stored in the same order as the config_format_t
78 : * objects in the manager's list of subformats. */
79 : smartlist_t *configs;
80 : };
81 :
82 : /**
83 : * Allocate a new empty config_suite_t.
84 : **/
85 : static config_suite_t *
86 6722 : config_suite_new(void)
87 : {
88 6722 : config_suite_t *suite = tor_malloc_zero(sizeof(config_suite_t));
89 6722 : suite->configs = smartlist_new();
90 6722 : return suite;
91 : }
92 :
93 : /** Release all storage held by a config_suite_t. (Does not free
94 : * any configuration objects it holds; the caller must do that first.) */
95 : static void
96 6715 : config_suite_free_(config_suite_t *suite)
97 : {
98 6715 : if (!suite)
99 : return;
100 6715 : smartlist_free(suite->configs);
101 6715 : tor_free(suite);
102 : }
103 :
104 : #define config_suite_free(suite) \
105 : FREE_AND_NULL(config_suite_t, config_suite_free_, (suite))
106 :
107 : struct config_mgr_t {
108 : /** The 'top-level' configuration format. This one is used for legacy
109 : * options that have not yet been assigned to different sub-modules.
110 : *
111 : * (NOTE: for now, this is the only config_format_t that a config_mgr_t
112 : * contains. A subsequent commit will add more. XXXX)
113 : */
114 : const config_format_t *toplevel;
115 : /**
116 : * List of second-level configuration format objects that this manager
117 : * also knows about.
118 : */
119 : smartlist_t *subconfigs;
120 : /** A smartlist of managed_var_t objects for all configuration formats. */
121 : smartlist_t *all_vars;
122 : /** A smartlist of config_abbrev_t objects for all configuration
123 : * formats. These objects are used to track synonyms and abbreviations for
124 : * different configuration options. */
125 : smartlist_t *all_abbrevs;
126 : /** A smartlist of config_deprecation_t for all configuration formats. */
127 : smartlist_t *all_deprecations;
128 : /** True if this manager has been frozen and cannot have any more formats
129 : * added to it. A manager must be frozen before it can be used to construct
130 : * or manipulate objects. */
131 : bool frozen;
132 : /** A replacement for the magic number of the toplevel object. We override
133 : * that number to make it unique for this particular config_mgr_t, so that
134 : * an object constructed with one mgr can't be used with another, even if
135 : * those managers' contents are equal.
136 : */
137 : struct_magic_decl_t toplevel_magic;
138 : };
139 :
140 : #define IDX_TOPLEVEL (-1)
141 :
142 : /** Create a new config_mgr_t to manage a set of configuration objects to be
143 : * wrapped under <b>toplevel_fmt</b>. */
144 : config_mgr_t *
145 5744 : config_mgr_new(const config_format_t *toplevel_fmt)
146 : {
147 5744 : config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
148 5744 : mgr->subconfigs = smartlist_new();
149 5744 : mgr->all_vars = smartlist_new();
150 5744 : mgr->all_abbrevs = smartlist_new();
151 5744 : mgr->all_deprecations = smartlist_new();
152 :
153 5744 : config_mgr_register_fmt(mgr, toplevel_fmt, IDX_TOPLEVEL);
154 5744 : mgr->toplevel = toplevel_fmt;
155 :
156 5744 : return mgr;
157 : }
158 :
159 : /** Add a config_format_t to a manager, with a specified (unique) index. */
160 : static void
161 22530 : config_mgr_register_fmt(config_mgr_t *mgr,
162 : const config_format_t *fmt,
163 : int object_idx)
164 : {
165 22530 : int i;
166 :
167 22530 : tor_assertf(!mgr->frozen,
168 : "Tried to add a format to a configuration manager after "
169 : "it had been frozen.");
170 :
171 22530 : if (object_idx != IDX_TOPLEVEL) {
172 16786 : tor_assertf(! fmt->has_config_suite,
173 : "Tried to register a toplevel format in a non-toplevel position");
174 : }
175 22530 : if (fmt->config_suite_offset) {
176 5673 : tor_assertf(fmt->has_config_suite,
177 : "config_suite_offset was set, but has_config_suite was not.");
178 : }
179 :
180 22530 : tor_assertf(fmt != mgr->toplevel &&
181 : ! smartlist_contains(mgr->subconfigs, fmt),
182 : "Tried to register an already-registered format.");
183 :
184 : /* register variables */
185 2411036 : for (i = 0; fmt->vars[i].member.name; ++i) {
186 2388506 : managed_var_t *mv = tor_malloc_zero(sizeof(managed_var_t));
187 2388506 : mv->cvar = &fmt->vars[i];
188 2388506 : mv->object_idx = object_idx;
189 2388506 : smartlist_add(mgr->all_vars, mv);
190 : }
191 :
192 : /* register abbrevs */
193 22530 : if (fmt->abbrevs) {
194 300104 : for (i = 0; fmt->abbrevs[i].abbreviated; ++i) {
195 294395 : smartlist_add(mgr->all_abbrevs, (void*)&fmt->abbrevs[i]);
196 : }
197 : }
198 :
199 : /* register deprecations. */
200 22530 : if (fmt->deprecations) {
201 : const config_deprecation_t *d;
202 33418 : for (d = fmt->deprecations; d->name; ++d) {
203 27815 : smartlist_add(mgr->all_deprecations, (void*)d);
204 : }
205 : }
206 22530 : }
207 :
208 : /**
209 : * Add a new format to this configuration object. Asserts on failure.
210 : *
211 : * Returns an internal "index" value used to identify this format within
212 : * all of those formats contained in <b>mgr</b>. This index value
213 : * should not generally be used outside of this module.
214 : **/
215 : int
216 16786 : config_mgr_add_format(config_mgr_t *mgr,
217 : const config_format_t *fmt)
218 : {
219 16786 : tor_assert(mgr);
220 16786 : int idx = smartlist_len(mgr->subconfigs);
221 16786 : config_mgr_register_fmt(mgr, fmt, idx);
222 16786 : smartlist_add(mgr->subconfigs, (void *)fmt);
223 16786 : return idx;
224 : }
225 :
226 : /** Return a pointer to the config_suite_t * pointer inside a
227 : * configuration object; returns NULL if there is no such member. */
228 : static inline config_suite_t **
229 1038380 : config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
230 : {
231 1038380 : if (! mgr->toplevel->has_config_suite)
232 : return NULL;
233 1031507 : return STRUCT_VAR_P(toplevel, mgr->toplevel->config_suite_offset);
234 : }
235 :
236 : /**
237 : * Return a pointer to the configuration object within <b>toplevel</b> whose
238 : * index is <b>idx</b>.
239 : *
240 : * NOTE: XXXX Eventually, there will be multiple objects supported within the
241 : * toplevel object. For example, the or_options_t will contain pointers
242 : * to configuration objects for other modules. This function gets
243 : * the sub-object for a particular module.
244 : */
245 : void *
246 4413689 : config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
247 : {
248 4413689 : tor_assert(mgr);
249 4413689 : tor_assert(toplevel);
250 4413689 : if (idx == IDX_TOPLEVEL)
251 : return toplevel;
252 :
253 457122 : tor_assertf(idx >= 0 && idx < smartlist_len(mgr->subconfigs),
254 : "Index %d is out of range.", idx);
255 457122 : config_suite_t **suite = config_mgr_get_suite_ptr(mgr, toplevel);
256 457122 : tor_assert(suite);
257 457122 : tor_assert(smartlist_len(mgr->subconfigs) ==
258 : smartlist_len((*suite)->configs));
259 :
260 457122 : return smartlist_get((*suite)->configs, idx);
261 : }
262 :
263 : /** As config_mgr_get_obj_mutable(), but return a const pointer. */
264 : const void *
265 171429 : config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
266 : {
267 171429 : return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx);
268 : }
269 :
270 : /** Sorting helper for smartlist of managed_var_t */
271 : static int
272 15759720 : managed_var_cmp(const void **a, const void **b)
273 : {
274 15759720 : const managed_var_t *mv1 = *(const managed_var_t**)a;
275 15759720 : const managed_var_t *mv2 = *(const managed_var_t**)b;
276 :
277 15759720 : return strcasecmp(mv1->cvar->member.name, mv2->cvar->member.name);
278 : }
279 :
280 : /**
281 : * Mark a configuration manager as "frozen", so that no more formats can be
282 : * added, and so that it can be used for manipulating configuration objects.
283 : **/
284 : void
285 5741 : config_mgr_freeze(config_mgr_t *mgr)
286 : {
287 5741 : static uint64_t mgr_count = 0;
288 :
289 5741 : smartlist_sort(mgr->all_vars, managed_var_cmp);
290 5741 : memcpy(&mgr->toplevel_magic, &mgr->toplevel->magic,
291 : sizeof(struct_magic_decl_t));
292 5741 : uint64_t magic_input[3] = { mgr->toplevel_magic.magic_val,
293 5741 : (uint64_t) (uintptr_t) mgr,
294 5741 : ++mgr_count };
295 11482 : mgr->toplevel_magic.magic_val =
296 5741 : (uint32_t)siphash24g(magic_input, sizeof(magic_input));
297 5741 : mgr->frozen = true;
298 5741 : }
299 :
300 : /** Release all storage held in <b>mgr</b> */
301 : void
302 1087 : config_mgr_free_(config_mgr_t *mgr)
303 : {
304 1087 : if (!mgr)
305 : return;
306 104956 : SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv, managed_var_free(mv));
307 302 : smartlist_free(mgr->all_vars);
308 302 : smartlist_free(mgr->all_abbrevs);
309 302 : smartlist_free(mgr->all_deprecations);
310 302 : smartlist_free(mgr->subconfigs);
311 302 : memset(mgr, 0, sizeof(*mgr));
312 302 : tor_free(mgr);
313 : }
314 :
315 : /** Return a new smartlist_t containing a config_var_t for every variable that
316 : * <b>mgr</b> knows about. The elements of this smartlist do not need
317 : * to be freed; they have the same lifespan as <b>mgr</b>. */
318 : smartlist_t *
319 567 : config_mgr_list_vars(const config_mgr_t *mgr)
320 : {
321 567 : smartlist_t *result = smartlist_new();
322 567 : tor_assert(mgr);
323 242985 : SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv,
324 : smartlist_add(result, (void*) mv->cvar));
325 567 : return result;
326 : }
327 :
328 : /** Return a new smartlist_t containing the names of all deprecated variables.
329 : * The elements of this smartlist do not need to be freed; they have the same
330 : * lifespan as <b>mgr</b>.
331 : */
332 : smartlist_t *
333 2 : config_mgr_list_deprecated_vars(const config_mgr_t *mgr)
334 : {
335 2 : smartlist_t *result = smartlist_new();
336 2 : tor_assert(mgr);
337 5 : SMARTLIST_FOREACH(mgr->all_deprecations, config_deprecation_t *, d,
338 : smartlist_add(result, (char*)d->name));
339 2 : return result;
340 : }
341 :
342 : /**
343 : * Check the magic number on <b>object</b> to make sure it's a valid toplevel
344 : * object, created with <b>mgr</b>. Exit with an assertion if it isn't.
345 : **/
346 : void
347 7193 : config_check_toplevel_magic(const config_mgr_t *mgr,
348 : const void *object)
349 : {
350 7193 : struct_check_magic(object, &mgr->toplevel_magic);
351 7193 : }
352 :
353 : /** Assert that the magic fields in <b>options</b> and its subsidiary
354 : * objects are all okay. */
355 : static void
356 566497 : config_mgr_assert_magic_ok(const config_mgr_t *mgr,
357 : const void *options)
358 : {
359 566497 : tor_assert(mgr);
360 566497 : tor_assert(options);
361 566497 : tor_assert(mgr->frozen);
362 566497 : struct_check_magic(options, &mgr->toplevel_magic);
363 :
364 566497 : config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, (void*)options);
365 566497 : if (suitep == NULL) {
366 6157 : tor_assert(smartlist_len(mgr->subconfigs) == 0);
367 : return;
368 : }
369 :
370 560340 : tor_assert(smartlist_len((*suitep)->configs) ==
371 : smartlist_len(mgr->subconfigs));
372 2230458 : SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
373 1670118 : void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
374 1670118 : tor_assert(obj);
375 1670118 : struct_check_magic(obj, &fmt->magic);
376 1670118 : } SMARTLIST_FOREACH_END(fmt);
377 : }
378 :
379 : /** Macro: assert that <b>cfg</b> has the right magic field for
380 : * <b>mgr</b>. */
381 : #define CONFIG_CHECK(mgr, cfg) STMT_BEGIN \
382 : config_mgr_assert_magic_ok((mgr), (cfg)); \
383 : STMT_END
384 :
385 : /** Allocate an empty configuration object of a given format type. */
386 : void *
387 6985 : config_new(const config_mgr_t *mgr)
388 : {
389 6985 : tor_assert(mgr->frozen);
390 6985 : void *opts = tor_malloc_zero(mgr->toplevel->size);
391 6985 : struct_set_magic(opts, &mgr->toplevel_magic);
392 6985 : config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, opts);
393 6985 : if (suitep) {
394 6722 : *suitep = config_suite_new();
395 26642 : SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
396 19920 : void *obj = tor_malloc_zero(fmt->size);
397 19920 : struct_set_magic(obj, &fmt->magic);
398 19920 : smartlist_add((*suitep)->configs, obj);
399 19920 : } SMARTLIST_FOREACH_END(fmt);
400 : }
401 6985 : CONFIG_CHECK(mgr, opts);
402 6985 : return opts;
403 : }
404 :
405 : /*
406 : * Functions to parse config options
407 : */
408 :
409 : /** If <b>option</b> is an official abbreviation for a longer option,
410 : * return the longer option. Otherwise return <b>option</b>.
411 : * If <b>command_line</b> is set, apply all abbreviations. Otherwise, only
412 : * apply abbreviations that work for the config file and the command line.
413 : * If <b>warn_obsolete</b> is set, warn about deprecated names. */
414 : const char *
415 3679 : config_expand_abbrev(const config_mgr_t *mgr, const char *option,
416 : int command_line, int warn_obsolete)
417 : {
418 151302 : SMARTLIST_FOREACH_BEGIN(mgr->all_abbrevs, const config_abbrev_t *, abbrev) {
419 : /* Abbreviations are case insensitive. */
420 147623 : if (!strcasecmp(option, abbrev->abbreviated) &&
421 42 : (command_line || !abbrev->commandline_only)) {
422 38 : if (warn_obsolete && abbrev->warn) {
423 1 : log_warn(LD_CONFIG,
424 : "The configuration option '%s' is deprecated; "
425 : "use '%s' instead.",
426 : abbrev->abbreviated,
427 : abbrev->full);
428 : }
429 : /* Keep going through the list in case we want to rewrite it more.
430 : * (We could imagine recursing here, but I don't want to get the
431 : * user into an infinite loop if we craft our list wrong.) */
432 38 : option = abbrev->full;
433 : }
434 147623 : } SMARTLIST_FOREACH_END(abbrev);
435 3679 : return option;
436 : }
437 :
438 : /** If <b>key</b> is a deprecated configuration option, return the message
439 : * explaining why it is deprecated (which may be an empty string). Return NULL
440 : * if it is not deprecated. The <b>key</b> field must be fully expanded. */
441 : const char *
442 1224 : config_find_deprecation(const config_mgr_t *mgr, const char *key)
443 : {
444 1224 : if (BUG(mgr == NULL) || BUG(key == NULL))
445 : return NULL; // LCOV_EXCL_LINE
446 :
447 7311 : SMARTLIST_FOREACH_BEGIN(mgr->all_deprecations, const config_deprecation_t *,
448 : d) {
449 6096 : if (!strcasecmp(d->name, key)) {
450 9 : return d->why_deprecated ? d->why_deprecated : "";
451 : }
452 6087 : } SMARTLIST_FOREACH_END(d);
453 : return NULL;
454 : }
455 :
456 : /**
457 : * Find the managed_var_t object for a variable whose name is <b>name</b>
458 : * according to <b>mgr</b>. Return that object, or NULL if none exists.
459 : *
460 : * If <b>allow_truncated</b> is true, then accept any variable whose
461 : * name begins with <b>name</b>.
462 : *
463 : * If <b>idx_out</b> is not NULL, set *<b>idx_out</b> to the position of
464 : * that variable within mgr->all_vars, or to -1 if the variable is
465 : * not found.
466 : */
467 : static const managed_var_t *
468 285950 : config_mgr_find_var(const config_mgr_t *mgr,
469 : const char *key,
470 : bool allow_truncated, int *idx_out)
471 : {
472 285950 : const size_t keylen = strlen(key);
473 285950 : if (idx_out)
474 3266 : *idx_out = -1;
475 :
476 285950 : if (!keylen)
477 : return NULL; /* if they say "--" on the command line, it's not an option */
478 :
479 : /* First, check for an exact (case-insensitive) match */
480 61786044 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
481 61785982 : if (!strcasecmp(mv->cvar->member.name, key)) {
482 285888 : if (idx_out)
483 3211 : *idx_out = mv_sl_idx;
484 285888 : return mv;
485 : }
486 61500094 : } SMARTLIST_FOREACH_END(mv);
487 :
488 62 : if (!allow_truncated)
489 : return NULL;
490 :
491 : /* If none, check for an abbreviated match */
492 23237 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
493 23226 : if (!strncasecmp(key, mv->cvar->member.name, keylen)) {
494 51 : log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
495 : "Please use '%s' instead",
496 : key, mv->cvar->member.name);
497 51 : if (idx_out)
498 50 : *idx_out = mv_sl_idx;
499 51 : return mv;
500 : }
501 23175 : } SMARTLIST_FOREACH_END(mv);
502 :
503 : /* Okay, unrecognized option */
504 : return NULL;
505 : }
506 :
507 : /**
508 : * If <b>key</b> is a name or an abbreviation configuration option, return
509 : * the corresponding canonical name for it. Warn if the abbreviation is
510 : * non-standard. Return NULL if the option does not exist.
511 : */
512 : const char *
513 18 : config_find_option_name(const config_mgr_t *mgr, const char *key)
514 : {
515 18 : key = config_expand_abbrev(mgr, key, 0, 0);
516 18 : const managed_var_t *mv = config_mgr_find_var(mgr, key, true, NULL);
517 18 : if (mv)
518 13 : return mv->cvar->member.name;
519 : else
520 : return NULL;
521 : }
522 :
523 : /** Return the number of option entries in <b>fmt</b>. */
524 : static int
525 2143 : config_count_options(const config_mgr_t *mgr)
526 : {
527 2143 : return smartlist_len(mgr->all_vars);
528 : }
529 :
530 : /**
531 : * Return true iff at least one bit from <b>flag</b> is set on <b>var</b>,
532 : * either in <b>var</b>'s flags, or on the flags of its type.
533 : **/
534 : static bool
535 621234 : config_var_has_flag(const config_var_t *var, uint32_t flag)
536 : {
537 621234 : uint32_t have_flags = var->flags | struct_var_get_flags(&var->member);
538 :
539 621234 : return (have_flags & flag) != 0;
540 : }
541 :
542 : /**
543 : * Return true if assigning a value to <b>var</b> replaces the previous
544 : * value. Return false if assigning a value to <b>var</b> appends
545 : * to the previous value.
546 : **/
547 : static bool
548 3261 : config_var_is_replaced_on_set(const config_var_t *var)
549 : {
550 3261 : return ! config_var_has_flag(var, CFLG_NOREPLACE);
551 : }
552 :
553 : /**
554 : * Return true iff <b>var</b> may be assigned by name (e.g., via the
555 : * CLI, the configuration files, or the controller API).
556 : **/
557 : bool
558 429 : config_var_is_settable(const config_var_t *var)
559 : {
560 429 : return ! config_var_has_flag(var, CFLG_NOSET);
561 : }
562 :
563 : /**
564 : * Return true iff the controller is allowed to fetch the value of
565 : * <b>var</b>.
566 : **/
567 : static bool
568 10192 : config_var_is_gettable(const config_var_t *var)
569 : {
570 : /* Arguably, invisible or obsolete options should not be gettable. However,
571 : * they have been gettable for a long time, and making them ungettable could
572 : * have compatibility effects. For now, let's leave them alone.
573 : */
574 :
575 : // return ! config_var_has_flag(var, CVFLAG_OBSOLETE|CFGLAGS_INVISIBLE);
576 10192 : (void)var;
577 10192 : return true;
578 : }
579 :
580 : /**
581 : * Return true iff we need to check <b>var</b> for changes when we are
582 : * comparing config options for changes.
583 : *
584 : * A false result might mean that the variable is a derived variable, and that
585 : * comparing the variable it derives from compares this one too-- or it might
586 : * mean that there is no data to compare.
587 : **/
588 : static bool
589 2145 : config_var_should_list_changes(const config_var_t *var)
590 : {
591 2145 : return ! config_var_has_flag(var, CFLG_NOCMP);
592 : }
593 :
594 : /**
595 : * Return true iff we need to copy the data for <b>var</b> when we are
596 : * copying a config option.
597 : *
598 : * A false option might mean that the variable is a derived variable, and that
599 : * copying the variable it derives from copies it-- or it might mean that
600 : * there is no data to copy.
601 : **/
602 : static bool
603 100815 : config_var_needs_copy(const config_var_t *var)
604 : {
605 100815 : return ! config_var_has_flag(var, CFLG_NOCOPY);
606 : }
607 :
608 : /**
609 : * Return true iff variable <b>var</b> should appear on list of variable
610 : * names given to the controller or the CLI.
611 : *
612 : * (Note that this option is imperfectly obeyed. The
613 : * --list-torrc-options command looks at the "settable" flag, whereas
614 : * "GETINFO config/defaults" and "list_deprecated_*()" do not filter
615 : * their results. It would be good for consistency to try to converge
616 : * these behaviors in the future.)
617 : **/
618 : bool
619 429 : config_var_is_listable(const config_var_t *var)
620 : {
621 429 : return ! config_var_has_flag(var, CFLG_NOLIST);
622 : }
623 :
624 : /**
625 : * Return true iff variable <b>var</b> should be written out when we
626 : * are writing our configuration to disk, to a controller, or via the
627 : * --dump-config command.
628 : *
629 : * This option may be set because a variable is hidden, or because it is
630 : * derived from another variable which will already be written out.
631 : **/
632 : static bool
633 48834 : config_var_is_dumpable(const config_var_t *var)
634 : {
635 48834 : return ! config_var_has_flag(var, CFLG_NODUMP);
636 : }
637 :
638 : /*
639 : * Functions to assign config options.
640 : */
641 :
642 : /** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
643 : * with <b>c</b>-\>value and return 0, or return -1 if bad value.
644 : *
645 : * Called from config_assign_line() and option_reset().
646 : */
647 : static int
648 231416 : config_assign_value(const config_mgr_t *mgr, void *options,
649 : config_line_t *c, char **msg)
650 : {
651 231416 : const managed_var_t *var;
652 :
653 231416 : CONFIG_CHECK(mgr, options);
654 :
655 231416 : var = config_mgr_find_var(mgr, c->key, true, NULL);
656 231416 : tor_assert(var);
657 231416 : tor_assert(!strcmp(c->key, var->cvar->member.name));
658 231416 : void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
659 :
660 231416 : if (config_var_has_flag(var->cvar, CFLG_WARN_OBSOLETE)) {
661 141 : log_warn(LD_GENERAL, "Skipping obsolete configuration option \"%s\".",
662 : var->cvar->member.name);
663 231275 : } else if (config_var_has_flag(var->cvar, CFLG_WARN_DISABLED)) {
664 0 : log_warn(LD_GENERAL, "This copy of Tor was built without support for "
665 : "the option \"%s\". Skipping.", var->cvar->member.name);
666 : }
667 :
668 231416 : return struct_var_kvassign(object, c, msg, &var->cvar->member);
669 : }
670 :
671 : /** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
672 : * to it will replace old ones. */
673 : static void
674 2113 : config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
675 : {
676 2113 : tor_assert(mgr);
677 2113 : tor_assert(options);
678 :
679 872808 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
680 870695 : void *object = config_mgr_get_obj_mutable(mgr, options, mv->object_idx);
681 870695 : struct_var_mark_fragile(object, &mv->cvar->member);
682 870695 : } SMARTLIST_FOREACH_END(mv);
683 2113 : }
684 :
685 : /**
686 : * Log a warning that declaring that the option called <b>what</b>
687 : * is deprecated because of the reason in <b>why</b>.
688 : *
689 : * (Both arguments must be non-NULL.)
690 : **/
691 : void
692 13 : warn_deprecated_option(const char *what, const char *why)
693 : {
694 13 : const char *space = (why && strlen(why)) ? " " : "";
695 13 : log_warn(LD_CONFIG, "The %s option is deprecated, and will most likely "
696 : "be removed in a future version of Tor.%s%s (If you think this is "
697 : "a mistake, please let us know!)",
698 : what, space, why);
699 13 : }
700 :
701 : /** If <b>c</b> is a syntactically valid configuration line, update
702 : * <b>options</b> with its value and return 0. Otherwise return -1 for bad
703 : * key, -2 for bad value.
704 : *
705 : * If <b>clear_first</b> is set, clear the value first. Then if
706 : * <b>use_defaults</b> is set, set the value to the default.
707 : *
708 : * Called from config_assign().
709 : */
710 : static int
711 3266 : config_assign_line(const config_mgr_t *mgr, void *options,
712 : config_line_t *c, unsigned flags,
713 : bitarray_t *options_seen, char **msg)
714 : {
715 3266 : const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
716 3266 : const unsigned clear_first = flags & CAL_CLEAR_FIRST;
717 3266 : const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
718 3266 : const managed_var_t *mvar;
719 :
720 3266 : CONFIG_CHECK(mgr, options);
721 :
722 3266 : int var_index = -1;
723 3266 : mvar = config_mgr_find_var(mgr, c->key, true, &var_index);
724 3266 : if (!mvar) {
725 5 : const config_format_t *fmt = mgr->toplevel;
726 5 : if (fmt->extra) {
727 3 : void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
728 3 : log_info(LD_CONFIG,
729 : "Found unrecognized option '%s'; saving it.", c->key);
730 3 : config_line_append((config_line_t**)lvalue, c->key, c->value);
731 3 : return 0;
732 : } else {
733 2 : tor_asprintf(msg,
734 : "Unknown option '%s'. Failing.", c->key);
735 2 : return -1;
736 : }
737 : }
738 :
739 3261 : const config_var_t *cvar = mvar->cvar;
740 3261 : tor_assert(cvar);
741 :
742 : /* Put keyword into canonical case. */
743 3261 : if (strcmp(cvar->member.name, c->key)) {
744 338 : tor_free(c->key);
745 338 : c->key = tor_strdup(cvar->member.name);
746 : }
747 :
748 3261 : const char *deprecation_msg;
749 3261 : if (warn_deprecations &&
750 1222 : (deprecation_msg = config_find_deprecation(mgr, cvar->member.name))) {
751 7 : warn_deprecated_option(cvar->member.name, deprecation_msg);
752 : }
753 :
754 3261 : if (!strlen(c->value)) {
755 : /* reset or clear it, then return */
756 32 : if (!clear_first) {
757 32 : if (! config_var_is_replaced_on_set(cvar) &&
758 25 : c->command != CONFIG_LINE_CLEAR) {
759 : /* We got an empty linelist from the torrc or command line.
760 : As a special case, call this an error. Warn and ignore. */
761 15 : log_warn(LD_CONFIG,
762 : "Linelist option '%s' has no value. Skipping.", c->key);
763 : } else { /* not already cleared */
764 17 : config_reset(mgr, options, mvar, use_defaults);
765 : }
766 : }
767 32 : return 0;
768 3229 : } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
769 : // This block is unreachable, since a CLEAR line always has an
770 : // empty value, and so will trigger be handled by the previous
771 : // "if (!strlen(c->value))" block.
772 :
773 : // LCOV_EXCL_START
774 : tor_assert_nonfatal_unreached();
775 : config_reset(mgr, options, mvar, use_defaults);
776 : // LCOV_EXCL_STOP
777 : }
778 :
779 3229 : if (options_seen && config_var_is_replaced_on_set(cvar)) {
780 : /* We're tracking which options we've seen, and this option is not
781 : * supposed to occur more than once. */
782 2096 : tor_assert(var_index >= 0);
783 2096 : if (bitarray_is_set(options_seen, var_index)) {
784 1 : log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
785 : "value will be ignored.", cvar->member.name);
786 : }
787 2096 : bitarray_set(options_seen, var_index);
788 : }
789 :
790 3229 : if (config_assign_value(mgr, options, c, msg) < 0)
791 28 : return -2;
792 : return 0;
793 : }
794 :
795 : /** Restore the option named <b>key</b> in options to its default value.
796 : * Called from config_assign(). */
797 : STATIC void
798 8 : config_reset_line(const config_mgr_t *mgr, void *options,
799 : const char *key, int use_defaults)
800 : {
801 8 : const managed_var_t *var;
802 :
803 8 : CONFIG_CHECK(mgr, options);
804 :
805 8 : var = config_mgr_find_var(mgr, key, true, NULL);
806 8 : if (!var)
807 : return; /* give error on next pass. */
808 :
809 8 : config_reset(mgr, options, var, use_defaults);
810 : }
811 :
812 : /** Return true iff value needs to be quoted and escaped to be used in
813 : * a configuration file. */
814 : static int
815 1581 : config_value_needs_escape(const char *value)
816 : {
817 1581 : if (*value == '\"')
818 : return 1;
819 35894 : while (*value) {
820 34314 : switch (*value)
821 : {
822 : case '\r':
823 : case '\n':
824 : case '#':
825 : /* Note: quotes and backspaces need special handling when we are using
826 : * quotes, not otherwise, so they don't trigger escaping on their
827 : * own. */
828 : return 1;
829 34313 : default:
830 34313 : if (!TOR_ISPRINT(*value))
831 : return 1;
832 : }
833 34313 : ++value;
834 : }
835 : return 0;
836 : }
837 :
838 : /** Return newly allocated line or lines corresponding to <b>key</b> in the
839 : * configuration <b>options</b>. If <b>escape_val</b> is true and a
840 : * value needs to be quoted before it's put in a config file, quote and
841 : * escape that value. Return NULL if no such key exists. */
842 : config_line_t *
843 10193 : config_get_assigned_option(const config_mgr_t *mgr, const void *options,
844 : const char *key, int escape_val)
845 : {
846 10193 : const managed_var_t *var;
847 10193 : config_line_t *result;
848 :
849 10193 : tor_assert(options && key);
850 :
851 10193 : CONFIG_CHECK(mgr, options);
852 :
853 10193 : var = config_mgr_find_var(mgr, key, true, NULL);
854 10193 : if (!var) {
855 1 : log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
856 1 : return NULL;
857 : }
858 10192 : if (! config_var_is_gettable(var->cvar)) {
859 0 : log_warn(LD_CONFIG, "Option '%s' is obsolete or unfetchable. Failing.",
860 : key);
861 0 : return NULL;
862 : }
863 10192 : const void *object = config_mgr_get_obj(mgr, options, var->object_idx);
864 :
865 10192 : result = struct_var_kvencode(object, &var->cvar->member);
866 :
867 10192 : if (escape_val) {
868 : config_line_t *line;
869 3328 : for (line = result; line; line = line->next) {
870 1581 : if (line->value && config_value_needs_escape(line->value)) {
871 1 : char *newval = esc_for_log(line->value);
872 1 : tor_free(line->value);
873 1 : line->value = newval;
874 : }
875 : }
876 : }
877 :
878 : return result;
879 : }
880 : /** Iterate through the linked list of requested options <b>list</b>.
881 : * For each item, convert as appropriate and assign to <b>options</b>.
882 : * If an item is unrecognized, set *msg and return -1 immediately,
883 : * else return 0 for success.
884 : *
885 : * If <b>clear_first</b>, interpret config options as replacing (not
886 : * extending) their previous values. If <b>clear_first</b> is set,
887 : * then <b>use_defaults</b> to decide if you set to defaults after
888 : * clearing, or make the value 0 or NULL.
889 : *
890 : * Here are the use cases:
891 : * 1. A non-empty AllowInvalid line in your torrc. Appends to current
892 : * if linelist, replaces current if csv.
893 : * 2. An empty AllowInvalid line in your torrc. Should clear it.
894 : * 3. "RESETCONF AllowInvalid" sets it to default.
895 : * 4. "SETCONF AllowInvalid" makes it NULL.
896 : * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo".
897 : *
898 : * Use_defaults Clear_first
899 : * 0 0 "append"
900 : * 1 0 undefined, don't use
901 : * 0 1 "set to null first"
902 : * 1 1 "set to defaults first"
903 : * Return 0 on success, -1 on bad key, -2 on bad value.
904 : *
905 : * As an additional special case, if a LINELIST config option has
906 : * no value and clear_first is 0, then warn and ignore it.
907 : */
908 :
909 : /*
910 : There are three call cases for config_assign() currently.
911 :
912 : Case one: Torrc entry
913 : options_init_from_torrc() calls config_assign(0, 0)
914 : calls config_assign_line(0, 0).
915 : if value is empty, calls config_reset(0) and returns.
916 : calls config_assign_value(), appends.
917 :
918 : Case two: setconf
919 : options_trial_assign() calls config_assign(0, 1)
920 : calls config_reset_line(0)
921 : calls config_reset(0)
922 : calls option_clear().
923 : calls config_assign_line(0, 1).
924 : if value is empty, returns.
925 : calls config_assign_value(), appends.
926 :
927 : Case three: resetconf
928 : options_trial_assign() calls config_assign(1, 1)
929 : calls config_reset_line(1)
930 : calls config_reset(1)
931 : calls option_clear().
932 : calls config_assign_value(default)
933 : calls config_assign_line(1, 1).
934 : returns.
935 : */
936 : int
937 2143 : config_assign(const config_mgr_t *mgr, void *options, config_line_t *list,
938 : unsigned config_assign_flags, char **msg)
939 : {
940 2143 : config_line_t *p;
941 2143 : bitarray_t *options_seen;
942 2143 : const int n_options = config_count_options(mgr);
943 2143 : const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
944 2143 : const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
945 :
946 2143 : CONFIG_CHECK(mgr, options);
947 :
948 : /* pass 1: normalize keys */
949 7555 : for (p = list; p; p = p->next) {
950 3269 : const char *full = config_expand_abbrev(mgr, p->key, 0, 1);
951 3269 : if (strcmp(full,p->key)) {
952 35 : tor_free(p->key);
953 35 : p->key = tor_strdup(full);
954 : }
955 : }
956 :
957 : /* pass 2: if we're reading from a resetting source, clear all
958 : * mentioned config options, and maybe set to their defaults. */
959 2143 : if (clear_first) {
960 6 : for (p = list; p; p = p->next)
961 5 : config_reset_line(mgr, options, p->key, use_defaults);
962 : }
963 :
964 2143 : options_seen = bitarray_init_zero(n_options);
965 : /* pass 3: assign. */
966 5379 : while (list) {
967 3266 : int r;
968 3266 : if ((r=config_assign_line(mgr, options, list, config_assign_flags,
969 : options_seen, msg))) {
970 30 : bitarray_free(options_seen);
971 30 : return r;
972 : }
973 3236 : list = list->next;
974 : }
975 2113 : bitarray_free(options_seen);
976 :
977 : /** Now we're done assigning a group of options to the configuration.
978 : * Subsequent group assignments should _replace_ linelists, not extend
979 : * them. */
980 2113 : config_mark_lists_fragile(mgr, options);
981 :
982 2113 : return 0;
983 : }
984 :
985 : /** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
986 : * Called from config_reset() and config_free(). */
987 : static void
988 3063579 : config_clear(const config_mgr_t *mgr, void *options, const managed_var_t *var)
989 : {
990 3063579 : void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
991 3063579 : struct_var_free(object, &var->cvar->member);
992 3063579 : }
993 :
994 : /** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
995 : * <b>use_defaults</b>, set it to its default value.
996 : * Called by config_init() and option_reset_line() and option_assign_line(). */
997 : static void
998 228209 : config_reset(const config_mgr_t *mgr, void *options,
999 : const managed_var_t *var, int use_defaults)
1000 : {
1001 228209 : config_line_t *c;
1002 228209 : char *msg = NULL;
1003 228209 : CONFIG_CHECK(mgr, options);
1004 228209 : config_clear(mgr, options, var); /* clear it first */
1005 :
1006 228209 : if (!use_defaults)
1007 19 : return; /* all done */
1008 :
1009 228190 : if (var->cvar->initvalue) {
1010 228187 : c = tor_malloc_zero(sizeof(config_line_t));
1011 228187 : c->key = tor_strdup(var->cvar->member.name);
1012 228187 : c->value = tor_strdup(var->cvar->initvalue);
1013 228187 : if (config_assign_value(mgr, options, c, &msg) < 0) {
1014 : // LCOV_EXCL_START
1015 : log_warn(LD_BUG, "Failed to assign default: %s", msg);
1016 : tor_free(msg); /* if this happens it's a bug */
1017 : // LCOV_EXCL_STOP
1018 : }
1019 228190 : config_free_lines(c);
1020 : }
1021 : }
1022 :
1023 : /** Release storage held by <b>options</b>. */
1024 : void
1025 7833 : config_free_(const config_mgr_t *mgr, void *options)
1026 : {
1027 7833 : if (!options)
1028 : return;
1029 :
1030 6965 : tor_assert(mgr);
1031 :
1032 6965 : if (mgr->toplevel->clear_fn) {
1033 6591 : mgr->toplevel->clear_fn(mgr, options);
1034 : }
1035 6965 : config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, options);
1036 6965 : if (suitep) {
1037 6715 : tor_assert(smartlist_len((*suitep)->configs) ==
1038 : smartlist_len(mgr->subconfigs));
1039 26624 : SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
1040 19909 : void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
1041 19909 : if (fmt->clear_fn) {
1042 12 : fmt->clear_fn(mgr, obj);
1043 : }
1044 19909 : } SMARTLIST_FOREACH_END(fmt);
1045 : }
1046 :
1047 2842335 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
1048 2835370 : config_clear(mgr, options, mv);
1049 2835370 : } SMARTLIST_FOREACH_END(mv);
1050 :
1051 6965 : if (mgr->toplevel->extra) {
1052 291 : config_line_t **linep = STRUCT_VAR_P(options,
1053 : mgr->toplevel->extra->offset);
1054 291 : config_free_lines(*linep);
1055 291 : *linep = NULL;
1056 : }
1057 :
1058 6965 : if (suitep) {
1059 26624 : SMARTLIST_FOREACH((*suitep)->configs, void *, obj, tor_free(obj));
1060 6715 : config_suite_free(*suitep);
1061 : }
1062 :
1063 6965 : tor_free(options);
1064 : }
1065 :
1066 : /** Return true iff the option <b>name</b> has the same value in <b>o1</b>
1067 : * and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
1068 : */
1069 : int
1070 41049 : config_is_same(const config_mgr_t *mgr,
1071 : const void *o1, const void *o2,
1072 : const char *name)
1073 : {
1074 41049 : CONFIG_CHECK(mgr, o1);
1075 41049 : CONFIG_CHECK(mgr, o2);
1076 :
1077 41049 : const managed_var_t *var = config_mgr_find_var(mgr, name, true, NULL);
1078 41049 : if (!var) {
1079 : return true;
1080 : }
1081 41049 : const void *obj1 = config_mgr_get_obj(mgr, o1, var->object_idx);
1082 41049 : const void *obj2 = config_mgr_get_obj(mgr, o2, var->object_idx);
1083 :
1084 41049 : return struct_var_eq(obj1, obj2, &var->cvar->member);
1085 : }
1086 :
1087 : /**
1088 : * Return a list of the options which have changed between <b>options1</b> and
1089 : * <b>options2</b>. If an option has reverted to its default value, it has a
1090 : * value entry of NULL.
1091 : *
1092 : * <b>options1</b> and <b>options2</b> must be top-level configuration objects
1093 : * of the type managed by <b>mgr</b>.
1094 : **/
1095 : config_line_t *
1096 5 : config_get_changes(const config_mgr_t *mgr,
1097 : const void *options1, const void *options2)
1098 : {
1099 5 : config_line_t *result = NULL;
1100 5 : config_line_t **next = &result;
1101 2150 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
1102 2145 : if (! config_var_should_list_changes(mv->cvar)) {
1103 : /* something else will check this var, or it doesn't need checking */
1104 530 : continue;
1105 : }
1106 1615 : const void *obj1 = config_mgr_get_obj(mgr, options1, mv->object_idx);
1107 1615 : const void *obj2 = config_mgr_get_obj(mgr, options2, mv->object_idx);
1108 :
1109 1615 : if (struct_var_eq(obj1, obj2, &mv->cvar->member)) {
1110 1611 : continue;
1111 : }
1112 :
1113 4 : const char *varname = mv->cvar->member.name;
1114 4 : config_line_t *line =
1115 4 : config_get_assigned_option(mgr, options2, varname, 1);
1116 :
1117 4 : if (line) {
1118 4 : *next = line;
1119 : } else {
1120 0 : *next = tor_malloc_zero(sizeof(config_line_t));
1121 0 : (*next)->key = tor_strdup(varname);
1122 : }
1123 8 : while (*next)
1124 4 : next = &(*next)->next;
1125 2145 : } SMARTLIST_FOREACH_END(mv);
1126 :
1127 5 : return result;
1128 : }
1129 :
1130 : /** Copy storage held by <b>old</b> into a new or_options_t and return it. */
1131 : void *
1132 235 : config_dup(const config_mgr_t *mgr, const void *old)
1133 : {
1134 235 : void *newopts;
1135 :
1136 235 : newopts = config_new(mgr);
1137 101050 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
1138 100815 : if (! config_var_needs_copy(mv->cvar)) {
1139 : // Something else will copy this option, or it doesn't need copying.
1140 24910 : continue;
1141 : }
1142 75905 : const void *oldobj = config_mgr_get_obj(mgr, old, mv->object_idx);
1143 75905 : void *newobj = config_mgr_get_obj_mutable(mgr, newopts, mv->object_idx);
1144 75905 : if (struct_var_copy(newobj, oldobj, &mv->cvar->member) < 0) {
1145 : // LCOV_EXCL_START
1146 : log_err(LD_BUG, "Unable to copy value for %s.",
1147 : mv->cvar->member.name);
1148 : tor_assert_unreached();
1149 : // LCOV_EXCL_STOP
1150 : }
1151 100815 : } SMARTLIST_FOREACH_END(mv);
1152 :
1153 235 : return newopts;
1154 : }
1155 : /** Set all vars in the configuration object <b>options</b> to their default
1156 : * values. */
1157 : void
1158 1368 : config_init(const config_mgr_t *mgr, void *options)
1159 : {
1160 1368 : CONFIG_CHECK(mgr, options);
1161 :
1162 420198 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
1163 418830 : if (!mv->cvar->initvalue)
1164 190646 : continue; /* defaults to NULL or 0 */
1165 228184 : config_reset(mgr, options, mv, 1);
1166 418830 : } SMARTLIST_FOREACH_END(mv);
1167 1368 : }
1168 :
1169 : /**
1170 : * Helper for config_validate_single: see whether any immutable option
1171 : * has changed between old_options and new_options.
1172 : *
1173 : * On success return 0; on failure set *msg_out to a newly allocated
1174 : * string explaining what is wrong, and return -1.
1175 : */
1176 : static int
1177 37 : config_check_immutable_flags(const config_format_t *fmt,
1178 : const void *old_options,
1179 : const void *new_options,
1180 : char **msg_out)
1181 : {
1182 37 : tor_assert(fmt);
1183 37 : tor_assert(new_options);
1184 37 : if (BUG(! old_options))
1185 0 : return 0;
1186 :
1187 : unsigned i;
1188 2666 : for (i = 0; fmt->vars[i].member.name; ++i) {
1189 2630 : const config_var_t *v = &fmt->vars[i];
1190 2630 : if (! config_var_has_flag(v, CFLG_IMMUTABLE))
1191 2500 : continue;
1192 :
1193 130 : if (! struct_var_eq(old_options, new_options, &v->member)) {
1194 1 : tor_asprintf(msg_out,
1195 : "While Tor is running, changing %s is not allowed",
1196 1 : v->member.name);
1197 1 : return -1;
1198 : }
1199 : }
1200 :
1201 : return 0;
1202 : }
1203 :
1204 : /**
1205 : * Normalize and validate a single object `options` within a configuration
1206 : * suite, according to its format. `options` may be modified as appropriate
1207 : * in order to set ancillary data. If `old_options` is provided, make sure
1208 : * that the transition from `old_options` to `options` is permitted.
1209 : *
1210 : * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
1211 : * string explaining what is wrong, and return a different validation_status_t
1212 : * to describe which step failed.
1213 : **/
1214 : static validation_status_t
1215 2549 : config_validate_single(const config_format_t *fmt,
1216 : const void *old_options, void *options,
1217 : char **msg_out)
1218 : {
1219 2549 : tor_assert(fmt);
1220 2549 : tor_assert(options);
1221 :
1222 2549 : if (fmt->pre_normalize_fn) {
1223 584 : if (fmt->pre_normalize_fn(options, msg_out) < 0) {
1224 : return VSTAT_PRE_NORMALIZE_ERR;
1225 : }
1226 : }
1227 :
1228 2547 : if (fmt->legacy_validate_fn) {
1229 591 : if (fmt->legacy_validate_fn(old_options, options, msg_out) < 0) {
1230 : return VSTAT_LEGACY_ERR;
1231 : }
1232 : }
1233 :
1234 2356 : if (fmt->validate_fn) {
1235 1165 : if (fmt->validate_fn(options, msg_out) < 0) {
1236 : return VSTAT_VALIDATE_ERR;
1237 : }
1238 : }
1239 :
1240 2351 : if (old_options) {
1241 37 : if (config_check_immutable_flags(fmt, old_options, options, msg_out) < 0) {
1242 : return VSTAT_TRANSITION_ERR;
1243 : }
1244 :
1245 36 : if (fmt->check_transition_fn) {
1246 8 : if (fmt->check_transition_fn(old_options, options, msg_out) < 0) {
1247 : return VSTAT_TRANSITION_ERR;
1248 : }
1249 : }
1250 : }
1251 :
1252 2349 : if (fmt->post_normalize_fn) {
1253 4 : if (fmt->post_normalize_fn(options, msg_out) < 0) {
1254 0 : return VSTAT_POST_NORMALIZE_ERR;
1255 : }
1256 : }
1257 :
1258 : return VSTAT_OK;
1259 : }
1260 :
1261 : /**
1262 : * Normalize and validate all the options in configuration object `options`
1263 : * and its sub-objects. `options` may be modified as appropriate in order to
1264 : * set ancillary data. If `old_options` is provided, make sure that the
1265 : * transition from `old_options` to `options` is permitted.
1266 : *
1267 : * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
1268 : * string explaining what is wrong, and return a different validation_status_t
1269 : * to describe which step failed.
1270 : **/
1271 : validation_status_t
1272 798 : config_validate(const config_mgr_t *mgr,
1273 : const void *old_options, void *options,
1274 : char **msg_out)
1275 : {
1276 798 : validation_status_t rv;
1277 798 : CONFIG_CHECK(mgr, options);
1278 798 : if (old_options) {
1279 13 : CONFIG_CHECK(mgr, old_options);
1280 : }
1281 :
1282 798 : config_suite_t **suitep_new = config_mgr_get_suite_ptr(mgr, options);
1283 798 : config_suite_t **suitep_old = NULL;
1284 798 : if (old_options)
1285 13 : suitep_old = config_mgr_get_suite_ptr(mgr, (void*) old_options);
1286 :
1287 : /* Validate the sub-objects */
1288 798 : if (suitep_new) {
1289 2346 : SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
1290 1759 : void *obj = smartlist_get((*suitep_new)->configs, fmt_sl_idx);
1291 1759 : const void *obj_old=NULL;
1292 1759 : if (suitep_old)
1293 32 : obj_old = smartlist_get((*suitep_old)->configs, fmt_sl_idx);
1294 :
1295 1759 : rv = config_validate_single(fmt, obj_old, obj, msg_out);
1296 1759 : if (rv < 0)
1297 8 : return rv;
1298 1751 : } SMARTLIST_FOREACH_END(fmt);
1299 : }
1300 :
1301 : /* Validate the top-level object. */
1302 790 : rv = config_validate_single(mgr->toplevel, old_options, options, msg_out);
1303 790 : if (rv < 0)
1304 : return rv;
1305 :
1306 : return VSTAT_OK;
1307 : }
1308 :
1309 : /** Allocate and return a new string holding the written-out values of the vars
1310 : * in 'options'. If 'minimal', do not write out any default-valued vars.
1311 : * Else, if comment_defaults, write default values as comments.
1312 : */
1313 : char *
1314 289 : config_dump(const config_mgr_t *mgr, const void *default_options,
1315 : const void *options, int minimal,
1316 : int comment_defaults)
1317 : {
1318 289 : const config_format_t *fmt = mgr->toplevel;
1319 289 : smartlist_t *elements;
1320 289 : const void *defaults = default_options;
1321 289 : void *defaults_tmp = NULL;
1322 289 : config_line_t *line, *assigned;
1323 289 : char *result;
1324 289 : char *msg = NULL;
1325 :
1326 289 : if (defaults == NULL) {
1327 178 : defaults = defaults_tmp = config_new(mgr);
1328 178 : config_init(mgr, defaults_tmp);
1329 : }
1330 :
1331 : /* XXX use a 1 here so we don't add a new log line while dumping */
1332 289 : if (default_options == NULL) {
1333 178 : if (config_validate(mgr, NULL, defaults_tmp, &msg) < 0) {
1334 : // LCOV_EXCL_START
1335 : log_err(LD_BUG, "Failed to validate default config: %s", msg);
1336 : tor_free(msg);
1337 : tor_assert(0);
1338 : // LCOV_EXCL_STOP
1339 : }
1340 : }
1341 :
1342 289 : elements = smartlist_new();
1343 49123 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
1344 48834 : int comment_option = 0;
1345 : /* Don't save 'hidden' control variables. */
1346 48834 : if (! config_var_is_dumpable(mv->cvar))
1347 13018 : continue;
1348 35816 : const char *name = mv->cvar->member.name;
1349 35816 : if (minimal && config_is_same(mgr, options, defaults, name))
1350 34083 : continue;
1351 1753 : else if (comment_defaults &&
1352 20 : config_is_same(mgr, options, defaults, name))
1353 1 : comment_option = 1;
1354 :
1355 1733 : line = assigned =
1356 1733 : config_get_assigned_option(mgr, options, name, 1);
1357 :
1358 5034 : for (; line; line = line->next) {
1359 1568 : if (!strcmpstart(line->key, "__")) {
1360 : /* This check detects "hidden" variables inside LINELIST_V structures.
1361 : */
1362 6 : continue;
1363 : }
1364 1562 : int value_exists = line->value && *(line->value);
1365 3123 : smartlist_add_asprintf(elements, "%s%s%s%s\n",
1366 : comment_option ? "# " : "",
1367 : line->key, value_exists ? " " : "", line->value);
1368 : }
1369 1733 : config_free_lines(assigned);
1370 48834 : } SMARTLIST_FOREACH_END(mv);
1371 :
1372 289 : if (fmt->extra) {
1373 175 : line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
1374 177 : for (; line; line = line->next) {
1375 2 : int value_exists = line->value && *(line->value);
1376 2 : smartlist_add_asprintf(elements, "%s%s%s\n",
1377 : line->key, value_exists ? " " : "", line->value);
1378 : }
1379 : }
1380 :
1381 289 : result = smartlist_join_strings(elements, "", 0, NULL);
1382 1853 : SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
1383 289 : smartlist_free(elements);
1384 289 : config_free(mgr, defaults_tmp);
1385 289 : return result;
1386 : }
1387 :
1388 : /**
1389 : * Return true if every member of <b>options</b> is in-range and well-formed.
1390 : * Return false otherwise. Log errors at level <b>severity</b>.
1391 : */
1392 : bool
1393 3 : config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
1394 : {
1395 3 : bool all_ok = true;
1396 :
1397 78 : SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
1398 75 : if (!struct_var_ok(options, &mv->cvar->member)) {
1399 1 : log_fn(severity, LD_BUG, "Invalid value for %s",
1400 : mv->cvar->member.name);
1401 1 : all_ok = false;
1402 : }
1403 75 : } SMARTLIST_FOREACH_END(mv);
1404 :
1405 3 : return all_ok;
1406 : }
|