config.c 50.6 KB
Newer Older
Roger Dingledine's avatar
Roger Dingledine committed
1
2
3
/* Copyright 2001 Matej Pfajfar.
 * Copyright 2001-2004 Roger Dingledine.
 * Copyright 2004 Roger Dingledine, Nick Mathewson. */
4
5
6
/* See LICENSE for licensing information */
/* $Id$ */

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

Roger Dingledine's avatar
Roger Dingledine committed
14
#include "or.h"
15
16
17
#ifdef MS_WINDOWS
#include <shlobj.h>
#endif
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
23
24
25
26
27
  CONFIG_TYPE_STRING = 0,   /**< An arbitrary string. */
  CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
  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 */
28
29
30
31
32
  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.
                             */
33
  CONFIG_TYPE_OBSOLETE,     /**< Obsolete (ignored) option. */
Nick Mathewson's avatar
Nick Mathewson committed
34
} config_type_t;
35

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

43
44
45
46
/* 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
47
/* A list of command-line abbreviations. */
48
static config_abbrev_t config_abbrevs[] = {
49
50
51
52
53
54
55
56
  PLURAL(ExitNode),
  PLURAL(EntryNodes),
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
  PLURAL(RendNode),
  PLURAL(RendExcludeNode),
57
  { "l", "Log", 1},
58
59
  { "BandwidthRate", "BandwidthRateBytes", 1},
  { "BandwidthBurst", "BandwidthBurstBytes", 1},
60
  { NULL, NULL , 0},
61
};
62
#undef PLURAL
63

64
/** A variable allowed in the configuration file or on the command line. */
65
typedef struct config_var_t {
66
67
68
69
  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. */
70
71
} config_var_t;

Nick Mathewson's avatar
Nick Mathewson committed
72
/** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
Nick Mathewson's avatar
Nick Mathewson committed
73
#define STRUCT_OFFSET(tp, member) ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
Nick Mathewson's avatar
Nick Mathewson committed
74
75
76
77
/** 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>"
 */
78
79
#define VAR(name,conftype,member,initvalue) \
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member), initvalue }
Nick Mathewson's avatar
Nick Mathewson committed
80
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
81
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL }
82

Nick Mathewson's avatar
Nick Mathewson committed
83
84
85
86
/** Array of configuration options.  Until we disallow nonstandard
 * abbreviations, order is significant, since the first matching option will
 * be chosen first.
 */
87
static config_var_t config_vars[] = {
88
  VAR("Address",             STRING,   Address,              NULL),
89
  VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes, "middle,rendezvous"),
90
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
91
92
  VAR("BandwidthRateBytes",  UINT,     BandwidthRateBytes,   "800000"),
  VAR("BandwidthBurstBytes", UINT,     BandwidthBurstBytes,  "50000000"),
93
94
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
95
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
  VAR("DirPort",             UINT,     DirPort,              "0"),
  VAR("DirBindAddress",      LINELIST, DirBindAddress,       NULL),
  VAR("DirFetchPostPeriod",  UINT,     DirFetchPostPeriod,   "600"),
  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),
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
110
  VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
111
112
113
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
  VAR("Group",               STRING,   Group,                NULL),
114
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
115
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
116
117
118
119
120
  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),
121
122
  VAR("IgnoreVersion",       BOOL,     IgnoreVersion,        "0"),
  VAR("KeepalivePeriod",     UINT,     KeepalivePeriod,      "300"),
123
124
125
  VAR("Log",                 LINELIST, Logs,                 NULL),
  VAR("LogLevel",            LINELIST_S, OldLogOptions,      NULL),
  VAR("LogFile",             LINELIST_S, OldLogOptions,      NULL),
126
  OBSOLETE("LinkPadding"),
127
128
129
130
131
132
133
134
135
136
137
138
139
  VAR("MaxConn",             UINT,     MaxConn,              "1024"),
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
  VAR("MonthlyAccountingStart",UINT,   AccountingStart,      "0"),
  VAR("AccountingMaxKB",     UINT,     AccountingMaxKB,      "0"),
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NewCircuitPeriod",    UINT,     NewCircuitPeriod,     "30"),
  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),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
140
  OBSOLETE("RouterFile"),
141
142
143
144
145
  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),
146
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
147
148
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
149
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
150
  OBSOLETE("TrafficShaping"),
151
152
  VAR("User",                STRING,   User,                 NULL),
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
153
154
155
156
};
#undef VAR
#undef OBSOLETE

Nick Mathewson's avatar
Nick Mathewson committed
157
/** Largest allowed config line */
158
#define CONFIG_LINE_T_MAXLEN 4096
159

160
161
162
163
164
165
166
static void option_reset(or_options_t *options, config_var_t *var);
static void options_free(or_options_t *options);
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);

167
static int parse_dir_server_line(const char *line);
Roger Dingledine's avatar
Roger Dingledine committed
168
169
static int parse_redirect_line(or_options_t *options,
                               struct config_line_t *line);
170
171
172
173
174
175
176
177
178
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);
179

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
static or_options_t *global_options=NULL;

or_options_t *get_options(void) {
  tor_assert(global_options);
  return global_options;
}
void set_options(or_options_t *new) {
  global_options = new;
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
199
/** If <b>option</b> is an official abbreviation for a longer option,
200
201
202
 * 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. */
203
static const char *
204
expand_abbrev(const char *option, int command_line)
205
206
207
208
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
209
210
    if (!strcmp(option,config_abbrevs[i].abbreviated) &&
        (command_line || !config_abbrevs[i].commandline_only)) {
211
      return config_abbrevs[i].full;
212
    }
213
214
215
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
216

Nick Mathewson's avatar
Nick Mathewson committed
217
/** Helper: Read a list of configuration options from the command line. */
218
219
220
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
221
222
  struct config_line_t *new;
  struct config_line_t *front = NULL;
223
224
225
  char *s;
  int i = 1;

226
  while (i < argc-1) {
227
228
229
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
230
      continue;
231
232
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
233
      continue;
234
235
    }

236
    new = tor_malloc(sizeof(struct config_line_t));
237
    s = argv[i];
238

239
240
    while(*s == '-')
      s++;
241

242
    new->key = tor_strdup(expand_abbrev(s, 1));
243
    new->value = tor_strdup(argv[i+1]);
244
245

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
246
        new->key, new->value);
247
248
249
250
251
252
253
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
254
255
/** Helper: allocate a new configuration option mapping 'key' to 'val',
 * prepend it to 'front', and return the newly allocated config_line_t */
256
struct config_line_t *
257
258
259
260
261
config_line_prepend(struct config_line_t *front,
                    const char *key,
                    const char *val)
{
  struct config_line_t *newline;
262

263
264
265
266
267
268
269
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
  newline->next = front;
  return newline;
}

270
271
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
272
273
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
274
275
int
config_get_lines(char *string, struct config_line_t **result)
276
{
277
278
  struct config_line_t *list = NULL;
  char *k, *v;
279

280
281
282
283
284
285
286
287
288
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
    if (k && v)
      list = config_line_prepend(list, k, v);
  } while (*string);
289

290
  *result = list;
291
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
292
293
}

Nick Mathewson's avatar
Nick Mathewson committed
294
295
296
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
297
void
298
299
config_free_lines(struct config_line_t *front)
{
300
  struct config_line_t *tmp;
301

302
  while (front) {
303
304
305
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
306
307
308
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
309
310
311
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
312
313
314
315
/** 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.
 */
316
317
318
static config_var_t *config_find_option(const char *key)
{
  int i;
Nick Mathewson's avatar
Nick Mathewson committed
319
  /* First, check for an exact (case-insensitive) match */
320
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
321
    if (!strcasecmp(key, config_vars[i].name))
322
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
323
324
325
326
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
    if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
327
328
329
330
331
332
      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];
    }
  }
Nick Mathewson's avatar
Nick Mathewson committed
333
  /* Okay, unrecogized options */
334
335
336
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
337
/** If <b>c</b> is a syntactically valid configuration line, update
338
339
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
340
341
342
343
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
344
static int
345
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
346
{
347
  int i, ok;
348
349
  config_var_t *var;
  void *lvalue;
350

351
352
353
354
355
356
357
  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)) {
358
    tor_free(c->key);
359
    c->key = tor_strdup(var->name);
360
361
  }

362
  if (reset && !strlen(c->value)) {
363
    option_reset(options, var);
364
365
366
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
367
  lvalue = ((char*)options) + var->var_offset;
368
  switch(var->type) {
369

370
371
372
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
373
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
374
          c->key,c->value);
375
      return -2;
376
    }
377
    *(int *)lvalue = i;
378
379
380
381
382
    break;

  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
383
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
384
      return -2;
385
    }
386
    *(int *)lvalue = i;
387
388
389
    break;

  case CONFIG_TYPE_STRING:
390
391
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
392
393
394
    break;

  case CONFIG_TYPE_DOUBLE:
395
    *(double *)lvalue = atof(c->value);
396
397
398
    break;

  case CONFIG_TYPE_CSV:
399
400
    if (*(smartlist_t**)lvalue == NULL)
      *(smartlist_t**)lvalue = smartlist_create();
401

402
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
403
404
405
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

406
407
408
409
410
411
412
413
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
    /* Note: this reverses the order that the lines appear in.  That's
     * just fine, since we build up the list of lines reversed in the
     * first place. */
    *(struct config_line_t**)lvalue =
      config_line_prepend(*(struct config_line_t**)lvalue, c->key, c->value);
    break;
414
415
416
417

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
418
419
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
420
    return -2;
421
422
423
  default:
    tor_assert(0);
    break;
424
  }
425
  return 0;
426
427
}

428
429
430
431
432
433
434
435
436
437
/** 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. */

438
  option_reset(options, var);
439
440
}

441
442
443
444
445
446
447
448
449
450
451
452
453
454
/** 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;

  var = config_find_option(key);
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
455
456
457
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
458
459
460
  }
  value = ((char*)options) + var->var_offset;

461
462
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
    /* Linelist requires special handling: we just copy and return it. */
    const struct config_line_t *next_in = value;
    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);
  switch(var->type)
    {
    case CONFIG_TYPE_STRING:
      result->value = tor_strdup(value ? (char*)value : "");
      break;
    case CONFIG_TYPE_UINT:
485
486
      /* XXX This means every or_options_t uint or bool element
       * needs to be an int. Not, say, a uint16_t or char. */
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
      tor_snprintf(buf, sizeof(buf), "%d", *(int*)value);
      result->value = tor_strdup(buf);
      break;
    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:
      if (value)
        result->value = smartlist_join_strings((smartlist_t*)value,",",0,NULL);
      else
        result->value = tor_strdup("");
      break;
    default:
      tor_free(result->key);
      tor_free(result);
506
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
507
508
509
510
511
512
      return NULL;
    }

  return result;
}

513
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
514
 * For each item, convert as appropriate and assign to <b>options</b>.
515
 * If an item is unrecognized, return -1 immediately,
516
517
518
519
 * 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
520
521
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
522
 */
523
static int
524
config_assign(or_options_t *options, struct config_line_t *list, int reset)
525
{
526
527
528
529
530
531
532
533
  struct config_line_t *p;

  /* 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);
534
    }
535
536
  }

537
  /* pass 2: if we're reading from a resetting source, clear all mentioned
538
539
540
541
542
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
543

544
545
  /* pass 3: assign. */
  while (list) {
546
547
548
    int r;
    if ((r=config_assign_line(options, list, reset)))
      return r;
549
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
550
  }
551
  return 0;
552
553
}

554
555
556
/** Try assigning <b>list</b> to <b>options</b>. You do this by duping
 * options, assigning list to the new one, then validating it. If it's
 * ok, then through out the old one and stick with the new one. Else,
557
558
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
559
560
561
562
 */
int
config_trial_assign(or_options_t **options, struct config_line_t *list, int reset)
{
563
  int r;
564
565
  or_options_t *trial_options = options_dup(*options);

566
  if ((r=config_assign(trial_options, list, reset)) < 0) {
567
    options_free(trial_options);
568
    return r;
569
570
571
572
  }

  if (options_validate(trial_options) < 0) {
    options_free(trial_options);
573
    return -2;
574
575
576
577
  }

  if (options_transition_allowed(*options, trial_options) < 0) {
    options_free(trial_options);
578
    return -3;
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  }

  /* XXX now act on options */

  options_free(*options);
  *options = trial_options;
  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;
    case CONFIG_TYPE_UINT:
    case CONFIG_TYPE_BOOL:
      *(int*)lvalue = 0;
      break;
    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) {
627
    c = tor_malloc_zero(sizeof(struct config_line_t));
628
629
630
631
632
633
634
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

635
636
637
static void
add_default_trusted_dirservers(void)
{
Nick Mathewson's avatar
Nick Mathewson committed
638
639
640
641
  /* moria1 */
  parse_dir_server_line("18.244.0.188:9031 "
                        "FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
  /* moria2 */
642
  parse_dir_server_line("18.244.0.114:80 "
Nick Mathewson's avatar
Nick Mathewson committed
643
644
645
646
                        "719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
  /* tor26 */
  parse_dir_server_line("62.116.124.106:9030 "
                        "847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
647
648
}

Nick Mathewson's avatar
Nick Mathewson committed
649
/** Print a usage message for tor. */
650
651
652
static void
print_usage(void)
{
653
  printf("tor -f <torrc> [args]\n"
654
655
         "See man page for more options. This -h is obsolete.\n");
#if 0
656
         "-b <bandwidth>\t\tbytes/second rate limiting\n"
657
         "-d <file>\t\tDebug file\n"
658
659
660
661
         "-l <level>\t\tLog level\n"
         "-r <file>\t\tList of known routers\n");
  printf("\nClient options:\n"
         "-e \"nick1 nick2 ...\"\t\tExit nodes\n"
662
         "-s <IP>\t\t\tPort to bind to for Socks\n");
663
664
  printf("\nServer options:\n"
         "-n <nick>\t\tNickname of router\n"
665
         "-o <port>\t\tOR port to bind to\n"
666
         "-p <file>\t\tPID file\n");
667
#endif
668
669
}

Nick Mathewson's avatar
Nick Mathewson committed
670
/**
671
672
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
673
 */
674
675
676
int
resolve_my_address(const char *address, uint32_t *addr)
{
677
678
  struct in_addr in;
  struct hostent *rent;
679
  char hostname[256];
680
  int explicit_ip=1;
681

682
683
  tor_assert(addr);

684
685
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
686
  } else { /* then we need to guess our address */
687
    explicit_ip = 0; /* it's implicit */
688

689
    if (gethostname(hostname, sizeof(hostname)) < 0) {
690
691
692
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
693
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
694
695
  }

696
  /* now we know hostname. resolve it and keep only the IP */
697

698
  if (tor_inet_aton(hostname, &in) == 0) {
699
700
    /* then we have to resolve it */
    explicit_ip = 0;
701
    rent = (struct hostent *)gethostbyname(hostname);
702
    if (!rent) {
703
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
704
705
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
706
    tor_assert(rent->h_length == 4);
707
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
708
  }
709
710

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
711
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
712
           "Please set the Address config option to be the IP you want to use.",
713
           hostname, inet_ntoa(in));
714
715
    return -1;
  }
716
717

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
718
  *addr = ntohl(in.s_addr);
719
720
721
  return 0;
}

722
723
static char *
get_default_nickname(void)
724
725
726
727
{
  char localhostname[256];
  char *cp, *out, *outp;

728
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
729
730
731
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
732

733
  /* Put it in lowercase; stop at the first dot. */
734
  for (cp = localhostname; *cp; ++cp) {
735
736
737
738
739
740
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
741

742
743
  /* Strip invalid characters. */
  cp = localhostname;
744
  out = outp = tor_malloc(strlen(localhostname) + 1);
745
746
747
748
749
750
751
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
752

753
754
755
756
757
758
759
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
760
/** Release storage held by <b>options</b> */
761
static void
762
options_free(or_options_t *options)
763
{
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
  int i;
  void *lvalue;

  for (i=0; config_vars[i].name; ++i) {
    lvalue = ((char*)options) + config_vars[i].var_offset;
    switch(config_vars[i].type) {
      case CONFIG_TYPE_UINT:
      case CONFIG_TYPE_BOOL:
      case CONFIG_TYPE_DOUBLE:
      case CONFIG_TYPE_OBSOLETE:
        break; /* nothing to free for these config types */
      case CONFIG_TYPE_STRING:
        tor_free(*(char **)lvalue);
        break;
      case CONFIG_TYPE_LINELIST:
779
      case CONFIG_TYPE_LINELIST_V:
780
781
782
783
784
785
786
787
788
789
        config_free_lines(*(struct config_line_t**)lvalue);
        *(struct config_line_t**)lvalue = NULL;
        break;
      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;
790
791
792
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
793
794
795
    }
  }
  /* XXX this last part is an exception. can we make it not needed? */
796
  if (options->RedirectExitList) {
Nick Mathewson's avatar
Nick Mathewson committed
797
798
    SMARTLIST_FOREACH(options->RedirectExitList,
                      exit_redirect_t *, p, tor_free(p));
Roger Dingledine's avatar
Roger Dingledine committed
799
    smartlist_free(options->RedirectExitList);
800
    options->RedirectExitList = NULL;
801
  }
802
}
803

804
805
806
/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
static or_options_t *
options_dup(or_options_t *old)
807
{
808
809
810
  or_options_t *new;
  int i;
  struct config_line_t *line;
811

812
813
814
815
816
817
818
819
  new = tor_malloc_zero(sizeof(or_options_t));
  for (i=0; config_vars[i].name; ++i) {
    line = config_get_assigned_option(old, config_vars[i].name);
    if (line) {
      if (config_assign(new, line, 0) < 0) {
        log_fn(LOG_WARN,"Bug: config_get_assigned_option() generated "
               "something we couldn't config_assign().");
        tor_assert(0);
820
      }
821
822
    }
    config_free_lines(line);
823
  }
824
  return new;
825
826
}

827
828
/** Set <b>options</b> to hold reasonable defaults for most options.
 * Each option defaults to zero. */
829
830
void
options_init(or_options_t *options)
831
{
832
833
834
835
836
837
838
  int i;
  config_var_t *var;

  for (i=0; config_vars[i].name; ++i) {
    var = &config_vars[i];
    if(!var->initvalue)
      continue; /* defaults to NULL or 0 */
839
    option_reset(options, var);
840
  }
841
842
}

Roger Dingledine's avatar
Roger Dingledine committed
843
static int
844
options_validate(or_options_t *options)
Roger Dingledine's avatar
Roger Dingledine committed
845
846
847
848
{
  int i;
  int result = 0;
  struct config_line_t *cl;
849

850
851
  if (options->ORPort < 0 || options->ORPort > 65535) {
    log(LOG_WARN, "ORPort option out of bounds.");
852
853
854
    result = -1;
  }

855
  if (options->Nickname == NULL) {
856
    if (server_mode(options)) {
857
858
859
860
      if (!(options->Nickname = get_default_nickname()))
        return -1;
      log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
    }
861
862
863
864
865
866
  } else {
    if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
        strlen(options->Nickname)) {
      log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
      result = -1;
    }
867
868
869
870
    if (strlen(options->Nickname) == 0) {
      log_fn(LOG_WARN, "Nickname must have at least one character");
      result = -1;
    }
871
872
873
874
    if (strlen(options->Nickname) > MAX_NICKNAME_LEN) {
      log_fn(LOG_WARN, "Nickname '%s' has more than %d characters.",
             options->Nickname, MAX_NICKNAME_LEN);
      result = -1;
875
    }
876
877
  }

878
  if (server_mode(options)) {
879
880
    /* confirm that our address isn't broken, so we can complain now */
    uint32_t tmp;
881
    if (resolve_my_address(options->Address, &tmp) < 0)
882
      result = -1;
883
884
  }

885
886
  if (options->SocksPort < 0 || options->SocksPort > 65535) {
    log(LOG_WARN, "SocksPort option out of bounds.");
887
888
889
    result = -1;
  }

890
891
  if (options->SocksPort == 0 && options->ORPort == 0) {
    log(LOG_WARN, "SocksPort and ORPort are both undefined? Quitting.");
892
    result = -1;
Roger Dingledine's avatar
Roger Dingledine committed
893
  }
894

895
896
897
898
899
  if (options->ControlPort < 0 || options->ControlPort > 65535) {
    log(LOG_WARN, "ControlPort option out of bounds.");
    result = -1;
  }

900
901
  if (options->DirPort < 0 || options->DirPort > 65535) {
    log(LOG_WARN, "DirPort option out of bounds.");
902
903
904
    result = -1;
  }

905
906
  if (options->StrictExitNodes &&
      (!options->ExitNodes || !strlen(options->ExitNodes))) {
907
    log(LOG_WARN, "StrictExitNodes set, but no ExitNodes listed.");
908
909
  }

910
911
  if (options->StrictEntryNodes &&
      (!options->EntryNodes || !strlen(options->EntryNodes))) {
912
    log(LOG_WARN, "StrictEntryNodes set, but no EntryNodes listed.");
913
914
  }

915
916
  if (options->AuthoritativeDir && options->RecommendedVersions == NULL) {
    log(LOG_WARN, "Directory servers must configure RecommendedVersions.");
917
918
919
    result = -1;
  }

920
921
  if (options->AuthoritativeDir && !options->DirPort) {
    log(LOG_WARN, "Running as authoritative directory, but no DirPort set.");
922
923
924
    result = -1;
  }

925
926
  if (options->AuthoritativeDir && !options->ORPort) {
    log(LOG_WARN, "Running as authoritative directory, but no ORPort set.");
Roger Dingledine's avatar
Roger Dingledine committed
927
928
    result = -1;
  }
929

930
931
  if (options->AuthoritativeDir && options->ClientOnly) {
    log(LOG_WARN, "Running as authoritative directory, but ClientOnly also set.");
Roger Dingledine's avatar
Roger Dingledine committed
932
933
    result = -1;
  }
934

935
  if (options->FirewallPorts) {
936
    SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp,
937
938
    {
      i = atoi(cp);
939
      if (i < 1 || i > 65535) {
940
941
942
943
944
945
        log(LOG_WARN, "Port '%s' out of range in FirewallPorts", cp);
        result=-1;
      }
    });
  }
  options->_AllowUnverified = 0;
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
  if (options->AllowUnverifiedNodes) {
    SMARTLIST_FOREACH(options->AllowUnverifiedNodes, const char *, cp, {
        if (!strcasecmp(cp, "entry"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_ENTRY;
        else if (!strcasecmp(cp, "exit"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_EXIT;
        else if (!strcasecmp(cp, "middle"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_MIDDLE;
        else if (!strcasecmp(cp, "introduction"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_INTRODUCTION;
        else if (!strcasecmp(cp, "rendezvous"))
          options->_AllowUnverified |= ALLOW_UNVERIFIED_RENDEZVOUS;
        else {
          log(LOG_WARN, "Unrecognized value '%s' in AllowUnverifiedNodes",
              cp);
          result=-1;
        }
      });
  }

  if (options->SocksPort >= 1 &&
      (options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0)) {
    log(LOG_WARN, "PathlenCoinWeight option must be >=0.0 and <1.0.");
969
970
971
    result = -1;
  }

972
973
  if (options->MaxConn < 1) {
    log(LOG_WARN, "MaxConn option must be a non-zero positive integer.");
974
975
976
    result = -1;
  }

977
978
  if (options->MaxConn >= MAXCONNECTIONS) {
    log(LOG_WARN, "MaxConn option must be less than %d.", MAXCONNECTIONS);
979
980
981
    result = -1;
  }

982
#define MIN_DIRFETCHPOSTPERIOD 60
983
984
  if (options->DirFetchPostPeriod < MIN_DIRFETCHPOSTPERIOD) {
    log(LOG_WARN, "DirFetchPostPeriod option must be at least %d.", MIN_DIRFETCHPOSTPERIOD);
985
986
    result = -1;
  }
987
988
989
  if (options->DirFetchPostPeriod > MIN_ONION_KEY_LIFETIME / 2) {
    log(LOG_WARN, "DirFetchPostPeriod is too large; clipping.");
    options->DirFetchPostPeriod = MIN_ONION_KEY_LIFETIME / 2;
990
  }
991

992
  if (options->KeepalivePeriod < 1) {
Roger Dingledine's avatar
Roger Dingledine committed
993
    log(LOG_WARN,"KeepalivePeriod option must be positive.");
994
995
996
    result = -1;
  }

997
  if (options->AccountingStart < 0 || options->AccountingStart > 31) {
998
    log(LOG_WARN,"Monthly accounting must start on a day of the month, and no months have %d days.",
999
1000
        options->AccountingStart);
    result = -1;