config.c 84.8 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$";
Nick Mathewson's avatar
Nick Mathewson committed
7
/**
8
 * \file config.c
Nick Mathewson's avatar
Nick Mathewson committed
9
 *
10
 * \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
139
140
141
142
  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),
143
  VAR("IgnoreVersion",       BOOL,     IgnoreVersion,        "0"),
144
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
145
146
147
  VAR("Log",                 LINELIST, Logs,                 NULL),
  VAR("LogLevel",            LINELIST_S, OldLogOptions,      NULL),
  VAR("LogFile",             LINELIST_S, OldLogOptions,      NULL),
148
  OBSOLETE("LinkPadding"),
149
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
150
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
151
  VAR("MonthlyAccountingStart",UINT,   _MonthlyAccountingStart,"0"),
152
153
  VAR("AccountingMaxKB",     UINT,     _AccountingMaxKB,     "0"),
  VAR("AccountingMax",       MEMUNIT,   AccountingMax,        "0 bytes"),
154
  VAR("Nickname",            STRING,   Nickname,             NULL),
155
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
156
  VAR("MaxCircuitDirtiness", INTERVAL, MaxCircuitDirtiness,  "10 minutes"),
157
158
159
160
161
  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),
162
  VAR("LongLivedPorts",      CSV,      LongLivedPorts,       "21,22,706,1863,5050,5190,5222,5223,6667,8300,8888"),
163
164
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
165
  OBSOLETE("RouterFile"),
166
167
168
169
170
  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),
171
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
172
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
173
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
174
175
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
176
177
  /** DOCDOC */
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),
178
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
179
  OBSOLETE("TrafficShaping"),
180
  VAR("User",                STRING,   User,                 NULL),
181
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
182
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
183
184
185
186
};
#undef VAR
#undef OBSOLETE

Nick Mathewson's avatar
Nick Mathewson committed
187
/** Largest allowed config line */
188
#define CONFIG_LINE_T_MAXLEN 4096
189

190
191
static void config_line_append(struct config_line_t **lst,
                               const char *key, const char *val);
192
193
static void option_reset(or_options_t *options, config_var_t *var);
static void options_free(or_options_t *options);
194
static int option_is_same(or_options_t *o1, or_options_t *o2,const char *name);
195
196
197
198
static or_options_t *options_dup(or_options_t *old);
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);
199
static void config_register_addressmaps(or_options_t *options);
200

201
static int parse_dir_server_line(const char *line, int validate_only);
202
static int parse_redirect_line(smartlist_t *result,
Roger Dingledine's avatar
Roger Dingledine committed
203
                               struct config_line_t *line);
204
205
206
207
208
209
210
211
212
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);
213
static int validate_data_directory(or_options_t *options);
214
static int write_configuration_file(const char *fname, or_options_t *options);
215

216
217
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
218
static void print_cvs_version(void);
219
static int init_libevent(void);
220
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
221
static void check_libevent_version(const char *m, const char *v, int server);
222
#endif
223

224
225
226
227
228
229
/*
 * 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
230
/** Name of most recently read torrc file. */
231
static char *config_fname = NULL;
232

233
234
235
/** Return the currently configured options. */
or_options_t *
get_options(void) {
236
237
238
  tor_assert(global_options);
  return global_options;
}
239

Roger Dingledine's avatar
Roger Dingledine committed
240
/** Change the current global options to contain <b>new_val</b> instead
241
 * of their current value; free the old value as necessary.
242
243
244
245
246
247
 */
void
set_options(or_options_t *new_val) {
  if (global_options)
    options_free(global_options);
  global_options = new_val;
248
249
}

250
251
252
253
254
255
256
void
config_free_all(void)
{
  options_free(global_options);
  tor_free(config_fname);
}

257
258
259
260
261
262
263
264
265
266
267
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
safe_str(const char *address) {
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

268
269
270
/** 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.
271
272
273
274
275
276
 *
 * 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.
277
278
279
280
281
 */
int
options_act(void) {
  struct config_line_t *cl;
  or_options_t *options = get_options();
282
283
284
285
286
287
  static int libevent_initialized = 0;

  /* XXXX009 We once had a reason to separate start_daemon and finish_daemon:
   *    It let us have the parent process stick around until we were sure Tor
   *    was started.  Should we make start_daemon get called earlier? -NM */
  if (options->RunAsDaemon) {
288
    start_daemon();
289
  }
290
291

  clear_trusted_dir_servers();
292
  for (cl = options->DirServers; cl; cl = cl->next) {
293
294
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
295
             "Bug: Previously validated DirServer line could not be added!");
296
      return -1;
297
298
299
    }
  }

300
  if (rend_config_services(options, 0)<0) {
301
    log_fn(LOG_ERR,
302
           "Bug: Previously validated hidden services line could not be added!");
303
    return -1;
304
  }
305
306

  /* Setuid/setgid as appropriate */
307
308
  if (options->User || options->Group) {
    if (switch_id(options->User, options->Group) != 0) {
309
310
311
312
313
      return -1;
    }
  }

  /* Ensure data directory is private; create if possible. */
314
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
315
    log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
316
           options->DataDirectory);
317
318
319
320
321
322
323
324
    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;

325
  mark_logs_temp(); /* Close current logs once new logs are open. */
326
  if (config_init_logs(options, 0)<0) /* Configure the log(s) */
327
    return -1;
328

329
330
331
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
332
333
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
  adjust_event_log_severity();
334

335
336
337
338
339
340
341
  /* Set up libevent. */
  if (!libevent_initialized) {
    if (init_libevent())
      return -1;
    libevent_initialized = 1;
  }

342
  options->_ConnLimit =
343
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
344
  if (options->_ConnLimit < 0)
345
346
    return -1;

347
348
349
350
351
352
353
354
355
  {
    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);
  }

356
  /* Finish backgrounding the process */
357
  if (options->RunAsDaemon) {
358
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
359
    finish_daemon(options->DataDirectory);
360
361
362
363
  }

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

367
368
369
  /* Register addressmap directives */
  config_register_addressmaps(options);

370
371
372
373
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();

374
375
  init_cookie_authentication(options->CookieAuthentication);

376
377
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
378
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
379
380
381
    return -1;
  }

382
  /* Set up accounting */
383
  if (accounting_parse_options(options, 0)<0) {
384
    log_fn(LOG_ERR,"Error in accounting options");
385
386
    return -1;
  }
387
  if (accounting_is_enabled(options))
388
389
    configure_accounting(time(NULL));

390
  if (!we_are_hibernating() && retry_all_listeners(1) < 0) {
391
392
393
394
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    return -1;
  }

395
396
397
398
399
400
#if 0
  {
    char *smin, *smax;
    smin = config_dump_options(options, 1);
    smax = config_dump_options(options, 0);
    log_fn(LOG_DEBUG, "These are our options:\n%s",smax);
Roger Dingledine's avatar
Roger Dingledine committed
401
    log_fn(LOG_DEBUG, "We changed these options:\n%s",smin);
402
403
404
405
406
    tor_free(smin);
    tor_free(smax);
  }
#endif

407
408
409
410
411
412
  /* 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();

413
  return 0;
414
415
416
417
418
419
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
420
/** If <b>option</b> is an official abbreviation for a longer option,
421
422
423
 * 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. */
424
static const char *
425
expand_abbrev(const char *option, int command_line)
426
427
428
429
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
430
    if (!strcasecmp(option,config_abbrevs[i].abbreviated) &&
431
        (command_line || !config_abbrevs[i].commandline_only)) {
432
      return config_abbrevs[i].full;
433
    }
434
435
436
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
437

Nick Mathewson's avatar
Nick Mathewson committed
438
/** Helper: Read a list of configuration options from the command line. */
439
440
441
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
442
443
  struct config_line_t *new;
  struct config_line_t *front = NULL;
444
445
446
  char *s;
  int i = 1;

447
  while (i < argc-1) {
448
449
450
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
451
      continue;
452
453
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
454
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
455
456
457
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
458
459
    }

460
    new = tor_malloc(sizeof(struct config_line_t));
461
    s = argv[i];
462

463
    while (*s == '-')
464
      s++;
465

466
    new->key = tor_strdup(expand_abbrev(s, 1));
467
    new->value = tor_strdup(argv[i+1]);
468
469

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
470
        new->key, new->value);
471
472
473
474
475
476
477
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
478
/** Helper: allocate a new configuration option mapping 'key' to 'val',
479
480
481
482
483
 * append it to *<b>lst</b>. */
static void
config_line_append(struct config_line_t **lst,
                   const char *key,
                   const char *val)
484
485
{
  struct config_line_t *newline;
486

487
488
489
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
490
491
492
493
494
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
495
496
}

497
498
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
499
500
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
501
502
int
config_get_lines(char *string, struct config_line_t **result)
503
{
504
  struct config_line_t *list = NULL, **next;
505
  char *k, *v;
506

507
  next = &list;
508
509
510
511
512
513
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
514
515
516
517
518
519
520
521
522
523
    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);
    }
524
  } while (*string);
525

526
  *result = list;
527
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
528
529
}

Nick Mathewson's avatar
Nick Mathewson committed
530
531
532
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
533
void
534
535
config_free_lines(struct config_line_t *front)
{
536
  struct config_line_t *tmp;
537

538
  while (front) {
539
540
541
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
542
543
544
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
545
546
547
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
548
549
550
551
/** 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.
 */
552
553
554
static config_var_t *config_find_option(const char *key)
{
  int i;
555
  size_t keylen = strlen(key);
556
  if (!keylen)
557
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
558
  /* First, check for an exact (case-insensitive) match */
559
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
560
    if (!strcasecmp(key, config_vars[i].name))
561
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
562
563
564
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
565
    if (!strncasecmp(key, config_vars[i].name, keylen)) {
566
567
568
569
570
571
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
          "Tell Nick and Roger to make it official, or just use '%s' instead",
             key, config_vars[i].name);
      return &config_vars[i];
    }
  }
572
  /* Okay, unrecognized options */
573
574
575
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
576
/** If <b>c</b> is a syntactically valid configuration line, update
577
578
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
579
580
581
582
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
583
static int
584
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
585
{
586
  int i, ok;
587
588
  config_var_t *var;
  void *lvalue;
589

590
591
592
593
594
595
596
  var = config_find_option(c->key);
  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)) {
597
    tor_free(c->key);
598
    c->key = tor_strdup(var->name);
599
600
  }

601
  if (reset && !strlen(c->value)) {
602
    option_reset(options, var);
603
604
605
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
606
  lvalue = ((char*)options) + var->var_offset;
607
  switch (var->type) {
608

609
610
611
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
612
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
613
          c->key,c->value);
614
      return -2;
615
    }
616
    *(int *)lvalue = i;
617
618
    break;

619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  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;
  }

637
638
639
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
640
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
641
      return -2;
642
    }
643
    *(int *)lvalue = i;
644
645
646
    break;

  case CONFIG_TYPE_STRING:
647
648
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
649
650
651
    break;

  case CONFIG_TYPE_DOUBLE:
652
    *(double *)lvalue = atof(c->value);
653
654
655
    break;

  case CONFIG_TYPE_CSV:
656
657
658
659
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
660
      *(smartlist_t**)lvalue = smartlist_create();
661
    }
662

663
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
664
665
666
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

667
668
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
669
    config_line_append((struct config_line_t**)lvalue, c->key, c->value);
670
    break;
671
672
673
674

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
675
676
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
677
    return -2;
678
679
680
  default:
    tor_assert(0);
    break;
681
  }
682
  return 0;
683
684
}

685
686
687
688
689
690
691
692
693
694
/** restore the option named <b>key</b> in options to its default value. */
static void
config_reset_line(or_options_t *options, const char *key)
{
  config_var_t *var;

  var = config_find_option(key);
  if (!var)
    return; /* give error on next pass. */

695
  option_reset(options, var);
696
697
}

698
699
700
701
702
703
704
705
/** Return true iff key is a valid configuration option. */
int
config_option_is_recognized(const char *key)
{
  config_var_t *var = config_find_option(key);
  return (var != NULL);
}

706
707
708
709
710
711
712
713
714
/** 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)
{
  config_var_t *var;
  const void *value;
  char buf[32];
  struct config_line_t *result;
715
  tor_assert(options && key);
716
717
718
719
720

  var = config_find_option(key);
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
721
722
723
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
724
725
726
  }
  value = ((char*)options) + var->var_offset;

727
728
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
729
    /* Linelist requires special handling: we just copy and return it. */
Roger Dingledine's avatar
Roger Dingledine committed
730
    const struct config_line_t *next_in = *(const struct config_line_t**)value;
731
732
733
734
735
736
737
738
739
740
741
742
743
744
    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);
745
  switch (var->type)
746
747
    {
    case CONFIG_TYPE_STRING:
748
749
750
751
752
753
754
      if (*(char**)value) {
        result->value = tor_strdup(*(char**)value);
      } else {
        tor_free(result->key);
        tor_free(result);
        return NULL;
      }
755
      break;
756
    case CONFIG_TYPE_INTERVAL:
757
    case CONFIG_TYPE_UINT:
758
      /* This means every or_options_t uint or bool element
759
       * needs to be an int. Not, say, a uint16_t or char. */
760
761
762
      tor_snprintf(buf, sizeof(buf), "%d", *(int*)value);
      result->value = tor_strdup(buf);
      break;
763
764
765
766
767
    case CONFIG_TYPE_MEMUNIT:
      tor_snprintf(buf, sizeof(buf), U64_FORMAT,
                   U64_PRINTF_ARG(*(uint64_t*)value));
      result->value = tor_strdup(buf);
      break;
768
769
770
771
772
773
774
775
    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
776
777
      if (*(smartlist_t**)value)
        result->value = smartlist_join_strings(*(smartlist_t**)value,",",0,NULL);
778
779
780
      else
        result->value = tor_strdup("");
      break;
781
782
783
784
785
    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;
786
787
788
    default:
      tor_free(result->key);
      tor_free(result);
789
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
790
791
792
793
794
795
      return NULL;
    }

  return result;
}

796
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
797
 * For each item, convert as appropriate and assign to <b>options</b>.
798
 * If an item is unrecognized, return -1 immediately,
799
800
801
802
 * 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
803
804
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
805
 */
806
static int
807
config_assign(or_options_t *options, struct config_line_t *list, int reset)
808
{
809
  struct config_line_t *p;
810
  tor_assert(options);
811
812
813
814
815
816
817

  /* pass 1: normalize keys */
  for (p = list; p; p = p->next) {
    const char *full = expand_abbrev(p->key, 0);
    if (strcmp(full,p->key)) {
      tor_free(p->key);
      p->key = tor_strdup(full);
818
    }
819
820
  }

821
  /* pass 2: if we're reading from a resetting source, clear all mentioned
822
823
824
825
826
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
827

828
829
  /* pass 3: assign. */
  while (list) {
830
831
832
    int r;
    if ((r=config_assign_line(options, list, reset)))
      return r;
833
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
834
  }
835
  return 0;
836
837
}

838
/** Try assigning <b>list</b> to the global options. You do this by duping
839
 * options, assigning list to the new one, then validating it. If it's
840
 * ok, then throw out the old one and stick with the new one. Else,
841
842
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
843
844
 */
int
845
config_trial_assign(struct config_line_t *list, int reset)
846
{
847
  int r;
848
  or_options_t *trial_options = options_dup(get_options());
849

850
  if ((r=config_assign(trial_options, list, reset)) < 0) {
851
    options_free(trial_options);
852
    return r;
853
854
855
856
  }

  if (options_validate(trial_options) < 0) {
    options_free(trial_options);
857
    return -2;
858
859
  }

860
  if (options_transition_allowed(get_options(), trial_options) < 0) {
861
    options_free(trial_options);
862
    return -3;
863
864
  }

865
  set_options(trial_options); /* we liked it. put it in place. */
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
  return 0;
}

/** Replace the option indexed by <b>var</b> in <b>options</b> with its
 * default value. */
static void
option_reset(or_options_t *options, config_var_t *var)
{
  struct config_line_t *c;
  void *lvalue;

  lvalue = ((char*)options) + var->var_offset;
  switch (var->type) {
    case CONFIG_TYPE_STRING:
      tor_free(*(char**)lvalue);
      break;
    case CONFIG_TYPE_DOUBLE:
      *(double*)lvalue = 0.0;
      break;
885
    case CONFIG_TYPE_INTERVAL:
886
887
888
889
    case CONFIG_TYPE_UINT:
    case CONFIG_TYPE_BOOL:
      *(int*)lvalue = 0;
      break;
890
891
892
    case CONFIG_TYPE_MEMUNIT:
      *(uint64_t*)lvalue = 0;
      break;
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
    case CONFIG_TYPE_CSV:
      if (*(smartlist_t**)lvalue) {
        SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
        smartlist_free(*(smartlist_t **)lvalue);
        *(smartlist_t **)lvalue = NULL;
      }
      break;
    case CONFIG_TYPE_LINELIST:
    case CONFIG_TYPE_LINELIST_S:
      config_free_lines(*(struct config_line_t **)lvalue);
      *(struct config_line_t **)lvalue = NULL;
      break;
    case CONFIG_TYPE_LINELIST_V:
      /* handled by linelist_s. */
      break;
    case CONFIG_TYPE_OBSOLETE:
      break;
  }
  if (var->initvalue) {
912
    c = tor_malloc_zero(sizeof(struct config_line_t));
913
914
915
916
917
918
919
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

920
/** Set <b>options</b>-&gt;DirServers to contain the default directory
921
 * servers. */
922
static void
923
add_default_trusted_dirservers(or_options_t *options)
924
{
Nick Mathewson's avatar
Nick Mathewson committed
925
  /* moria1 */
926
  config_line_append(&options->DirServers, "DirServer",
927
       "18.244.0.188:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
Nick Mathewson's avatar
Nick Mathewson committed
928
  /* moria2 */
929
  config_line_append(&options->DirServers, "DirServer",
930
         "18.244.0.114:80 719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
Nick Mathewson's avatar
Nick Mathewson committed
931
  /* tor26 */
932
  config_line_append(&options->DirServers, "DirServer",
933
     "62.116.124.106:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
934
//  "tor.noreply.org:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
Roger Dingledine's avatar