tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

confmgt.c (44489B)


      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 managed_var_free_(managed_var_t *mv)
     67 {
     68  if (!mv)
     69    return;
     70  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 config_suite_new(void)
     87 {
     88  config_suite_t *suite = tor_malloc_zero(sizeof(config_suite_t));
     89  suite->configs = smartlist_new();
     90  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 config_suite_free_(config_suite_t *suite)
     97 {
     98  if (!suite)
     99    return;
    100  smartlist_free(suite->configs);
    101  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 config_mgr_new(const config_format_t *toplevel_fmt)
    146 {
    147  config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
    148  mgr->subconfigs = smartlist_new();
    149  mgr->all_vars = smartlist_new();
    150  mgr->all_abbrevs = smartlist_new();
    151  mgr->all_deprecations = smartlist_new();
    152 
    153  config_mgr_register_fmt(mgr, toplevel_fmt, IDX_TOPLEVEL);
    154  mgr->toplevel = toplevel_fmt;
    155 
    156  return mgr;
    157 }
    158 
    159 /** Add a config_format_t to a manager, with a specified (unique) index. */
    160 static void
    161 config_mgr_register_fmt(config_mgr_t *mgr,
    162                        const config_format_t *fmt,
    163                        int object_idx)
    164 {
    165  int i;
    166 
    167  tor_assertf(!mgr->frozen,
    168              "Tried to add a format to a configuration manager after "
    169              "it had been frozen.");
    170 
    171  if (object_idx != IDX_TOPLEVEL) {
    172    tor_assertf(! fmt->has_config_suite,
    173          "Tried to register a toplevel format in a non-toplevel position");
    174  }
    175  if (fmt->config_suite_offset) {
    176    tor_assertf(fmt->has_config_suite,
    177                "config_suite_offset was set, but has_config_suite was not.");
    178  }
    179 
    180  tor_assertf(fmt != mgr->toplevel &&
    181              ! smartlist_contains(mgr->subconfigs, fmt),
    182              "Tried to register an already-registered format.");
    183 
    184  /* register variables */
    185  for (i = 0; fmt->vars[i].member.name; ++i) {
    186    managed_var_t *mv = tor_malloc_zero(sizeof(managed_var_t));
    187    mv->cvar = &fmt->vars[i];
    188    mv->object_idx = object_idx;
    189    smartlist_add(mgr->all_vars, mv);
    190  }
    191 
    192  /* register abbrevs */
    193  if (fmt->abbrevs) {
    194    for (i = 0; fmt->abbrevs[i].abbreviated; ++i) {
    195      smartlist_add(mgr->all_abbrevs, (void*)&fmt->abbrevs[i]);
    196    }
    197  }
    198 
    199  /* register deprecations. */
    200  if (fmt->deprecations) {
    201    const config_deprecation_t *d;
    202    for (d = fmt->deprecations; d->name; ++d) {
    203      smartlist_add(mgr->all_deprecations, (void*)d);
    204    }
    205  }
    206 }
    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 config_mgr_add_format(config_mgr_t *mgr,
    217                      const config_format_t *fmt)
    218 {
    219  tor_assert(mgr);
    220  int idx = smartlist_len(mgr->subconfigs);
    221  config_mgr_register_fmt(mgr, fmt, idx);
    222  smartlist_add(mgr->subconfigs, (void *)fmt);
    223  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 config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
    230 {
    231  if (! mgr->toplevel->has_config_suite)
    232    return NULL;
    233  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 config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
    247 {
    248  tor_assert(mgr);
    249  tor_assert(toplevel);
    250  if (idx == IDX_TOPLEVEL)
    251    return toplevel;
    252 
    253  tor_assertf(idx >= 0 && idx < smartlist_len(mgr->subconfigs),
    254              "Index %d is out of range.", idx);
    255  config_suite_t **suite = config_mgr_get_suite_ptr(mgr, toplevel);
    256  tor_assert(suite);
    257  tor_assert(smartlist_len(mgr->subconfigs) ==
    258             smartlist_len((*suite)->configs));
    259 
    260  return smartlist_get((*suite)->configs, idx);
    261 }
    262 
    263 /** As config_mgr_get_obj_mutable(), but return a const pointer. */
    264 const void *
    265 config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
    266 {
    267  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 managed_var_cmp(const void **a, const void **b)
    273 {
    274  const managed_var_t *mv1 = *(const managed_var_t**)a;
    275  const managed_var_t *mv2 = *(const managed_var_t**)b;
    276 
    277  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 config_mgr_freeze(config_mgr_t *mgr)
    286 {
    287  static uint64_t mgr_count = 0;
    288 
    289  smartlist_sort(mgr->all_vars, managed_var_cmp);
    290  memcpy(&mgr->toplevel_magic, &mgr->toplevel->magic,
    291         sizeof(struct_magic_decl_t));
    292  uint64_t magic_input[3] = { mgr->toplevel_magic.magic_val,
    293                              (uint64_t) (uintptr_t) mgr,
    294                              ++mgr_count };
    295  mgr->toplevel_magic.magic_val =
    296    (uint32_t)siphash24g(magic_input, sizeof(magic_input));
    297  mgr->frozen = true;
    298 }
    299 
    300 /** Release all storage held in <b>mgr</b> */
    301 void
    302 config_mgr_free_(config_mgr_t *mgr)
    303 {
    304  if (!mgr)
    305    return;
    306  SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv, managed_var_free(mv));
    307  smartlist_free(mgr->all_vars);
    308  smartlist_free(mgr->all_abbrevs);
    309  smartlist_free(mgr->all_deprecations);
    310  smartlist_free(mgr->subconfigs);
    311  memset(mgr, 0, sizeof(*mgr));
    312  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 config_mgr_list_vars(const config_mgr_t *mgr)
    320 {
    321  smartlist_t *result = smartlist_new();
    322  tor_assert(mgr);
    323  SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv,
    324                    smartlist_add(result, (void*) mv->cvar));
    325  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 config_mgr_list_deprecated_vars(const config_mgr_t *mgr)
    334 {
    335  smartlist_t *result = smartlist_new();
    336  tor_assert(mgr);
    337  SMARTLIST_FOREACH(mgr->all_deprecations, config_deprecation_t *, d,
    338                    smartlist_add(result, (char*)d->name));
    339  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 config_check_toplevel_magic(const config_mgr_t *mgr,
    348                            const void *object)
    349 {
    350  struct_check_magic(object, &mgr->toplevel_magic);
    351 }
    352 
    353 /** Assert that the magic fields in <b>options</b> and its subsidiary
    354 * objects are all okay. */
    355 static void
    356 config_mgr_assert_magic_ok(const config_mgr_t *mgr,
    357                           const void *options)
    358 {
    359  tor_assert(mgr);
    360  tor_assert(options);
    361  tor_assert(mgr->frozen);
    362  struct_check_magic(options, &mgr->toplevel_magic);
    363 
    364  config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, (void*)options);
    365  if (suitep == NULL) {
    366    tor_assert(smartlist_len(mgr->subconfigs) == 0);
    367    return;
    368  }
    369 
    370  tor_assert(smartlist_len((*suitep)->configs) ==
    371             smartlist_len(mgr->subconfigs));
    372  SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
    373    void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
    374    tor_assert(obj);
    375    struct_check_magic(obj, &fmt->magic);
    376  } 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 config_new(const config_mgr_t *mgr)
    388 {
    389  tor_assert(mgr->frozen);
    390  void *opts = tor_malloc_zero(mgr->toplevel->size);
    391  struct_set_magic(opts, &mgr->toplevel_magic);
    392  config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, opts);
    393  if (suitep) {
    394    *suitep = config_suite_new();
    395    SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
    396      void *obj = tor_malloc_zero(fmt->size);
    397      struct_set_magic(obj, &fmt->magic);
    398      smartlist_add((*suitep)->configs, obj);
    399    } SMARTLIST_FOREACH_END(fmt);
    400  }
    401  CONFIG_CHECK(mgr, opts);
    402  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 config_expand_abbrev(const config_mgr_t *mgr, const char *option,
    416                     int command_line, int warn_obsolete)
    417 {
    418  SMARTLIST_FOREACH_BEGIN(mgr->all_abbrevs, const config_abbrev_t *, abbrev) {
    419    /* Abbreviations are case insensitive. */
    420    if (!strcasecmp(option, abbrev->abbreviated) &&
    421        (command_line || !abbrev->commandline_only)) {
    422      if (warn_obsolete && abbrev->warn) {
    423        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      option = abbrev->full;
    433    }
    434  } SMARTLIST_FOREACH_END(abbrev);
    435  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 config_find_deprecation(const config_mgr_t *mgr, const char *key)
    443 {
    444  if (BUG(mgr == NULL) || BUG(key == NULL))
    445    return NULL; // LCOV_EXCL_LINE
    446 
    447  SMARTLIST_FOREACH_BEGIN(mgr->all_deprecations, const config_deprecation_t *,
    448                          d) {
    449    if (!strcasecmp(d->name, key)) {
    450      return d->why_deprecated ? d->why_deprecated : "";
    451    }
    452  } 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-&gt;all_vars, or to -1 if the variable is
    465 * not found.
    466 */
    467 static const managed_var_t *
    468 config_mgr_find_var(const config_mgr_t *mgr,
    469                    const char *key,
    470                    bool allow_truncated, int *idx_out)
    471 {
    472  const size_t keylen = strlen(key);
    473  if (idx_out)
    474    *idx_out = -1;
    475 
    476  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  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
    481    if (!strcasecmp(mv->cvar->member.name, key)) {
    482      if (idx_out)
    483        *idx_out = mv_sl_idx;
    484      return mv;
    485    }
    486  } SMARTLIST_FOREACH_END(mv);
    487 
    488  if (!allow_truncated)
    489    return NULL;
    490 
    491  /* If none, check for an abbreviated match */
    492  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
    493    if (!strncasecmp(key, mv->cvar->member.name, keylen)) {
    494      log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
    495               "Please use '%s' instead",
    496               key, mv->cvar->member.name);
    497      if (idx_out)
    498        *idx_out = mv_sl_idx;
    499      return mv;
    500    }
    501  } 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 config_find_option_name(const config_mgr_t *mgr, const char *key)
    514 {
    515  key = config_expand_abbrev(mgr, key, 0, 0);
    516  const managed_var_t *mv = config_mgr_find_var(mgr, key, true, NULL);
    517  if (mv)
    518    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 config_count_options(const config_mgr_t *mgr)
    526 {
    527  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 config_var_has_flag(const config_var_t *var, uint32_t flag)
    536 {
    537  uint32_t have_flags = var->flags | struct_var_get_flags(&var->member);
    538 
    539  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 config_var_is_replaced_on_set(const config_var_t *var)
    549 {
    550  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 config_var_is_settable(const config_var_t *var)
    559 {
    560  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 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  (void)var;
    577  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 config_var_should_list_changes(const config_var_t *var)
    590 {
    591  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 config_var_needs_copy(const config_var_t *var)
    604 {
    605  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 config_var_is_listable(const config_var_t *var)
    620 {
    621  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 config_var_is_dumpable(const config_var_t *var)
    634 {
    635  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 config_assign_value(const config_mgr_t *mgr, void *options,
    649                    config_line_t *c, char **msg)
    650 {
    651  const managed_var_t *var;
    652 
    653  CONFIG_CHECK(mgr, options);
    654 
    655  var = config_mgr_find_var(mgr, c->key, true, NULL);
    656  tor_assert(var);
    657  tor_assert(!strcmp(c->key, var->cvar->member.name));
    658  void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
    659 
    660  if (config_var_has_flag(var->cvar, CFLG_WARN_OBSOLETE)) {
    661    log_warn(LD_GENERAL, "Skipping obsolete configuration option \"%s\".",
    662             var->cvar->member.name);
    663  } else if (config_var_has_flag(var->cvar, CFLG_WARN_DISABLED)) {
    664    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  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 config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
    675 {
    676  tor_assert(mgr);
    677  tor_assert(options);
    678 
    679  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
    680    void *object = config_mgr_get_obj_mutable(mgr, options, mv->object_idx);
    681    struct_var_mark_fragile(object, &mv->cvar->member);
    682  } SMARTLIST_FOREACH_END(mv);
    683 }
    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 warn_deprecated_option(const char *what, const char *why)
    693 {
    694  const char *space = (why && strlen(why)) ? " " : "";
    695  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 }
    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 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  const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
    716  const unsigned clear_first = flags & CAL_CLEAR_FIRST;
    717  const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
    718  const managed_var_t *mvar;
    719 
    720  CONFIG_CHECK(mgr, options);
    721 
    722  int var_index = -1;
    723  mvar = config_mgr_find_var(mgr, c->key, true, &var_index);
    724  if (!mvar) {
    725    const config_format_t *fmt = mgr->toplevel;
    726    if (fmt->extra) {
    727      void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
    728      log_info(LD_CONFIG,
    729               "Found unrecognized option '%s'; saving it.", c->key);
    730      config_line_append((config_line_t**)lvalue, c->key, c->value);
    731      return 0;
    732    } else {
    733      tor_asprintf(msg,
    734                "Unknown option '%s'.  Failing.", c->key);
    735      return -1;
    736    }
    737  }
    738 
    739  const config_var_t *cvar = mvar->cvar;
    740  tor_assert(cvar);
    741 
    742  /* Put keyword into canonical case. */
    743  if (strcmp(cvar->member.name, c->key)) {
    744    tor_free(c->key);
    745    c->key = tor_strdup(cvar->member.name);
    746  }
    747 
    748  const char *deprecation_msg;
    749  if (warn_deprecations &&
    750      (deprecation_msg = config_find_deprecation(mgr, cvar->member.name))) {
    751    warn_deprecated_option(cvar->member.name, deprecation_msg);
    752  }
    753 
    754  if (!strlen(c->value)) {
    755    /* reset or clear it, then return */
    756    if (!clear_first) {
    757      if (! config_var_is_replaced_on_set(cvar) &&
    758          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        log_warn(LD_CONFIG,
    762                 "Linelist option '%s' has no value. Skipping.", c->key);
    763      } else { /* not already cleared */
    764        config_reset(mgr, options, mvar, use_defaults);
    765      }
    766    }
    767    return 0;
    768  } 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  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    tor_assert(var_index >= 0);
    783    if (bitarray_is_set(options_seen, var_index)) {
    784      log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
    785               "value will be ignored.", cvar->member.name);
    786    }
    787    bitarray_set(options_seen, var_index);
    788  }
    789 
    790  if (config_assign_value(mgr, options, c, msg) < 0)
    791    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 config_reset_line(const config_mgr_t *mgr, void *options,
    799                  const char *key, int use_defaults)
    800 {
    801  const managed_var_t *var;
    802 
    803  CONFIG_CHECK(mgr, options);
    804 
    805  var = config_mgr_find_var(mgr, key, true, NULL);
    806  if (!var)
    807    return; /* give error on next pass. */
    808 
    809  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 config_value_needs_escape(const char *value)
    816 {
    817  if (*value == '\"')
    818    return 1;
    819  while (*value) {
    820    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    default:
    830      if (!TOR_ISPRINT(*value))
    831        return 1;
    832    }
    833    ++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 config_get_assigned_option(const config_mgr_t *mgr, const void *options,
    844                           const char *key, int escape_val)
    845 {
    846  const managed_var_t *var;
    847  config_line_t *result;
    848 
    849  tor_assert(options && key);
    850 
    851  CONFIG_CHECK(mgr, options);
    852 
    853  var = config_mgr_find_var(mgr, key, true, NULL);
    854  if (!var) {
    855    log_warn(LD_CONFIG, "Unknown option '%s'.  Failing.", key);
    856    return NULL;
    857  }
    858  if (! config_var_is_gettable(var->cvar)) {
    859    log_warn(LD_CONFIG, "Option '%s' is obsolete or unfetchable. Failing.",
    860             key);
    861    return NULL;
    862  }
    863  const void *object = config_mgr_get_obj(mgr, options, var->object_idx);
    864 
    865  result = struct_var_kvencode(object, &var->cvar->member);
    866 
    867  if (escape_val) {
    868    config_line_t *line;
    869    for (line = result; line; line = line->next) {
    870      if (line->value && config_value_needs_escape(line->value)) {
    871        char *newval = esc_for_log(line->value);
    872        tor_free(line->value);
    873        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 config_assign(const config_mgr_t *mgr, void *options, config_line_t *list,
    938              unsigned config_assign_flags, char **msg)
    939 {
    940  config_line_t *p;
    941  bitarray_t *options_seen;
    942  const int n_options = config_count_options(mgr);
    943  const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
    944  const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
    945 
    946  CONFIG_CHECK(mgr, options);
    947 
    948  /* pass 1: normalize keys */
    949  for (p = list; p; p = p->next) {
    950    const char *full = config_expand_abbrev(mgr, p->key, 0, 1);
    951    if (strcmp(full,p->key)) {
    952      tor_free(p->key);
    953      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  if (clear_first) {
    960    for (p = list; p; p = p->next)
    961      config_reset_line(mgr, options, p->key, use_defaults);
    962  }
    963 
    964  options_seen = bitarray_init_zero(n_options);
    965  /* pass 3: assign. */
    966  while (list) {
    967    int r;
    968    if ((r=config_assign_line(mgr, options, list, config_assign_flags,
    969                              options_seen, msg))) {
    970      bitarray_free(options_seen);
    971      return r;
    972    }
    973    list = list->next;
    974  }
    975  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  config_mark_lists_fragile(mgr, options);
    981 
    982  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 config_clear(const config_mgr_t *mgr, void *options, const managed_var_t *var)
    989 {
    990  void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
    991  struct_var_free(object, &var->cvar->member);
    992 }
    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 config_reset(const config_mgr_t *mgr, void *options,
    999             const managed_var_t *var, int use_defaults)
   1000 {
   1001  config_line_t *c;
   1002  char *msg = NULL;
   1003  CONFIG_CHECK(mgr, options);
   1004  config_clear(mgr, options, var); /* clear it first */
   1005 
   1006  if (!use_defaults)
   1007    return; /* all done */
   1008 
   1009  if (var->cvar->initvalue) {
   1010    c = tor_malloc_zero(sizeof(config_line_t));
   1011    c->key = tor_strdup(var->cvar->member.name);
   1012    c->value = tor_strdup(var->cvar->initvalue);
   1013    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    config_free_lines(c);
   1020  }
   1021 }
   1022 
   1023 /** Release storage held by <b>options</b>. */
   1024 void
   1025 config_free_(const config_mgr_t *mgr, void *options)
   1026 {
   1027  if (!options)
   1028    return;
   1029 
   1030  tor_assert(mgr);
   1031 
   1032  if (mgr->toplevel->clear_fn) {
   1033    mgr->toplevel->clear_fn(mgr, options);
   1034  }
   1035  config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, options);
   1036  if (suitep) {
   1037    tor_assert(smartlist_len((*suitep)->configs) ==
   1038               smartlist_len(mgr->subconfigs));
   1039    SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
   1040      void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
   1041      if (fmt->clear_fn) {
   1042        fmt->clear_fn(mgr, obj);
   1043      }
   1044    } SMARTLIST_FOREACH_END(fmt);
   1045  }
   1046 
   1047  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
   1048    config_clear(mgr, options, mv);
   1049  } SMARTLIST_FOREACH_END(mv);
   1050 
   1051  if (mgr->toplevel->extra) {
   1052    config_line_t **linep = STRUCT_VAR_P(options,
   1053                                         mgr->toplevel->extra->offset);
   1054    config_free_lines(*linep);
   1055    *linep = NULL;
   1056  }
   1057 
   1058  if (suitep) {
   1059    SMARTLIST_FOREACH((*suitep)->configs, void *, obj, tor_free(obj));
   1060    config_suite_free(*suitep);
   1061  }
   1062 
   1063  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 config_is_same(const config_mgr_t *mgr,
   1071               const void *o1, const void *o2,
   1072               const char *name)
   1073 {
   1074  CONFIG_CHECK(mgr, o1);
   1075  CONFIG_CHECK(mgr, o2);
   1076 
   1077  const managed_var_t *var = config_mgr_find_var(mgr, name, true, NULL);
   1078  if (!var) {
   1079    return true;
   1080  }
   1081  const void *obj1 = config_mgr_get_obj(mgr, o1, var->object_idx);
   1082  const void *obj2 = config_mgr_get_obj(mgr, o2, var->object_idx);
   1083 
   1084  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 config_get_changes(const config_mgr_t *mgr,
   1097                   const void *options1, const void *options2)
   1098 {
   1099  config_line_t *result = NULL;
   1100  config_line_t **next = &result;
   1101  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
   1102    if (! config_var_should_list_changes(mv->cvar)) {
   1103      /* something else will check this var, or it doesn't need checking */
   1104      continue;
   1105    }
   1106    const void *obj1 = config_mgr_get_obj(mgr, options1, mv->object_idx);
   1107    const void *obj2 = config_mgr_get_obj(mgr, options2, mv->object_idx);
   1108 
   1109    if (struct_var_eq(obj1, obj2, &mv->cvar->member)) {
   1110      continue;
   1111    }
   1112 
   1113    const char *varname = mv->cvar->member.name;
   1114    config_line_t *line =
   1115      config_get_assigned_option(mgr, options2, varname, 1);
   1116 
   1117    if (line) {
   1118      *next = line;
   1119    } else {
   1120      *next = tor_malloc_zero(sizeof(config_line_t));
   1121      (*next)->key = tor_strdup(varname);
   1122    }
   1123    while (*next)
   1124      next = &(*next)->next;
   1125  } SMARTLIST_FOREACH_END(mv);
   1126 
   1127  return result;
   1128 }
   1129 
   1130 /** Copy storage held by <b>old</b> into a new or_options_t and return it. */
   1131 void *
   1132 config_dup(const config_mgr_t *mgr, const void *old)
   1133 {
   1134  void *newopts;
   1135 
   1136  newopts = config_new(mgr);
   1137  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
   1138    if (! config_var_needs_copy(mv->cvar)) {
   1139      // Something else will copy this option, or it doesn't need copying.
   1140      continue;
   1141    }
   1142    const void *oldobj = config_mgr_get_obj(mgr, old, mv->object_idx);
   1143    void *newobj = config_mgr_get_obj_mutable(mgr, newopts, mv->object_idx);
   1144    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  } SMARTLIST_FOREACH_END(mv);
   1152 
   1153  return newopts;
   1154 }
   1155 /** Set all vars in the configuration object <b>options</b> to their default
   1156 * values. */
   1157 void
   1158 config_init(const config_mgr_t *mgr, void *options)
   1159 {
   1160  CONFIG_CHECK(mgr, options);
   1161 
   1162  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
   1163    if (!mv->cvar->initvalue)
   1164      continue; /* defaults to NULL or 0 */
   1165    config_reset(mgr, options, mv, 1);
   1166  } SMARTLIST_FOREACH_END(mv);
   1167 }
   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 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  tor_assert(fmt);
   1183  tor_assert(new_options);
   1184  if (BUG(! old_options))
   1185    return 0;
   1186 
   1187  unsigned i;
   1188  for (i = 0; fmt->vars[i].member.name; ++i) {
   1189    const config_var_t *v = &fmt->vars[i];
   1190    if (! config_var_has_flag(v, CFLG_IMMUTABLE))
   1191      continue;
   1192 
   1193    if (! struct_var_eq(old_options, new_options, &v->member)) {
   1194      tor_asprintf(msg_out,
   1195                   "While Tor is running, changing %s is not allowed",
   1196                   v->member.name);
   1197      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 config_validate_single(const config_format_t *fmt,
   1216                       const void *old_options, void *options,
   1217                       char **msg_out)
   1218 {
   1219  tor_assert(fmt);
   1220  tor_assert(options);
   1221 
   1222  if (fmt->pre_normalize_fn) {
   1223    if (fmt->pre_normalize_fn(options, msg_out) < 0) {
   1224      return VSTAT_PRE_NORMALIZE_ERR;
   1225    }
   1226  }
   1227 
   1228  if (fmt->legacy_validate_fn) {
   1229    if (fmt->legacy_validate_fn(old_options, options, msg_out) < 0) {
   1230      return VSTAT_LEGACY_ERR;
   1231    }
   1232  }
   1233 
   1234  if (fmt->validate_fn) {
   1235    if (fmt->validate_fn(options, msg_out) < 0) {
   1236      return VSTAT_VALIDATE_ERR;
   1237    }
   1238  }
   1239 
   1240  if (old_options) {
   1241    if (config_check_immutable_flags(fmt, old_options, options, msg_out) < 0) {
   1242      return VSTAT_TRANSITION_ERR;
   1243    }
   1244 
   1245    if (fmt->check_transition_fn) {
   1246      if (fmt->check_transition_fn(old_options, options, msg_out) < 0) {
   1247        return VSTAT_TRANSITION_ERR;
   1248      }
   1249    }
   1250  }
   1251 
   1252  if (fmt->post_normalize_fn) {
   1253    if (fmt->post_normalize_fn(options, msg_out) < 0) {
   1254      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 config_validate(const config_mgr_t *mgr,
   1273                const void *old_options, void *options,
   1274                char **msg_out)
   1275 {
   1276  validation_status_t rv;
   1277  CONFIG_CHECK(mgr, options);
   1278  if (old_options) {
   1279    CONFIG_CHECK(mgr, old_options);
   1280  }
   1281 
   1282  config_suite_t **suitep_new = config_mgr_get_suite_ptr(mgr, options);
   1283  config_suite_t **suitep_old = NULL;
   1284  if (old_options)
   1285    suitep_old = config_mgr_get_suite_ptr(mgr, (void*) old_options);
   1286 
   1287  /* Validate the sub-objects */
   1288  if (suitep_new) {
   1289    SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
   1290      void *obj = smartlist_get((*suitep_new)->configs, fmt_sl_idx);
   1291      const void *obj_old=NULL;
   1292      if (suitep_old)
   1293        obj_old = smartlist_get((*suitep_old)->configs, fmt_sl_idx);
   1294 
   1295      rv = config_validate_single(fmt, obj_old, obj, msg_out);
   1296      if (rv < 0)
   1297        return rv;
   1298    } SMARTLIST_FOREACH_END(fmt);
   1299  }
   1300 
   1301  /* Validate the top-level object. */
   1302  rv = config_validate_single(mgr->toplevel, old_options, options, msg_out);
   1303  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 config_dump(const config_mgr_t *mgr, const void *default_options,
   1315            const void *options, int minimal,
   1316            int comment_defaults)
   1317 {
   1318  const config_format_t *fmt = mgr->toplevel;
   1319  smartlist_t *elements;
   1320  const void *defaults = default_options;
   1321  void *defaults_tmp = NULL;
   1322  config_line_t *line, *assigned;
   1323  char *result;
   1324  char *msg = NULL;
   1325 
   1326  if (defaults == NULL) {
   1327    defaults = defaults_tmp = config_new(mgr);
   1328    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  if (default_options == NULL) {
   1333    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  elements = smartlist_new();
   1343  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
   1344    int comment_option = 0;
   1345    /* Don't save 'hidden' control variables. */
   1346    if (! config_var_is_dumpable(mv->cvar))
   1347      continue;
   1348    const char *name = mv->cvar->member.name;
   1349    if (minimal && config_is_same(mgr, options, defaults, name))
   1350      continue;
   1351    else if (comment_defaults &&
   1352             config_is_same(mgr, options, defaults, name))
   1353      comment_option = 1;
   1354 
   1355    line = assigned =
   1356      config_get_assigned_option(mgr, options, name, 1);
   1357 
   1358    for (; line; line = line->next) {
   1359      if (!strcmpstart(line->key, "__")) {
   1360        /* This check detects "hidden" variables inside LINELIST_V structures.
   1361         */
   1362        continue;
   1363      }
   1364      int value_exists = line->value && *(line->value);
   1365      smartlist_add_asprintf(elements, "%s%s%s%s\n",
   1366                   comment_option ? "# " : "",
   1367                   line->key, value_exists ? " " : "", line->value);
   1368    }
   1369    config_free_lines(assigned);
   1370  } SMARTLIST_FOREACH_END(mv);
   1371 
   1372  if (fmt->extra) {
   1373    line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
   1374    for (; line; line = line->next) {
   1375      int value_exists = line->value && *(line->value);
   1376      smartlist_add_asprintf(elements, "%s%s%s\n",
   1377                             line->key, value_exists ? " " : "", line->value);
   1378    }
   1379  }
   1380 
   1381  result = smartlist_join_strings(elements, "", 0, NULL);
   1382  SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
   1383  smartlist_free(elements);
   1384  config_free(mgr, defaults_tmp);
   1385  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 config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
   1394 {
   1395  bool all_ok = true;
   1396 
   1397  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
   1398    if (!struct_var_ok(options, &mv->cvar->member)) {
   1399      log_fn(severity, LD_BUG, "Invalid value for %s",
   1400             mv->cvar->member.name);
   1401      all_ok = false;
   1402    }
   1403  } SMARTLIST_FOREACH_END(mv);
   1404 
   1405  return all_ok;
   1406 }