config.c 48.5 KB
Newer Older
1
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2
3
4
/* See LICENSE for licensing information */
/* $Id$ */

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

Roger Dingledine's avatar
Roger Dingledine committed
12
#include "or.h"
13
14
15
#ifdef MS_WINDOWS
#include <shlobj.h>
#endif
Roger Dingledine's avatar
Roger Dingledine committed
16

Nick Mathewson's avatar
Nick Mathewson committed
17
18
/** Enumeration of types which option values can take */
typedef enum config_type_t {
19
20
21
22
23
24
25
  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 */
26
27
28
29
30
  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.
                             */
31
  CONFIG_TYPE_OBSOLETE,     /**< Obsolete (ignored) option. */
Nick Mathewson's avatar
Nick Mathewson committed
32
} config_type_t;
33

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

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

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

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

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

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

158
static struct config_line_t *config_get_commandlines(int argc, char **argv);
159
static int config_get_lines(FILE *f, struct config_line_t **result);
160
static void config_free_lines(struct config_line_t *front);
161
162
163
164
static int config_assign_line(or_options_t *options, struct config_line_t *c,
                              int reset);
static int config_assign(or_options_t *options, struct config_line_t *list,
                         int reset);
165
static int parse_dir_server_line(const char *line);
Roger Dingledine's avatar
Roger Dingledine committed
166
167
static int parse_redirect_line(or_options_t *options,
                               struct config_line_t *line);
168
static const char *expand_abbrev(const char *option, int commandline_only);
169
static config_var_t *config_find_option(const char *key);
170
static void reset_option(or_options_t *options, config_var_t *var);
171
172
173
174
175
176
177
178
179
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);
180

Nick Mathewson's avatar
Nick Mathewson committed
181
/** If <b>option</b> is an official abbreviation for a longer option,
182
183
184
 * 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. */
185
static const char *
186
expand_abbrev(const char *option, int command_line)
187
188
189
190
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
191
192
    if (!strcmp(option,config_abbrevs[i].abbreviated) &&
        (command_line || !config_abbrevs[i].commandline_only)) {
193
      return config_abbrevs[i].full;
194
    }
195
196
197
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
198

Nick Mathewson's avatar
Nick Mathewson committed
199
/** Helper: Read a list of configuration options from the command line. */
200
201
202
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
203
204
  struct config_line_t *new;
  struct config_line_t *front = NULL;
205
206
207
  char *s;
  int i = 1;

208
  while (i < argc-1) {
209
210
211
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
212
      continue;
213
214
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
215
      continue;
216
217
    }

218
    new = tor_malloc(sizeof(struct config_line_t));
219
    s = argv[i];
220

221
222
    while(*s == '-')
      s++;
223

224
    new->key = tor_strdup(expand_abbrev(s, 1));
225
    new->value = tor_strdup(argv[i+1]);
226
227

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
228
        new->key, new->value);
229
230
231
232
233
234
235
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
236
237
/** Helper: allocate a new configuration option mapping 'key' to 'val',
 * prepend it to 'front', and return the newly allocated config_line_t */
238
struct config_line_t *
239
240
241
242
243
config_line_prepend(struct config_line_t *front,
                    const char *key,
                    const char *val)
{
  struct config_line_t *newline;
244

245
246
247
248
249
250
251
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
  newline->next = front;
  return newline;
}

252
/** Helper: parse the config file and strdup into key/value
253
254
255
 * strings. Set *result to the list, or NULL if parsing the file
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
256
257
258
static int
config_get_lines(FILE *f, struct config_line_t **result)
{
259
260
  struct config_line_t *front = NULL;
  char line[CONFIG_LINE_T_MAXLEN];
261
  int r;
262
  char *key, *value;
263

264
  while ((r = parse_line_from_file(line, sizeof(line), f, &key, &value)) > 0) {
265
    front = config_line_prepend(front, key, value);
Roger Dingledine's avatar
Roger Dingledine committed
266
  }
267
268

  if (r < 0) {
269
270
271
    *result = NULL;
    return -1;
  }
272
273
  *result = front;
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
274
275
}

Nick Mathewson's avatar
Nick Mathewson committed
276
277
278
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
279
280
281
static void
config_free_lines(struct config_line_t *front)
{
282
  struct config_line_t *tmp;
283

284
  while (front) {
285
286
287
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
288
289
290
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
291
292
293
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
294
295
296
297
/** 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.
 */
298
299
300
static config_var_t *config_find_option(const char *key)
{
  int i;
Nick Mathewson's avatar
Nick Mathewson committed
301
  /* First, check for an exact (case-insensitive) match */
302
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
303
    if (!strcasecmp(key, config_vars[i].name))
304
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
305
306
307
308
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
    if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
309
310
311
312
313
314
      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
315
  /* Okay, unrecogized options */
316
317
318
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
319
/** If <b>c</b> is a syntactically valid configuration line, update
320
321
322
323
324
 * <b>options</b> with its value and return 0.  Otherwise return -1.
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
325
static int
326
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
327
{
328
  int i, ok;
329
330
  config_var_t *var;
  void *lvalue;
331

332
333
334
335
336
337
338
  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)) {
339
    tor_free(c->key);
340
    c->key = tor_strdup(var->name);
341
342
  }

343
344
345
346
347
  if (reset && !strlen(c->value)) {
    reset_option(options, var);
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
348
  lvalue = ((char*)options) + var->var_offset;
349
  switch(var->type) {
350

351
352
353
354
355
356
357
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds. Skipping.",
          c->key,c->value);
      return 0;
    }
358
    *(int *)lvalue = i;
359
360
361
362
363
364
365
366
    break;

  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1. Skipping.", c->key);
      return 0;
    }
367
    *(int *)lvalue = i;
368
369
370
    break;

  case CONFIG_TYPE_STRING:
371
372
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
373
374
375
    break;

  case CONFIG_TYPE_DOUBLE:
376
    *(double *)lvalue = atof(c->value);
377
378
379
    break;

  case CONFIG_TYPE_CSV:
380
381
    if (*(smartlist_t**)lvalue == NULL)
      *(smartlist_t**)lvalue = smartlist_create();
382

383
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
384
385
386
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

387
388
389
390
391
392
393
394
395

  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;
396
397
398
399

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
400
401
402
403
404
405
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
    return -1;
  default:
    tor_assert(0);
    break;
406
  }
407

408
  return 0;
409
410
}

411
412
413
414
415
416
417
418
419
420
421
422
423
/** 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. */

  reset_option(options, var);
}

424
425
426
427
428
429
430
431
432
433
434
435
436
437
/** 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;
438
439
440
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
441
442
443
  }
  value = ((char*)options) + var->var_offset;

444
445
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
    /* 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:
      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);
487
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
488
489
490
491
492
493
      return NULL;
    }

  return result;
}

494
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
495
 * For each item, convert as appropriate and assign to <b>options</b>.
496
 * If an item is unrecognized, return -1 immediately,
497
498
499
500
501
502
 * 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
 * extending) their previous values.
 */
503
static int
504
config_assign(or_options_t *options, struct config_line_t *list, int reset)
505
{
506
507
508
509
510
511
512
513
  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);
514
    }
515
516
517
518
519
520
521
522
  }

  /* pass 2: if we're reading from a resetting souurce, clear all mentioned
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
523

524
525
526
  /* pass 3: assign. */
  while (list) {
    if (config_assign_line(options, list, reset))
527
      return -1;
528
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
529
  }
530
  return 0;
531
532
}

533
534
535
static void
add_default_trusted_dirservers(void)
{
Nick Mathewson's avatar
Nick Mathewson committed
536
537
538
539
  /* moria1 */
  parse_dir_server_line("18.244.0.188:9031 "
                        "FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
  /* moria2 */
540
  parse_dir_server_line("18.244.0.114:80 "
Nick Mathewson's avatar
Nick Mathewson committed
541
542
543
544
                        "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");
545
546
}

Nick Mathewson's avatar
Nick Mathewson committed
547
/** Print a usage message for tor. */
548
549
550
static void
print_usage(void)
{
551
  printf("tor -f <torrc> [args]\n"
552
553
         "See man page for more options. This -h is obsolete.\n");
#if 0
554
         "-b <bandwidth>\t\tbytes/second rate limiting\n"
555
         "-d <file>\t\tDebug file\n"
556
557
558
559
         "-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"
560
         "-s <IP>\t\t\tPort to bind to for Socks\n");
561
562
  printf("\nServer options:\n"
         "-n <nick>\t\tNickname of router\n"
563
         "-o <port>\t\tOR port to bind to\n"
564
         "-p <file>\t\tPID file\n");
565
#endif
566
567
}

Nick Mathewson's avatar
Nick Mathewson committed
568
/**
569
570
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
571
 */
572
573
574
int
resolve_my_address(const char *address, uint32_t *addr)
{
575
576
  struct in_addr in;
  struct hostent *rent;
577
  char hostname[256];
578
  int explicit_ip=1;
579

580
581
  tor_assert(addr);

582
583
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
584
  } else { /* then we need to guess our address */
585
    explicit_ip = 0; /* it's implicit */
586

587
    if (gethostname(hostname, sizeof(hostname)) < 0) {
588
589
590
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
591
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
592
593
  }

594
  /* now we know hostname. resolve it and keep only the IP */
595

596
  if (tor_inet_aton(hostname, &in) == 0) {
597
598
    /* then we have to resolve it */
    explicit_ip = 0;
599
    rent = (struct hostent *)gethostbyname(hostname);
600
    if (!rent) {
601
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
602
603
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
604
    tor_assert(rent->h_length == 4);
605
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
606
  }
607
608

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
609
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
610
           "Please set the Address config option to be the IP you want to use.",
611
           hostname, inet_ntoa(in));
612
613
    return -1;
  }
614
615

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
616
  *addr = ntohl(in.s_addr);
617
618
619
  return 0;
}

620
621
static char *
get_default_nickname(void)
622
623
624
625
{
  char localhostname[256];
  char *cp, *out, *outp;

626
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
627
628
629
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
630

631
  /* Put it in lowercase; stop at the first dot. */
632
  for (cp = localhostname; *cp; ++cp) {
633
634
635
636
637
638
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
639

640
641
  /* Strip invalid characters. */
  cp = localhostname;
642
  out = outp = tor_malloc(strlen(localhostname) + 1);
643
644
645
646
647
648
649
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
650

651
652
653
654
655
656
657
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
658
/** Release storage held by <b>options</b> */
659
660
661
static void
free_options(or_options_t *options)
{
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
  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:
677
      case CONFIG_TYPE_LINELIST_V:
678
679
680
681
682
683
684
685
686
687
        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;
688
689
690
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
691
692
693
    }
  }
  /* XXX this last part is an exception. can we make it not needed? */
694
  if (options->RedirectExitList) {
Nick Mathewson's avatar
Nick Mathewson committed
695
696
    SMARTLIST_FOREACH(options->RedirectExitList,
                      exit_redirect_t *, p, tor_free(p));
Roger Dingledine's avatar
Roger Dingledine committed
697
    smartlist_free(options->RedirectExitList);
698
    options->RedirectExitList = NULL;
699
  }
700
}
701

702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
/** Replace the option indexed by <b>var</b> in <b>options</b> with its
 * default value. */
static void
reset_option(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) {
    c = tor_malloc(sizeof(struct config_line_t));
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

749
750
751
752
753
/** Set <b>options</b> to hold reasonable defaults for most options.
 * Each option defaults to zero. */
static void
init_options(or_options_t *options)
{
754
755
756
  int i;
  config_var_t *var;

757
  memset(options,0,sizeof(or_options_t));
758
759
760
761
  for (i=0; config_vars[i].name; ++i) {
    var = &config_vars[i];
    if(!var->initvalue)
      continue; /* defaults to NULL or 0 */
762
    reset_option(options, var);
763
  }
764
765
}

766
#ifdef MS_WINDOWS
767
768
769
770
771
static char *get_windows_conf_root(void)
{
  static int is_set = 0;
  static char path[MAX_PATH+1];

772
773
774
  LPITEMIDLIST idl;
  IMalloc *m;
  HRESULT result;
775
776
777

  if (is_set)
    return path;
778

779
780
781
782
783
  /* Find X:\documents and settings\username\applicatation data\ .
   * We would use SHGetSpecialFolder path, but that wasn't added until IE4.
   */
  if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA,
                                            &idl))) {
784
785
786
787
    GetCurrentDirectory(MAX_PATH, path);
    is_set = 1;
    log_fn(LOG_WARN, "I couldn't find your application data folder: are you running an ancient version of Windows 95? Defaulting to '%s'", path);
    return path;
788
789
790
791
792
793
794
795
796
797
  }
  /* Convert the path from an "ID List" (whatever that is!) to a path. */
  result = SHGetPathFromIDList(idl, path);
  /* Now we need to free the */
  SHGetMalloc(&m);
  if (m) {
    m->lpVtbl->Free(m, idl);
    m->lpVtbl->Release(m);
  }
  if (!SUCCEEDED(result)) {
Nick Mathewson's avatar
Nick Mathewson committed
798
    return NULL;
799
  }
800
  strlcat(path,"\\tor",MAX_PATH);
801
802
803
804
805
806
807
808
809
810
811
  is_set = 1;
  return path;
}
#endif

static char *
get_default_conf_file(void)
{
#ifdef MS_WINDOWS
  char *path = tor_malloc(MAX_PATH);
  strlcpy(path, get_windows_conf_root(), MAX_PATH);
812
  strlcat(path,"\\torrc",MAX_PATH);
813
814
  return path;
#else
815
  return tor_strdup(CONFDIR "/torrc");
816
817
818
#endif
}

819
820
821
822
/** Verify whether lst is a string containing valid-looking space-separated
 * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure.
 */
static int check_nickname_list(const char *lst, const char *name)
823
{
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  int r = 0;
  smartlist_t *sl;

  if (!lst)
    return 0;
  sl = smartlist_create();
  smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  SMARTLIST_FOREACH(sl, const char *, s,
    {
      if (!is_legal_nickname_or_hexdigest(s)) {
        log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name);
        r = -1;
      }
    });
  SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
839
  smartlist_free(sl);
840
841
842
  return r;
}

Roger Dingledine's avatar
Roger Dingledine committed
843
844
845
846
847
848
static int
validate_options(or_options_t *options)
{
  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()) {
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()) {
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;