tor

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

typedvar.c (6622B)


      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 typedvar.c
      9 * @brief Functions for accessing a pointer as an object of a given type.
     10 *
     11 * These functions represent a low-level API for accessing a typed variable.
     12 * They are used in the configuration system to examine and set fields in
     13 * configuration objects used by individual modules.
     14 *
     15 * Almost no code should call these directly.
     16 **/
     17 
     18 #include "orconfig.h"
     19 #include "lib/conf/conftypes.h"
     20 #include "lib/confmgt/type_defs.h"
     21 #include "lib/confmgt/typedvar.h"
     22 #include "lib/encoding/confline.h"
     23 #include "lib/log/escape.h"
     24 #include "lib/log/log.h"
     25 #include "lib/log/util_bug.h"
     26 #include "lib/malloc/malloc.h"
     27 #include "lib/string/printf.h"
     28 #include "lib/string/util_string.h"
     29 
     30 #include "lib/confmgt/var_type_def_st.h"
     31 
     32 #include <stddef.h>
     33 #include <string.h>
     34 
     35 /**
     36 * Try to parse a string in <b>value</b> that encodes an object of the type
     37 * defined by <b>def</b>.
     38 *
     39 * On success, adjust the lvalue pointed to by <b>target</b> to hold that
     40 * value, and return 0.  On failure, set *<b>errmsg</b> to a newly allocated
     41 * string holding an error message, and return -1.
     42 **/
     43 int
     44 typed_var_assign(void *target, const char *value, char **errmsg,
     45                    const var_type_def_t *def)
     46 {
     47  if (BUG(!def))
     48    return -1; // LCOV_EXCL_LINE
     49  // clear old value if needed.
     50  typed_var_free(target, def);
     51 
     52  tor_assert(def->fns->parse);
     53  return def->fns->parse(target, value, errmsg, def->params);
     54 }
     55 
     56 /**
     57 * Try to parse a single line from the head of<b>line</b> that encodes an
     58 * object of the type defined in <b>def</b>. On success and failure, behave as
     59 * typed_var_assign().
     60 *
     61 * All types for which keys are significant should use this function.
     62 *
     63 * Note that although multiple lines may be provided in <b>line</b>,
     64 * only the first one is handled by this function.
     65 **/
     66 int
     67 typed_var_kvassign(void *target, const config_line_t *line,
     68                      char **errmsg, const var_type_def_t *def)
     69 {
     70  if (BUG(!def))
     71    return -1; // LCOV_EXCL_LINE
     72 
     73  if (def->fns->kv_parse) {
     74    // We do _not_ free the old value here, since linelist options
     75    // sometimes have append semantics.
     76    return def->fns->kv_parse(target, line, errmsg, def->params);
     77  }
     78 
     79  int rv = typed_var_assign(target, line->value, errmsg, def);
     80  if (rv < 0 && *errmsg != NULL) {
     81    /* typed_var_assign() didn't know the line's keyword, but we do.
     82     * Let's add it to the error message. */
     83    char *oldmsg = *errmsg;
     84    tor_asprintf(errmsg, "Could not parse %s: %s", line->key, oldmsg);
     85    tor_free(oldmsg);
     86  }
     87  return rv;
     88 }
     89 
     90 /**
     91 * Release storage held by a variable in <b>target</b> of type defined by
     92 * <b>def</b>, and set <b>target</b> to a reasonable default.
     93 **/
     94 void
     95 typed_var_free(void *target, const var_type_def_t *def)
     96 {
     97  if (BUG(!def))
     98    return; // LCOV_EXCL_LINE
     99  if (def->fns->clear) {
    100    def->fns->clear(target, def->params);
    101  }
    102 }
    103 
    104 /**
    105 * Encode a value of type <b>def</b> pointed to by <b>value</b>, and return
    106 * its result in a newly allocated string.  The string may need to be escaped.
    107 *
    108 * Returns NULL if this option has a NULL value, or on internal error.
    109 **/
    110 char *
    111 typed_var_encode(const void *value, const var_type_def_t *def)
    112 {
    113  if (BUG(!def))
    114    return NULL; // LCOV_EXCL_LINE
    115  tor_assert(def->fns->encode);
    116  return def->fns->encode(value, def->params);
    117 }
    118 
    119 /**
    120 * As typed_var_encode(), but returns a newly allocated config_line_t
    121 * object.  The provided <b>key</b> is used as the key of the lines, unless
    122 * the type is one (line a linelist) that encodes its own keys.
    123 *
    124 * This function may return a list of multiple lines.
    125 *
    126 * Returns NULL if there are no lines to encode, or on internal error.
    127 */
    128 config_line_t *
    129 typed_var_kvencode(const char *key, const void *value,
    130                      const var_type_def_t *def)
    131 {
    132  if (BUG(!def))
    133    return NULL; // LCOV_EXCL_LINE
    134  if (def->fns->kv_encode) {
    135    return def->fns->kv_encode(key, value, def->params);
    136  }
    137  char *encoded_value = typed_var_encode(value, def);
    138  if (!encoded_value)
    139    return NULL;
    140 
    141  config_line_t *result = tor_malloc_zero(sizeof(config_line_t));
    142  result->key = tor_strdup(key);
    143  result->value = encoded_value;
    144  return result;
    145 }
    146 
    147 /**
    148 * Set <b>dest</b> to contain the same value as <b>src</b>. Both types
    149 * must be as defined by <b>def</b>.
    150 *
    151 * Return 0 on success, and -1 on failure.
    152 **/
    153 int
    154 typed_var_copy(void *dest, const void *src, const var_type_def_t *def)
    155 {
    156  if (BUG(!def))
    157    return -1; // LCOV_EXCL_LINE
    158  if (def->fns->copy) {
    159    // If we have been provided a copy function, use it.
    160    return def->fns->copy(dest, src, def);
    161  }
    162 
    163  // Otherwise, encode 'src' and parse the result into 'def'.
    164  char *enc = typed_var_encode(src, def);
    165  if (!enc) {
    166    typed_var_free(dest, def);
    167    return 0;
    168  }
    169  char *err = NULL;
    170  int rv = typed_var_assign(dest, enc, &err, def);
    171  if (BUG(rv < 0)) {
    172    // LCOV_EXCL_START
    173    log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s",
    174             escaped(enc), def->name, err?err:"");
    175    // LCOV_EXCL_STOP
    176  }
    177  tor_free(err);
    178  tor_free(enc);
    179  return rv;
    180 }
    181 
    182 /**
    183 * Return true if <b>a</b> and <b>b</b> are semantically equivalent.
    184 * Both types must be as defined by <b>def</b>.
    185 **/
    186 bool
    187 typed_var_eq(const void *a, const void *b, const var_type_def_t *def)
    188 {
    189  if (BUG(!def))
    190    return false; // LCOV_EXCL_LINE
    191 
    192  if (def->fns->eq) {
    193    // Use a provided eq function if we got one.
    194    return def->fns->eq(a, b, def->params);
    195  }
    196 
    197  // Otherwise, encode the values and compare them.
    198  char *enc_a = typed_var_encode(a, def);
    199  char *enc_b = typed_var_encode(b, def);
    200  bool eq = !strcmp_opt(enc_a,enc_b);
    201  tor_free(enc_a);
    202  tor_free(enc_b);
    203  return eq;
    204 }
    205 
    206 /**
    207 * Check whether <b>value</b> encodes a valid value according to the
    208 * type definition in <b>def</b>.
    209 */
    210 bool
    211 typed_var_ok(const void *value, const var_type_def_t *def)
    212 {
    213  if (BUG(!def))
    214    return false; // LCOV_EXCL_LINE
    215 
    216  if (def->fns->ok)
    217    return def->fns->ok(value, def->params);
    218 
    219  return true;
    220 }
    221 
    222 /**
    223 * Mark <b>value</b> -- a variable that ordinarily would be extended by
    224 * assignment -- as "fragile", so that it will get replaced by the next
    225 * assignment instead.
    226 **/
    227 void
    228 typed_var_mark_fragile(void *value, const var_type_def_t *def)
    229 {
    230  if (BUG(!def)) {
    231    return; // LCOV_EXCL_LINE
    232  }
    233 
    234  if (def->fns->mark_fragile)
    235    def->fns->mark_fragile(value, def->params);
    236 }