config.c 53.5 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, int validate_only);
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
/*
 * Functions to read and write the global options pointer.
 */

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

187
188
189
/** Return the currently configured options. */
or_options_t *
get_options(void) {
190
191
192
  tor_assert(global_options);
  return global_options;
}
193

Roger Dingledine's avatar
Roger Dingledine committed
194
195
196
/** Change the current global options to contain <b>new_val</b> instead
 * of their current value; free the old value as necessary.  Where
 * <b>new_val</b> is different from the old value, update the process to
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
 * use the new value instead.
 *
 * 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.
 */
void
set_options(or_options_t *new_val) {
  struct config_line_t *cl;

  if (global_options)
    options_free(global_options);
  global_options = new_val;

  clear_trusted_dir_servers();
  for (cl = new_val->DirServers; cl; cl = cl->next) {
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
             "Previously validated DirServer line could not be added!");
      tor_assert(0);
    }
  }

  if (rend_config_services(new_val, 0)<0) {
    log_fn(LOG_ERR,
           "Previously validated hidden services line could not be added!");
    tor_assert(0);
  }
227
228
229
230
231
232
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
233
/** If <b>option</b> is an official abbreviation for a longer option,
234
235
236
 * 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. */
237
static const char *
238
expand_abbrev(const char *option, int command_line)
239
240
241
242
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
243
244
    if (!strcmp(option,config_abbrevs[i].abbreviated) &&
        (command_line || !config_abbrevs[i].commandline_only)) {
245
      return config_abbrevs[i].full;
246
    }
247
248
249
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
250

Nick Mathewson's avatar
Nick Mathewson committed
251
/** Helper: Read a list of configuration options from the command line. */
252
253
254
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
255
256
  struct config_line_t *new;
  struct config_line_t *front = NULL;
257
258
259
  char *s;
  int i = 1;

260
  while (i < argc-1) {
261
262
263
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
264
      continue;
265
266
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
267
      continue;
268
269
    }

270
    new = tor_malloc(sizeof(struct config_line_t));
271
    s = argv[i];
272

273
274
    while(*s == '-')
      s++;
275

276
    new->key = tor_strdup(expand_abbrev(s, 1));
277
    new->value = tor_strdup(argv[i+1]);
278
279

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
280
        new->key, new->value);
281
282
283
284
285
286
287
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
288
289
/** Helper: allocate a new configuration option mapping 'key' to 'val',
 * prepend it to 'front', and return the newly allocated config_line_t */
290
struct config_line_t *
291
292
293
294
295
config_line_prepend(struct config_line_t *front,
                    const char *key,
                    const char *val)
{
  struct config_line_t *newline;
296

297
298
299
300
301
302
303
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
  newline->next = front;
  return newline;
}

304
305
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
306
307
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
308
309
int
config_get_lines(char *string, struct config_line_t **result)
310
{
311
312
  struct config_line_t *list = NULL;
  char *k, *v;
313

314
315
316
317
318
319
320
321
322
  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);
323

324
  *result = list;
325
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
326
327
}

Nick Mathewson's avatar
Nick Mathewson committed
328
329
330
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
331
void
332
333
config_free_lines(struct config_line_t *front)
{
334
  struct config_line_t *tmp;
335

336
  while (front) {
337
338
339
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
340
341
342
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
343
344
345
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
346
347
348
349
/** 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.
 */
350
351
352
static config_var_t *config_find_option(const char *key)
{
  int i;
Nick Mathewson's avatar
Nick Mathewson committed
353
  /* First, check for an exact (case-insensitive) match */
354
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
355
    if (!strcasecmp(key, config_vars[i].name))
356
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
357
358
359
360
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
    if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
361
362
363
364
365
366
      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
367
  /* Okay, unrecogized options */
368
369
370
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
371
/** If <b>c</b> is a syntactically valid configuration line, update
372
373
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
374
375
376
377
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
378
static int
379
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
380
{
381
  int i, ok;
382
383
  config_var_t *var;
  void *lvalue;
384

385
386
387
388
389
390
391
  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)) {
392
    tor_free(c->key);
393
    c->key = tor_strdup(var->name);
394
395
  }

396
  if (reset && !strlen(c->value)) {
397
    option_reset(options, var);
398
399
400
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
401
  lvalue = ((char*)options) + var->var_offset;
402
  switch(var->type) {
403

404
405
406
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
407
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
408
          c->key,c->value);
409
      return -2;
410
    }
411
    *(int *)lvalue = i;
412
413
414
415
416
    break;

  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
417
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
418
      return -2;
419
    }
420
    *(int *)lvalue = i;
421
422
423
    break;

  case CONFIG_TYPE_STRING:
424
425
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
426
427
428
    break;

  case CONFIG_TYPE_DOUBLE:
429
    *(double *)lvalue = atof(c->value);
430
431
432
    break;

  case CONFIG_TYPE_CSV:
433
434
    if (*(smartlist_t**)lvalue == NULL)
      *(smartlist_t**)lvalue = smartlist_create();
435

436
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
437
438
439
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

440
441
442
443
444
445
446
447
  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;
448
449
450
451

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
452
453
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
454
    return -2;
455
456
457
  default:
    tor_assert(0);
    break;
458
  }
459
  return 0;
460
461
}

462
463
464
465
466
467
468
469
470
471
/** 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. */

472
  option_reset(options, var);
473
474
}

475
476
477
478
479
480
481
482
483
484
485
486
487
488
/** 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;
489
490
491
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
492
493
494
  }
  value = ((char*)options) + var->var_offset;

495
496
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
    /* 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:
519
520
      /* XXX This means every or_options_t uint or bool element
       * needs to be an int. Not, say, a uint16_t or char. */
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
      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);
540
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
541
542
543
544
545
546
      return NULL;
    }

  return result;
}

547
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
548
 * For each item, convert as appropriate and assign to <b>options</b>.
549
 * If an item is unrecognized, return -1 immediately,
550
551
552
553
 * 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
554
555
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
556
 */
557
static int
558
config_assign(or_options_t *options, struct config_line_t *list, int reset)
559
{
560
561
562
563
564
565
566
567
  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);
568
    }
569
570
  }

571
  /* pass 2: if we're reading from a resetting source, clear all mentioned
572
573
574
575
576
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
577

578
579
  /* pass 3: assign. */
  while (list) {
580
581
582
    int r;
    if ((r=config_assign_line(options, list, reset)))
      return r;
583
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
584
  }
585
  return 0;
586
587
}

588
589
590
/** 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,
591
592
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
593
594
595
596
 */
int
config_trial_assign(or_options_t **options, struct config_line_t *list, int reset)
{
597
  int r;
598
599
  or_options_t *trial_options = options_dup(*options);

600
  if ((r=config_assign(trial_options, list, reset)) < 0) {
601
    options_free(trial_options);
602
    return r;
603
604
605
606
  }

  if (options_validate(trial_options) < 0) {
    options_free(trial_options);
607
    return -2;
608
609
610
611
  }

  if (options_transition_allowed(*options, trial_options) < 0) {
    options_free(trial_options);
612
    return -3;
613
614
  }

615
  set_options(trial_options);
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  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) {
658
    c = tor_malloc_zero(sizeof(struct config_line_t));
659
660
661
662
663
664
665
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

666
667
/** Set <b>options</b>-&gt;DirServers to contain the default directory 
 * servers. */
668
static void
669
add_default_trusted_dirservers(or_options_t *options)
670
{
Nick Mathewson's avatar
Nick Mathewson committed
671
  /* moria1 */
672
673
  options->DirServers = config_line_prepend(options->DirServers, "DirServer",
       "18.244.0.188:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
Nick Mathewson's avatar
Nick Mathewson committed
674
  /* moria2 */
675
676
  options->DirServers = config_line_prepend(options->DirServers, "DirServer",
         "18.244.0.114:80 719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
Nick Mathewson's avatar
Nick Mathewson committed
677
  /* tor26 */
678
679
  options->DirServers = config_line_prepend(options->DirServers, "DirServer",
     "62.116.124.106:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
680
681
}

Nick Mathewson's avatar
Nick Mathewson committed
682
/** Print a usage message for tor. */
683
684
685
static void
print_usage(void)
{
686
  printf("tor -f <torrc> [args]\n"
687
688
         "See man page for more options. This -h is obsolete.\n");
#if 0
689
         "-b <bandwidth>\t\tbytes/second rate limiting\n"
690
         "-d <file>\t\tDebug file\n"
691
692
693
694
         "-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"
695
         "-s <IP>\t\t\tPort to bind to for Socks\n");
696
697
  printf("\nServer options:\n"
         "-n <nick>\t\tNickname of router\n"
698
         "-o <port>\t\tOR port to bind to\n"
699
         "-p <file>\t\tPID file\n");
700
#endif
701
702
}

Nick Mathewson's avatar
Nick Mathewson committed
703
/**
704
705
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
706
 */
707
708
709
int
resolve_my_address(const char *address, uint32_t *addr)
{
710
711
  struct in_addr in;
  struct hostent *rent;
712
  char hostname[256];
713
  int explicit_ip=1;
714

715
716
  tor_assert(addr);

717
718
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
719
  } else { /* then we need to guess our address */
720
    explicit_ip = 0; /* it's implicit */
721

722
    if (gethostname(hostname, sizeof(hostname)) < 0) {
723
724
725
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
726
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
727
728
  }

729
  /* now we know hostname. resolve it and keep only the IP */
730

731
  if (tor_inet_aton(hostname, &in) == 0) {
732
733
    /* then we have to resolve it */
    explicit_ip = 0;
734
    rent = (struct hostent *)gethostbyname(hostname);
735
    if (!rent) {
736
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
737
738
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
739
    tor_assert(rent->h_length == 4);
740
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
741
  }
742
743

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
744
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
745
           "Please set the Address config option to be the IP you want to use.",
746
           hostname, inet_ntoa(in));
747
748
    return -1;
  }
749
750

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
751
  *addr = ntohl(in.s_addr);
752
753
754
  return 0;
}

755
756
/** Called when we don't have a nickname set.  Try to guess a good
 * nickname based on the hostname, and return it. */
757
758
static char *
get_default_nickname(void)
759
760
761
762
{
  char localhostname[256];
  char *cp, *out, *outp;

763
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
764
765
766
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
767

768
  /* Put it in lowercase; stop at the first dot. */
769
  for (cp = localhostname; *cp; ++cp) {
770
771
772
773
774
775
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
776

777
778
  /* Strip invalid characters. */
  cp = localhostname;
779
  out = outp = tor_malloc(strlen(localhostname) + 1);
780
781
782
783
784
785
786
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
787

788
789
790
791
792
793
794
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
795
/** Release storage held by <b>options</b> */
796
static void
797
options_free(or_options_t *options)
798
{
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
  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:
814
      case CONFIG_TYPE_LINELIST_V:
815
816
817
818
819
820
821
822
823
824
        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;
825
826
827
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
828
829
830
    }
  }
  /* XXX this last part is an exception. can we make it not needed? */
831
  if (options->RedirectExitList) {
Nick Mathewson's avatar
Nick Mathewson committed
832
833
    SMARTLIST_FOREACH(options->RedirectExitList,
                      exit_redirect_t *, p, tor_free(p));
Roger Dingledine's avatar
Roger Dingledine committed
834
    smartlist_free(options->RedirectExitList);
835
    options->RedirectExitList = NULL;
836
  }
837
}
838

839
840
841
/** 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)
842
{
843
844
845
  or_options_t *new;
  int i;
  struct config_line_t *line;
846

847
848
849
850
851
852
853
854
  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);
855
      }
856
857
    }
    config_free_lines(line);
858
  }
859
  return new;
860
861
}

862
863
/** Set <b>options</b> to hold reasonable defaults for most options.
 * Each option defaults to zero. */
864
865
void
options_init(or_options_t *options)
866
{
867
868
869
870
871
872
873
  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 */
874
    option_reset(options, var);
875
  }
876
877
}

878
879
880
/** Return 0 if every setting in <b>options</b> is reasonable.  Else
 * warn and return -1.  Should have no side effects, except for
 * normalizing the contents of <b>options</b>. */
Roger Dingledine's avatar
Roger Dingledine committed
881
static int
882
options_validate(or_options_t *options)
Roger Dingledine's avatar
Roger Dingledine committed
883
884
885
886
{
  int i;
  int result = 0;
  struct config_line_t *cl;
887

888
889
  if (options->ORPort < 0 || options->ORPort > 65535) {
    log(LOG_WARN, "ORPort option out of bounds.");
890
891
892
    result = -1;
  }

893
  if (options->Nickname == NULL) {
894
    if (server_mode(options)) {
895
896
897
898
      if (!(options->Nickname = get_default_nickname()))
        return -1;
      log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
    }
899
900
901
902
903
904
  } else {
    if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
        strlen(options->Nickname)) {
      log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
      result = -1;
    }
905
906
907
908
    if (strlen(options->Nickname) == 0) {
      log_fn(LOG_WARN, "Nickname must have at least one character");
      result = -1;
    }
909
910
911
912
    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;
913
    }
914
915
  }

916
917
918
919
920
921
922
923
  if (normalize_log_options(options))
    return -1;

  /* Special case if no options are given. */
  if (!options->Logs) {
    options->Logs = config_line_prepend(NULL, "Log", "notice-err stdout");
  }

924
  if (server_mode(options)) {
925
926
    /* confirm that our address isn't broken, so we can complain now */
    uint32_t tmp;
927
    if (resolve_my_address(options->Address, &tmp) < 0)
928
      result = -1;
929
930
  }

931
932
  if (options->SocksPort < 0 || options->SocksPort > 65535) {
    log(LOG_WARN, "SocksPort option out of bounds.");
933
934
935
    result = -1;
  }

936
937
  if (options->SocksPort == 0 && options->ORPort == 0) {
    log(LOG_WARN, "SocksPort and ORPort are both undefined? Quitting.");
938
    result = -1;
Roger Dingledine's avatar
Roger Dingledine committed
939
  }
940

941
942
943
944
945
  if (options->ControlPort < 0 || options->ControlPort > 65535) {
    log(LOG_WARN, "ControlPort option out of bounds.");
    result = -1;
  }

946
947
  if (options->DirPort < 0 || options->DirPort > 65535) {
    log(LOG_WARN, "DirPort option out of bounds.");
948
949
950
    result = -1;
  }

951
952
  if (options->StrictExitNodes &&
      (!options->ExitNodes || !strlen(options->ExitNodes))) {
953
    log(LOG_WARN, "StrictExitNodes set, but no ExitNodes listed.");
954
955
  }

956
957
  if (options->StrictEntryNodes &&
      (!options->EntryNodes || !strlen(options->EntryNodes))) {
958
    log(LOG_WARN, "StrictEntryNodes set, but no EntryNodes listed.");
959
960
  }

961
962
  if (options->AuthoritativeDir && options->RecommendedVersions == NULL) {
    log(LOG_WARN, "Directory servers must configure RecommendedVersions.");
963
964
965
    result = -1;
  }

966
967
  if (options->AuthoritativeDir && !options->DirPort) {
    log(LOG_WARN, "Running as authoritative directory, but no DirPort set.");
968
969
970
    result = -1;
  }

971
972
  if (options->AuthoritativeDir && !options->ORPort) {
    log(LOG_WARN, "Running as authoritative directory, but no ORPort set.");
Roger Dingledine's avatar
Roger Dingledine committed
973
974
    result = -1;
  }
975

976
977
  if (options->AuthoritativeDir && options->ClientOnly) {
    log(LOG_WARN, "Running as authoritative directory, but ClientOnly also set.");
Roger Dingledine's avatar
Roger Dingledine committed
978
979
    result = -1;
  }
980

981
  if (options->FirewallPorts) {
982
    SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp,
983
984
    {
      i = atoi(cp);
985
      if (i < 1 || i > 65535) {
986
987
988
989
990
991
        log(LOG_WARN, "Port '%s' out of range in FirewallPorts", cp);
        result=-1;
      }
    });
  }
  options->_AllowUnverified = 0;
992
993
994
995
996
997
998
999
1000
  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"))