config.c 87.2 KB
Newer Older
Roger Dingledine's avatar
Roger Dingledine committed
1
2
/* Copyright 2001 Matej Pfajfar.
 * Copyright 2001-2004 Roger Dingledine.
Nick Mathewson's avatar
Nick Mathewson committed
3
 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
4
5
/* See LICENSE for licensing information */
/* $Id$ */
6
const char config_c_id[] = "$Id$";
7

Nick Mathewson's avatar
Nick Mathewson committed
8
/**
9
10
 * \file config.c
 * \brief Code to parse and interpret configuration files.
Nick Mathewson's avatar
Nick Mathewson committed
11
12
 **/

Roger Dingledine's avatar
Roger Dingledine committed
13
#include "or.h"
14
15
16
#ifdef MS_WINDOWS
#include <shlobj.h>
#endif
17
#include "../common/aes.h"
Roger Dingledine's avatar
Roger Dingledine committed
18

Nick Mathewson's avatar
Nick Mathewson committed
19
20
/** Enumeration of types which option values can take */
typedef enum config_type_t {
21
22
  CONFIG_TYPE_STRING = 0,   /**< An arbitrary string. */
  CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
23
24
  CONFIG_TYPE_INTERVAL,     /**< A number of seconds, with optional units*/
  CONFIG_TYPE_MEMUNIT,      /**< A number of bytes, with optional units*/
25
26
27
28
29
  CONFIG_TYPE_DOUBLE,       /**< A floating-point value */
  CONFIG_TYPE_BOOL,         /**< A boolean value, expressed as 0 or 1. */
  CONFIG_TYPE_CSV,          /**< A list of strings, separated by commas and optional
                              * whitespace. */
  CONFIG_TYPE_LINELIST,     /**< Uninterpreted config lines */
30
31
32
33
34
  CONFIG_TYPE_LINELIST_S,   /**< Uninterpreted, context-sensitive config lines,
                             * mixed with other keywords. */
  CONFIG_TYPE_LINELIST_V,   /**< Catch-all "virtual" option to summarize
                             * context-sensitive config lines when fetching.
                             */
35
  CONFIG_TYPE_OBSOLETE,     /**< Obsolete (ignored) option. */
Nick Mathewson's avatar
Nick Mathewson committed
36
} config_type_t;
37

Nick Mathewson's avatar
Nick Mathewson committed
38
/* An abbreviation for a configuration option allowed on the command line */
39
typedef struct config_abbrev_t {
40
41
  const char *abbreviated;
  const char *full;
42
  int commandline_only;
43
44
} config_abbrev_t;

45
46
47
48
/* Handy macro for declaring "In the config file or on the command line,
 * you can abbreviate <b>tok</b>s as <b>tok</b>". */
#define PLURAL(tok) { #tok, #tok "s", 0 }

Nick Mathewson's avatar
Nick Mathewson committed
49
/* A list of command-line abbreviations. */
50
static config_abbrev_t _config_abbrevs[] = {
51
  PLURAL(ExitNode),
52
  PLURAL(EntryNode),
53
54
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
55
  PLURAL(LongLivedPort),
56
57
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
58
  PLURAL(NumCpu),
59
60
  PLURAL(RendNode),
  PLURAL(RendExcludeNode),
61
62
  PLURAL(StrictEntryNode),
  PLURAL(StrictExitNode),
63
  { "l", "Log", 1},
64
65
  { "BandwidthRateBytes", "BandwidthRate", 0},
  { "BandwidthBurstBytes", "BandwidthBurst", 0},
66
  { "DirFetchPostPeriod", "StatusFetchPeriod", 0},
67
  { "MaxConn", "ConnLimit", 0},
68
  { NULL, NULL , 0},
69
};
70
#undef PLURAL
71

72
/** A variable allowed in the configuration file or on the command line. */
73
typedef struct config_var_t {
74
75
76
77
  const char *name; /**< The full keyword (case insensitive). */
  config_type_t type; /**< How to interpret the type and turn it into a value. */
  off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
  const char *initvalue; /**< String (or null) describing initial value. */
78
79
} config_var_t;

Nick Mathewson's avatar
Nick Mathewson committed
80
/** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
Nick Mathewson's avatar
Nick Mathewson committed
81
#define STRUCT_OFFSET(tp, member) ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
Nick Mathewson's avatar
Nick Mathewson committed
82
83
84
85
/** An entry for config_vars: "The option <b>name</b> has type
 * CONFIG_TYPE_<b>conftype</b>, and corresponds to
 * or_options_t.<b>member</b>"
 */
86
87
#define VAR(name,conftype,member,initvalue) \
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member), initvalue }
Nick Mathewson's avatar
Nick Mathewson committed
88
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
89
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL }
90

Nick Mathewson's avatar
Nick Mathewson committed
91
92
93
94
/** Array of configuration options.  Until we disallow nonstandard
 * abbreviations, order is significant, since the first matching option will
 * be chosen first.
 */
95
static config_var_t _config_vars[] = {
96
  VAR("Address",             STRING,   Address,              NULL),
97
  VAR("AccountingStart",     STRING,   AccountingStart,      NULL),
98
  VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes, "middle,rendezvous"),
99
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
100
  VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "2 MB"),
101
  VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "5 MB"),
102
  VAR("MaxAdvertisedBandwidth",MEMUNIT,MaxAdvertisedBandwidth,"128 TB"),
103
104
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
105
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
106
  VAR("CookieAuthentication",BOOL,     CookieAuthentication, "0"),
107
108
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
109
  VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
110
111
  VAR("DirPort",             UINT,     DirPort,              "0"),
  VAR("DirBindAddress",      LINELIST, DirBindAddress,       NULL),
112
113
  /** DOCDOC **/
  VAR("DirFetchPeriod",      INTERVAL, DirFetchPeriod,       "0 seconds"),
114
115
  VAR("DirPostPeriod",       INTERVAL, DirPostPeriod,        "20 minutes"),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
116
117
118
119
120
121
122
123
  VAR("DirPolicy",           LINELIST, DirPolicy,            NULL),
  VAR("DirServer",           LINELIST, DirServers,           NULL),
  VAR("ExitNodes",           STRING,   ExitNodes,            NULL),
  VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
124
125
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
126
  VAR("MapAddress",          LINELIST, AddressMap,           NULL),
127
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
128
  VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
129
130
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
Roger Dingledine's avatar
Roger Dingledine committed
131
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
132
  VAR("Group",               STRING,   Group,                NULL),
133
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
134
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
135
  VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL),
136
  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
137
  VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL),
138
  VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
139
140
141
142
143
  VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines,    NULL),
  VAR("HiddenServiceDir",    LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServicePort",   LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServiceNodes",  LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL),
144
  VAR("IgnoreVersion",       BOOL,     IgnoreVersion,        "0"),
145
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
146
147
148
  VAR("Log",                 LINELIST, Logs,                 NULL),
  VAR("LogLevel",            LINELIST_S, OldLogOptions,      NULL),
  VAR("LogFile",             LINELIST_S, OldLogOptions,      NULL),
149
  OBSOLETE("LinkPadding"),
150
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
151
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
152
  VAR("MonthlyAccountingStart",UINT,   _MonthlyAccountingStart,"0"),
153
154
  VAR("AccountingMaxKB",     UINT,     _AccountingMaxKB,     "0"),
  VAR("AccountingMax",       MEMUNIT,   AccountingMax,        "0 bytes"),
155
  VAR("Nickname",            STRING,   Nickname,             NULL),
156
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
157
  VAR("MaxCircuitDirtiness", INTERVAL, MaxCircuitDirtiness,  "10 minutes"),
158
159
160
161
162
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
  VAR("ORPort",              UINT,     ORPort,               "0"),
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PidFile",             STRING,   PidFile,              NULL),
163
  VAR("LongLivedPorts",      CSV,      LongLivedPorts,       "21,22,706,1863,5050,5190,5222,5223,6667,8300,8888"),
164
165
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
166
  OBSOLETE("RouterFile"),
167
168
169
170
171
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
172
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
173
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
174
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
175
176
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
177
178
  /** DOCDOC */
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),
179
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
180
  OBSOLETE("TrafficShaping"),
181
  VAR("User",                STRING,   User,                 NULL),
182
183
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
184
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
185
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
186
187
188
189
};
#undef VAR
#undef OBSOLETE

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
typedef int (*validate_fn_t)(void*);

typedef struct {
  size_t size;
  uint32_t magic;
  off_t magic_offset;
  config_abbrev_t *abbrevs;
  config_var_t *vars;
  validate_fn_t validate_fn;
} config_format_t;

#define CHECK(fmt, cfg) do {                                            \
    tor_assert(fmt && cfg);                                             \
    tor_assert((fmt)->magic == *(uint32_t*)(((char*)(cfg))+fmt->magic_offset)); \
  } while (0)

Nick Mathewson's avatar
Nick Mathewson committed
206
/** Largest allowed config line */
207
#define CONFIG_LINE_T_MAXLEN 4096
208

209
210
static void config_line_append(struct config_line_t **lst,
                               const char *key, const char *val);
211
212
213
214
215
216
static void option_reset(config_format_t *fmt, or_options_t *options,
                         config_var_t *var);
static void options_free(config_format_t *fmt, or_options_t *options);
static int option_is_same(config_format_t *fmt,
                          or_options_t *o1, or_options_t *o2,const char *name);
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
217
218
219
static int options_validate(or_options_t *options);
static int options_transition_allowed(or_options_t *old, or_options_t *new);
static int check_nickname_list(const char *lst, const char *name);
220
static void config_register_addressmaps(or_options_t *options);
221

222
static int parse_dir_server_line(const char *line, int validate_only);
223
static int parse_redirect_line(smartlist_t *result,
Roger Dingledine's avatar
Roger Dingledine committed
224
                               struct config_line_t *line);
225
226
227
228
229
230
231
232
233
static int parse_log_severity_range(const char *range, int *min_out,
                                    int *max_out);
static int convert_log_option(or_options_t *options,
                              struct config_line_t *level_opt,
                              struct config_line_t *file_opt, int isDaemon);
static int add_single_log_option(or_options_t *options, int minSeverity,
                                 int maxSeverity,
                                 const char *type, const char *fname);
static int normalize_log_options(or_options_t *options);
234
static int validate_data_directory(or_options_t *options);
235
static int write_configuration_file(const char *fname, or_options_t *options);
236
237
238
static struct config_line_t *get_assigned_option(config_format_t *fmt,
                                     or_options_t *options, const char *key);
static void config_init(config_format_t *fmt, or_options_t *options);
239

240
241
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
242
static void print_cvs_version(void);
243
static int init_libevent(void);
244
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
245
static void check_libevent_version(const char *m, const char *v, int server);
246
#endif
247

248
249
250
251
252
253
254
255
256
257
258
#define OR_OPTIONS_MAGIC 9090909

static config_format_t config_format = {
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
  _config_abbrevs,
  _config_vars,
  (validate_fn_t)options_validate
};

259
260
261
262
263
264
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
static or_options_t *global_options=NULL;
Roger Dingledine's avatar
Roger Dingledine committed
265
/** Name of most recently read torrc file. */
266
static char *config_fname = NULL;
267

268
269
270
271
272
273
274
275
276
static void *
config_alloc(config_format_t *fmt)
{
  void *opts = opts = tor_malloc_zero(fmt->size);
  *(uint32_t*)(((char*)opts)+fmt->magic_offset) = fmt->magic;
  CHECK(fmt, opts);
  return opts;
}

277
278
/** Return the currently configured options. */
or_options_t *
279
280
get_options(void)
{
281
282
283
  tor_assert(global_options);
  return global_options;
}
284

Roger Dingledine's avatar
Roger Dingledine committed
285
/** Change the current global options to contain <b>new_val</b> instead
286
 * of their current value; free the old value as necessary.
287
288
 */
void
289
290
set_options(or_options_t *new_val)
{
291
  if (global_options)
292
    options_free(&config_format, global_options);
293
  global_options = new_val;
294
295
}

296
297
298
void
config_free_all(void)
{
299
  options_free(&config_format, global_options);
300
301
302
  tor_free(config_fname);
}

303
304
305
306
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
307
308
safe_str(const char *address)
{
309
310
311
312
313
314
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

315
316
317
/** Fetch the active option list, and take actions based on it. All
 * of the things we do should survive being done repeatedly.
 * Return 0 if all goes well, return -1 if it's time to die.
318
319
320
321
322
323
 *
 * Note 1: <b>new_val</b> must have previously been validated with
 * options_validate(), or Tor may freak out and exit.
 *
 * Note 2: We haven't moved all the "act on new configuration" logic
 * here yet.  Some is still in do_hup() and other places.
324
325
 */
int
326
327
options_act(void)
{
328
329
  struct config_line_t *cl;
  or_options_t *options = get_options();
330
331
332
  static int libevent_initialized = 0;

  if (options->RunAsDaemon) {
333
    start_daemon();
334
  }
335
336

  clear_trusted_dir_servers();
337
  for (cl = options->DirServers; cl; cl = cl->next) {
338
339
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
340
             "Bug: Previously validated DirServer line could not be added!");
341
      return -1;
342
343
344
    }
  }

345
  if (rend_config_services(options, 0)<0) {
346
    log_fn(LOG_ERR,
347
           "Bug: Previously validated hidden services line could not be added!");
348
    return -1;
349
  }
350

351
352
353
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

354
  /* Setuid/setgid as appropriate */
355
356
  if (options->User || options->Group) {
    if (switch_id(options->User, options->Group) != 0) {
357
358
359
360
361
      return -1;
    }
  }

  /* Ensure data directory is private; create if possible. */
362
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
363
    log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
364
           options->DataDirectory);
365
366
367
368
369
370
371
372
    return -1;
  }

  /* Bail out at this point if we're not going to be a server: we want
   * to not fork, and to log stuff to stderr. */
  if (options->command != CMD_RUN_TOR)
    return 0;

373
  mark_logs_temp(); /* Close current logs once new logs are open. */
374
  if (config_init_logs(options, 0)<0) /* Configure the log(s) */
375
    return -1;
376

377
378
379
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
380
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
381
  control_adjust_event_log_severity();
382

383
384
385
386
387
388
389
  /* Set up libevent. */
  if (!libevent_initialized) {
    if (init_libevent())
      return -1;
    libevent_initialized = 1;
  }

390
  options->_ConnLimit =
391
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
392
  if (options->_ConnLimit < 0)
393
394
    return -1;

395
396
397
398
399
400
401
402
403
  {
    smartlist_t *sl = smartlist_create();
    for (cl = options->RedirectExit; cl; cl = cl->next) {
      if (parse_redirect_line(sl, cl)<0)
        return -1;
    }
    set_exit_redirects(sl);
  }

404
  /* Finish backgrounding the process */
405
  if (options->RunAsDaemon) {
406
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
407
    finish_daemon(options->DataDirectory);
408
409
410
411
  }

  /* Write our pid to the pid file. If we do not have write permissions we
   * will log a warning */
412
  if (options->PidFile)
413
414
    write_pidfile(options->PidFile);

415
416
417
  /* Register addressmap directives */
  config_register_addressmaps(options);

418
419
420
421
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();

422
423
  init_cookie_authentication(options->CookieAuthentication);

424
425
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
426
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
427
428
429
    return -1;
  }

430
  /* Set up accounting */
431
  if (accounting_parse_options(options, 0)<0) {
432
    log_fn(LOG_ERR,"Error in accounting options");
433
434
    return -1;
  }
435
  if (accounting_is_enabled(options))
436
437
    configure_accounting(time(NULL));

438
  if (!we_are_hibernating() && retry_all_listeners(0) < 0) {
439
440
441
442
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    return -1;
  }

443
444
445
446
447
448
  /* Since our options changed, we might need to regenerate and upload our
   * server descriptor.  (We could probably be more clever about only calling
   * this when something significant changed.)
   */
  mark_my_descriptor_dirty();

449
  return 0;
450
451
452
453
454
455
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
456
/** If <b>option</b> is an official abbreviation for a longer option,
457
458
459
 * return the longer option.  Otherwise return <b>option</b>.
 * If <b>command_line</b> is set, apply all abbreviations.  Otherwise, only
 * apply abbreviations that work for the config file and the command line. */
460
static const char *
461
expand_abbrev(config_format_t *fmt, const char *option, int command_line)
462
463
{
  int i;
464
465
466
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
467
    /* Abbreviations aren't casei. */
468
469
470
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
      return fmt->abbrevs[i].full;
471
    }
472
473
474
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
475

Nick Mathewson's avatar
Nick Mathewson committed
476
/** Helper: Read a list of configuration options from the command line. */
477
478
479
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
480
  struct config_line_t *front = NULL;
481
  struct config_line_t **new = &front;
482
483
484
  char *s;
  int i = 1;

485
  while (i < argc-1) {
486
487
488
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
489
      continue;
490
491
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
492
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
493
494
495
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
496
497
    }

498
    *new = tor_malloc_zero(sizeof(struct config_line_t));
499
    s = argv[i];
500

501
    while (*s == '-')
502
      s++;
503

504
    (*new)->key = tor_strdup(expand_abbrev(&config_format, s, 1));
505
506
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
507
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
508
509
510
        (*new)->key, (*new)->value);

    new = &((*new)->next);
511
512
513
514
515
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
516
/** Helper: allocate a new configuration option mapping 'key' to 'val',
517
518
519
520
521
 * append it to *<b>lst</b>. */
static void
config_line_append(struct config_line_t **lst,
                   const char *key,
                   const char *val)
522
523
{
  struct config_line_t *newline;
524

525
526
527
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
528
529
530
531
532
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
533
534
}

535
536
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
537
538
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
539
540
int
config_get_lines(char *string, struct config_line_t **result)
541
{
542
  struct config_line_t *list = NULL, **next;
543
  char *k, *v;
544

545
  next = &list;
546
547
548
549
550
551
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
552
553
554
555
556
557
558
559
560
561
    if (k && v) {
      /* This list can get long, so we keep a pointer to the end of it
       * rather than using config_line_append over and over and getting n^2
       * performance.  This is the only really long list. */
      *next = tor_malloc(sizeof(struct config_line_t));
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
562
  } while (*string);
563

564
  *result = list;
565
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
566
567
}

Nick Mathewson's avatar
Nick Mathewson committed
568
569
570
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
571
void
572
573
config_free_lines(struct config_line_t *front)
{
574
  struct config_line_t *tmp;
575

576
  while (front) {
577
578
579
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
580
581
582
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
583
584
585
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
586
587
588
589
/** If <b>key</b> is a configuration option, return the corresponding
 * config_var_t.  Otherwise, if <b>key</b> is a non-standard abbreviation,
 * warn, and return the corresponding config_var_t.  Otherwise return NULL.
 */
590
static config_var_t *
591
config_find_option(config_format_t *fmt, const char *key)
592
593
{
  int i;
594
  size_t keylen = strlen(key);
595
  if (!keylen)
596
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
597
  /* First, check for an exact (case-insensitive) match */
598
599
600
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strcasecmp(key, fmt->vars[i].name))
      return &fmt->vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
601
602
  }
  /* If none, check for an abbreviated match */
603
604
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
605
606
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
          "Tell Nick and Roger to make it official, or just use '%s' instead",
607
608
             key, fmt->vars[i].name);
      return &fmt->vars[i];
609
610
    }
  }
611
  /* Okay, unrecognized options */
612
613
614
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
615
/** If <b>c</b> is a syntactically valid configuration line, update
616
617
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
618
619
620
621
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
622
static int
623
624
config_assign_line(config_format_t *fmt,
                   or_options_t *options, struct config_line_t *c, int reset)
625
{
626
  int i, ok;
627
628
  config_var_t *var;
  void *lvalue;
629

630
631
632
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
633
634
635
636
637
638
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", c->key);
    return -1;
  }
  /* Put keyword into canonical case. */
  if (strcmp(var->name, c->key)) {
639
    tor_free(c->key);
640
    c->key = tor_strdup(var->name);
641
642
  }

643
  if (reset && !strlen(c->value)) {
644
    option_reset(fmt, options, var);
645
646
647
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
648
  lvalue = ((char*)options) + var->var_offset;
649
  switch (var->type) {
650

651
652
653
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
654
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
655
          c->key,c->value);
656
      return -2;
657
    }
658
    *(int *)lvalue = i;
659
660
    break;

661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
      return -2;
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
      return -2;
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

679
680
681
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
682
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
683
      return -2;
684
    }
685
    *(int *)lvalue = i;
686
687
688
    break;

  case CONFIG_TYPE_STRING:
689
690
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
691
692
693
    break;

  case CONFIG_TYPE_DOUBLE:
694
    *(double *)lvalue = atof(c->value);
695
696
697
    break;

  case CONFIG_TYPE_CSV:
698
699
700
701
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
702
      *(smartlist_t**)lvalue = smartlist_create();
703
    }
704

705
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
706
707
708
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

709
710
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
711
    config_line_append((struct config_line_t**)lvalue, c->key, c->value);
712
    break;
713
714
715
716

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
717
718
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
719
    return -2;
720
721
722
  default:
    tor_assert(0);
    break;
723
  }
724
  return 0;
725
726
}

727
728
/** restore the option named <b>key</b> in options to its default value. */
static void
729
config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
730
731
732
{
  config_var_t *var;

733
734
735
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
736
737
738
  if (!var)
    return; /* give error on next pass. */

739
  option_reset(fmt, options, var);
740
741
}

742
743
744
745
/** Return true iff key is a valid configuration option. */
int
config_option_is_recognized(const char *key)
{
746
  config_var_t *var = config_find_option(&config_format, key);
747
748
749
  return (var != NULL);
}

750
751
752
753
/** Return the canonical name of a configuration option. */
const char *
config_option_get_canonical_name(const char *key)
{
754
  config_var_t *var = config_find_option(&config_format, key);
755
756
757
  return var->name;
}

758

759
760
761
762
/** Return a canonicalized list of the options assigned for key.
 */
struct config_line_t *
config_get_assigned_option(or_options_t *options, const char *key)
763
764
765
766
767
768
{
  return get_assigned_option(&config_format, options, key);
}

static struct config_line_t *
get_assigned_option(config_format_t *fmt, or_options_t *options, const char *key)
769
770
771
772
773
{
  config_var_t *var;
  const void *value;
  char buf[32];
  struct config_line_t *result;
774
  tor_assert(options && key);
775

776
777
778
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
779
780
781
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
782
783
784
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
785
786
787
  }
  value = ((char*)options) + var->var_offset;

788
789
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
790
    /* Linelist requires special handling: we just copy and return it. */
Roger Dingledine's avatar
Roger Dingledine committed
791
    const struct config_line_t *next_in = *(const struct config_line_t**)value;
792
793
794
795
796
797
798
799
800
801
802
803
804
805
    struct config_line_t **next_out = &result;
    while (next_in) {
      *next_out = tor_malloc(sizeof(struct config_line_t));
      (*next_out)->key = tor_strdup(next_in->key);
      (*next_out)->value = tor_strdup(next_in->value);
      next_in = next_in->next;
      next_out = &((*next_out)->next);
    }
    (*next_out) = NULL;
    return result;
  }

  result = tor_malloc_zero(sizeof(struct config_line_t));
  result->key = tor_strdup(var->name);
806
  switch (var->type)
807
808
    {
    case CONFIG_TYPE_STRING:
809
810
811
812
813
814
815
      if (*(char**)value) {
        result->value = tor_strdup(*(char**)value);
      } else {
        tor_free(result->key);
        tor_free(result);
        return NULL;
      }
816
      break;
817
    case CONFIG_TYPE_INTERVAL:
818
    case CONFIG_TYPE_UINT:
819
      /* This means every or_options_t uint or bool element
820
       * needs to be an int. Not, say, a uint16_t or char. */
821
822
823
      tor_snprintf(buf, sizeof(buf), "%d", *(int*)value);
      result->value = tor_strdup(buf);
      break;
824
825
826
827
828
    case CONFIG_TYPE_MEMUNIT:
      tor_snprintf(buf, sizeof(buf), U64_FORMAT,
                   U64_PRINTF_ARG(*(uint64_t*)value));
      result->value = tor_strdup(buf);
      break;
829
830
831
832
833
834
835
836
    case CONFIG_TYPE_DOUBLE:
      tor_snprintf(buf, sizeof(buf), "%f", *(double*)value);
      result->value = tor_strdup(buf);
      break;
    case CONFIG_TYPE_BOOL:
      result->value = tor_strdup(*(int*)value ? "1" : "0");
      break;
    case CONFIG_TYPE_CSV:
Roger Dingledine's avatar
Roger Dingledine committed
837
838
      if (*(smartlist_t**)value)
        result->value = smartlist_join_strings(*(smartlist_t**)value,",",0,NULL);
839
840
841
      else
        result->value = tor_strdup("");
      break;
842
843
844
845
846
    case CONFIG_TYPE_OBSOLETE:
      log_fn(LOG_WARN,"You asked me for the value of an obsolete config option %s.", key);
      tor_free(result->key);
      tor_free(result);
      return NULL;
847
848
849
    default:
      tor_free(result->key);
      tor_free(result);
850
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
851
852
853
854
855
856
      return NULL;
    }

  return result;
}

857
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
858
 * For each item, convert as appropriate and assign to <b>options</b>.
859
 * If an item is unrecognized, return -1 immediately,
860
861
862
863
 * else return 0 for success.
 *
 * If <b>reset</b>, then interpret empty lines as meaning "restore to
 * default value", and interpret LINELIST* options as replacing (not
864
865
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
866
 */
867
static int
868
869
config_assign(config_format_t *fmt,
              or_options_t *options, struct config_line_t *list, int reset)
870
{
871
  struct config_line_t *p;
872
873

  CHECK(fmt, options);
874
875
876

  /* pass 1: normalize keys */
  for (p = list; p; p = p->next) {
877
    const char *full = expand_abbrev(fmt, p->key, 0);
878
879
880
    if (strcmp(full,p->key)) {
      tor_free(p->key);
      p->key = tor_strdup(full);
881
    }
882
883
  }

884
  /* pass 2: if we're reading from a resetting source, clear all mentioned
885
886
887
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
888
      config_reset_line(fmt, options, p->key);
889
  }
890

891
892
  /* pass 3: assign. */
  while (list) {
893
    int r;
894
    if ((r=config_assign_line(fmt, options, list, reset)))
895
      return r;
896
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
897
  }
898
  return 0;
899
900
}

901
/** Try assigning <b>list</b> to the global options. You do this by duping
902
 * options, assigning list to the new one, then validating it. If it's
903
 * ok, then throw out the old one and stick with the new one. Else,
904
905
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
906
907
 */
int
908
config_trial_assign(struct config_line_t *list, int reset)
909
{
910
  int r;