config.c 56.1 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
  VAR("MaxConn",             UINT,     MaxConn,              "1024"),
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
Nick Mathewson's avatar
Nick Mathewson committed
129
  VAR("MonthlyAccountingStart",UINT,   AccountingStart,      "1"),
130
131
132
133
134
135
136
137
138
139
  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
 * 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) {
  if (global_options)
    options_free(global_options);
  global_options = new_val;
210
211
212
213
214
215
216
217
218
219
}

/** Fetch the active option list, and take actions based on it. All
 * of the things we do should survive being done repeatedly.
 * Return 0 if all goes well, return -1 if it's time to die.
 */
int
options_act(void) {
  struct config_line_t *cl;
  or_options_t *options = get_options();
220
221

  clear_trusted_dir_servers();
222
  for (cl = options->DirServers; cl; cl = cl->next) {
223
224
225
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
             "Previously validated DirServer line could not be added!");
226
      return -1;
227
228
229
    }
  }

230
  if (rend_config_services(options, 0)<0) {
231
232
    log_fn(LOG_ERR,
           "Previously validated hidden services line could not be added!");
233
    return -1;
234
  }
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295

  /* Setuid/setgid as appropriate */
  if(options->User || options->Group) {
    if(switch_id(options->User, options->Group) != 0) {
      return -1;
    }
  }

/*XXX in options_validate, we should check if this is going to fail */
  /* Ensure data directory is private; create if possible. */
  if (get_data_directory() &&
      check_private_dir(get_data_directory(), 1) != 0) {
    log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
           get_data_directory());
    return -1;
  }

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

  if (set_max_file_descriptors(get_options()->MaxConn) < 0)
    return -1;

  /* Configure the log(s) */
  if (config_init_logs(options)<0)
    return -1;
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
  add_callback_log(LOG_WARN, LOG_ERR, control_event_logmsg);

  /* Start backgrounding the process, if requested. */
  if (options->RunAsDaemon) {
    start_daemon(get_data_directory());
  }

  /* Finish backgrounding the process */
  if(options->RunAsDaemon) {
    /* XXXX Can we delay this any more? */
    finish_daemon();
  }

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

  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
    log_fn(LOG_ERR,"Error reloading rendezvous service keys");
    return -1;
  }

  if(retry_all_listeners(1) < 0) {
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    return -1;
  }

  return 0;
296
297
298
299
300
301
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
302
/** If <b>option</b> is an official abbreviation for a longer option,
303
304
305
 * 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. */
306
static const char *
307
expand_abbrev(const char *option, int command_line)
308
309
310
311
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
312
313
    if (!strcmp(option,config_abbrevs[i].abbreviated) &&
        (command_line || !config_abbrevs[i].commandline_only)) {
314
      return config_abbrevs[i].full;
315
    }
316
317
318
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
319

Nick Mathewson's avatar
Nick Mathewson committed
320
/** Helper: Read a list of configuration options from the command line. */
321
322
323
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
324
325
  struct config_line_t *new;
  struct config_line_t *front = NULL;
326
327
328
  char *s;
  int i = 1;

329
  while (i < argc-1) {
330
331
332
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
333
      continue;
334
335
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
336
      continue;
337
338
    }

339
    new = tor_malloc(sizeof(struct config_line_t));
340
    s = argv[i];
341

342
343
    while(*s == '-')
      s++;
344

345
    new->key = tor_strdup(expand_abbrev(s, 1));
346
    new->value = tor_strdup(argv[i+1]);
347
348

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
349
        new->key, new->value);
350
351
352
353
354
355
356
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
357
358
/** Helper: allocate a new configuration option mapping 'key' to 'val',
 * prepend it to 'front', and return the newly allocated config_line_t */
359
struct config_line_t *
360
361
362
363
364
config_line_prepend(struct config_line_t *front,
                    const char *key,
                    const char *val)
{
  struct config_line_t *newline;
365

366
367
368
369
370
371
372
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
  newline->next = front;
  return newline;
}

373
374
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
375
376
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
377
378
int
config_get_lines(char *string, struct config_line_t **result)
379
{
380
381
  struct config_line_t *list = NULL;
  char *k, *v;
382

383
384
385
386
387
388
389
390
391
  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);
392

393
  *result = list;
394
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
395
396
}

Nick Mathewson's avatar
Nick Mathewson committed
397
398
399
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
400
void
401
402
config_free_lines(struct config_line_t *front)
{
403
  struct config_line_t *tmp;
404

405
  while (front) {
406
407
408
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
409
410
411
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
412
413
414
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
415
416
417
418
/** 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.
 */
419
420
421
static config_var_t *config_find_option(const char *key)
{
  int i;
Nick Mathewson's avatar
Nick Mathewson committed
422
  /* First, check for an exact (case-insensitive) match */
423
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
424
    if (!strcasecmp(key, config_vars[i].name))
425
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
426
427
428
429
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
    if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
430
431
432
433
434
435
      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
436
  /* Okay, unrecogized options */
437
438
439
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
440
/** If <b>c</b> is a syntactically valid configuration line, update
441
442
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
443
444
445
446
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
447
static int
448
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
449
{
450
  int i, ok;
451
452
  config_var_t *var;
  void *lvalue;
453

454
455
456
457
458
459
460
  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)) {
461
    tor_free(c->key);
462
    c->key = tor_strdup(var->name);
463
464
  }

465
  if (reset && !strlen(c->value)) {
466
    option_reset(options, var);
467
468
469
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
470
  lvalue = ((char*)options) + var->var_offset;
471
  switch(var->type) {
472

473
474
475
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
476
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
477
          c->key,c->value);
478
      return -2;
479
    }
480
    *(int *)lvalue = i;
481
482
483
484
485
    break;

  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
486
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
487
      return -2;
488
    }
489
    *(int *)lvalue = i;
490
491
492
    break;

  case CONFIG_TYPE_STRING:
493
494
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
495
496
497
    break;

  case CONFIG_TYPE_DOUBLE:
498
    *(double *)lvalue = atof(c->value);
499
500
501
    break;

  case CONFIG_TYPE_CSV:
502
503
    if (*(smartlist_t**)lvalue == NULL)
      *(smartlist_t**)lvalue = smartlist_create();
504

505
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
506
507
508
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

509
510
511
512
513
514
515
516
  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;
517
518
519
520

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
521
522
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
523
    return -2;
524
525
526
  default:
    tor_assert(0);
    break;
527
  }
528
  return 0;
529
530
}

531
532
533
534
535
536
537
538
539
540
/** 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. */

541
  option_reset(options, var);
542
543
}

544
545
546
547
548
549
550
551
552
553
554
555
556
557
/** 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;
558
559
560
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
561
562
563
  }
  value = ((char*)options) + var->var_offset;

564
565
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
    /* 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:
588
589
      /* XXX This means every or_options_t uint or bool element
       * needs to be an int. Not, say, a uint16_t or char. */
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
      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);
609
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
610
611
612
613
614
615
      return NULL;
    }

  return result;
}

616
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
617
 * For each item, convert as appropriate and assign to <b>options</b>.
618
 * If an item is unrecognized, return -1 immediately,
619
620
621
622
 * 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
623
624
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
625
 */
626
static int
627
config_assign(or_options_t *options, struct config_line_t *list, int reset)
628
{
629
630
631
632
633
634
635
636
  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);
637
    }
638
639
  }

640
  /* pass 2: if we're reading from a resetting source, clear all mentioned
641
642
643
644
645
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
646

647
648
  /* pass 3: assign. */
  while (list) {
649
650
651
    int r;
    if ((r=config_assign_line(options, list, reset)))
      return r;
652
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
653
  }
654
  return 0;
655
656
}

657
658
659
/** 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,
660
661
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
662
663
664
665
 */
int
config_trial_assign(or_options_t **options, struct config_line_t *list, int reset)
{
666
  int r;
667
668
  or_options_t *trial_options = options_dup(*options);

669
  if ((r=config_assign(trial_options, list, reset)) < 0) {
670
    options_free(trial_options);
671
    return r;
672
673
674
675
  }

  if (options_validate(trial_options) < 0) {
    options_free(trial_options);
676
    return -2;
677
678
679
680
  }

  if (options_transition_allowed(*options, trial_options) < 0) {
    options_free(trial_options);
681
    return -3;
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
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
  }

  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) {
726
    c = tor_malloc_zero(sizeof(struct config_line_t));
727
728
729
730
731
732
733
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

734
735
/** Set <b>options</b>-&gt;DirServers to contain the default directory 
 * servers. */
736
static void
737
add_default_trusted_dirservers(or_options_t *options)
738
{
Nick Mathewson's avatar
Nick Mathewson committed
739
  /* moria1 */
740
741
  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
742
  /* moria2 */
743
744
  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
745
  /* tor26 */
746
747
  options->DirServers = config_line_prepend(options->DirServers, "DirServer",
     "62.116.124.106:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
748
749
}

Nick Mathewson's avatar
Nick Mathewson committed
750
/** Print a usage message for tor. */
751
752
753
static void
print_usage(void)
{
754
  printf("tor -f <torrc> [args]\n"
755
756
         "See man page for more options. This -h is obsolete.\n");
#if 0
757
         "-b <bandwidth>\t\tbytes/second rate limiting\n"
758
         "-d <file>\t\tDebug file\n"
759
760
761
762
         "-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"
763
         "-s <IP>\t\t\tPort to bind to for Socks\n");
764
765
  printf("\nServer options:\n"
         "-n <nick>\t\tNickname of router\n"
766
         "-o <port>\t\tOR port to bind to\n"
767
         "-p <file>\t\tPID file\n");
768
#endif
769
770
}

Nick Mathewson's avatar
Nick Mathewson committed
771
/**
772
773
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
774
 */
775
776
777
int
resolve_my_address(const char *address, uint32_t *addr)
{
778
779
  struct in_addr in;
  struct hostent *rent;
780
  char hostname[256];
781
  int explicit_ip=1;
782

783
784
  tor_assert(addr);

785
786
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
787
  } else { /* then we need to guess our address */
788
    explicit_ip = 0; /* it's implicit */
789

790
    if (gethostname(hostname, sizeof(hostname)) < 0) {
791
792
793
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
794
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
795
796
  }

797
  /* now we know hostname. resolve it and keep only the IP */
798

799
  if (tor_inet_aton(hostname, &in) == 0) {
800
801
    /* then we have to resolve it */
    explicit_ip = 0;
802
    rent = (struct hostent *)gethostbyname(hostname);
803
    if (!rent) {
804
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
805
806
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
807
    tor_assert(rent->h_length == 4);
808
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
809
  }
810
811

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
812
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
813
           "Please set the Address config option to be the IP you want to use.",
814
           hostname, inet_ntoa(in));
815
816
    return -1;
  }
817
818

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
819
  *addr = ntohl(in.s_addr);
820
821
822
  return 0;
}

823
824
/** Called when we don't have a nickname set.  Try to guess a good
 * nickname based on the hostname, and return it. */
825
826
static char *
get_default_nickname(void)
827
828
829
830
{
  char localhostname[256];
  char *cp, *out, *outp;

831
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
832
833
834
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
835

836
  /* Put it in lowercase; stop at the first dot. */
837
  for (cp = localhostname; *cp; ++cp) {
838
839
840
841
842
843
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
844

845
846
  /* Strip invalid characters. */
  cp = localhostname;
847
  out = outp = tor_malloc(strlen(localhostname) + 1);
848
849
850
851
852
853
854
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
855

856
857
858
859
860
861
862
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
863
/** Release storage held by <b>options</b> */
864
static void
865
options_free(or_options_t *options)
866
{
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
  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:
882
      case CONFIG_TYPE_LINELIST_V:
883
884
885
886
887
888
889
890
891
892
        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;
893
894
895
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
896
897
898
    }
  }
  /* XXX this last part is an exception. can we make it not needed? */
899
  if (options->RedirectExitList) {
Nick Mathewson's avatar
Nick Mathewson committed
900
901
    SMARTLIST_FOREACH(options->RedirectExitList,
                      exit_redirect_t *, p, tor_free(p));
Roger Dingledine's avatar
Roger Dingledine committed
902
    smartlist_free(options->RedirectExitList);
903
    options->RedirectExitList = NULL;
904
  }
905
}
906

907
908
909
/** 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)
910
{
911
912
913
  or_options_t *new;
  int i;
  struct config_line_t *line;
914

915
916
917
918
919
920
921
922
  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);
923
      }
924
925
    }
    config_free_lines(line);
926
  }
927
  return new;
928
929
}

930
931
/** Set <b>options</b> to hold reasonable defaults for most options.
 * Each option defaults to zero. */
932
933
void
options_init(or_options_t *options)
934
{
935
936
937
938
939
940
941
  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 */
942
    option_reset(options, var);
943
  }
944
945
}

946
947
948
/** 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
949
static int
950
options_validate(or_options_t *options)
Roger Dingledine's avatar
Roger Dingledine committed
951
952
953
954
{
  int i;
  int result = 0;
  struct config_line_t *cl;
955

956
957
  if (options->ORPort < 0 || options->ORPort > 65535) {
    log(LOG_WARN, "ORPort option out of bounds.");
958
959
960
    result = -1;
  }

961
962
963
964
965
  if (validate_data_directory(options)<0) {
    log(LOG_WARN, "Invalid DataDirectory");
    result = -1;
  }

966
  if (options->Nickname == NULL) {
967
    if (server_mode(options)) {
968
969
970
971
      if (!(options->Nickname = get_default_nickname()))
        return -1;
      log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
    }
972
973
974
975
976
977
  } else {
    if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
        strlen(options->Nickname)) {
      log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
      result = -1;
    }
978
979
980
981
    if (strlen(options->Nickname) == 0) {
      log_fn(LOG_WARN, "Nickname must have at least one character");
      result = -1;
    }
982
983
984
985
    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;
986
    }
987
988
  }

989
990
991
992
993
994
995
996
  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");
  }

997
  if (server_mode(options)) {
998
999
    /* confirm that our address isn't broken, so we can complain now */
    uint32_t tmp;
1000
    if (resolve_my_address(options->Address, &tmp) < 0)