config.c 58.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
  PLURAL(ExitNode),
50
  PLURAL(EntryNode),
51
52
53
54
55
56
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
  PLURAL(RendNode),
  PLURAL(RendExcludeNode),
57
  { "l", "Log", 1},
58
59
  { "BandwidthRate", "BandwidthRateBytes", 0},
  { "BandwidthBurst", "BandwidthBurstBytes", 0},
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);
168
static int parse_redirect_line(smartlist_t *result,
Roger Dingledine's avatar
Roger Dingledine committed
169
                               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
static int validate_data_directory(or_options_t *options);
180

181
182
183
184
185
186
187
/*
 * Functions to read and write the global options pointer.
 */

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

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

Roger Dingledine's avatar
Roger Dingledine committed
195
196
197
/** 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
198
199
200
201
202
203
204
205
206
207
208
209
210
 * 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;
211
212
213
214
215
216
217
218
219
220
}

/** 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();
221
222

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

231
  if (rend_config_services(options, 0)<0) {
232
233
    log_fn(LOG_ERR,
           "Previously validated hidden services line could not be added!");
234
    return -1;
235
  }
236
237
238
239
240
241
242
243
244

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

  /* Ensure data directory is private; create if possible. */
245
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
246
    log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
247
           options->DataDirectory);
248
249
250
251
252
253
254
255
    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;

256
  if (set_max_file_descriptors(options->MaxConn) < 0)
257
258
    return -1;

259

260
  mark_logs_temp(); /* Close current logs once new logs are open. */
261
  if (config_init_logs(options, 0)<0) /* Configure the log(s) */
262
263
264
265
    return -1;
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
266
  add_callback_log(LOG_NOTICE, LOG_ERR, control_event_logmsg);
267

268
269
270
271
272
273
274
275
276
  {
    smartlist_t *sl = smartlist_create();
    for (cl = options->RedirectExit; cl; cl = cl->next) {
      if (parse_redirect_line(sl, cl)<0)
        return -1;
    }
    set_exit_redirects(sl);
  }

277
  /* Start backgrounding the process, if requested. */
278

279
280
281
  /* XXXX009 We once had a reason to separate start_daemon and finish_daemon:
   *    It let us have the parent process stick around until we were sure Tor
   *    was started.  Should we make start_daemon get called earlier? -NM */
282
  if (options->RunAsDaemon) {
283
    start_daemon(options->DataDirectory);
284
285
286
287
  }

  /* Finish backgrounding the process */
  if(options->RunAsDaemon) {
288
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    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;
309
310
311
312
313
314
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
315
/** If <b>option</b> is an official abbreviation for a longer option,
316
317
318
 * 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. */
319
static const char *
320
expand_abbrev(const char *option, int command_line)
321
322
323
324
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
325
    if (!strcasecmp(option,config_abbrevs[i].abbreviated) &&
326
        (command_line || !config_abbrevs[i].commandline_only)) {
327
      return config_abbrevs[i].full;
328
    }
329
330
331
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
332

Nick Mathewson's avatar
Nick Mathewson committed
333
/** Helper: Read a list of configuration options from the command line. */
334
335
336
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
337
338
  struct config_line_t *new;
  struct config_line_t *front = NULL;
339
340
341
  char *s;
  int i = 1;

342
  while (i < argc-1) {
343
344
345
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
346
      continue;
347
348
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
349
      continue;
350
351
    }

352
    new = tor_malloc(sizeof(struct config_line_t));
353
    s = argv[i];
354

355
356
    while(*s == '-')
      s++;
357

358
    new->key = tor_strdup(expand_abbrev(s, 1));
359
    new->value = tor_strdup(argv[i+1]);
360
361

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
362
        new->key, new->value);
363
364
365
366
367
368
369
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
370
371
/** Helper: allocate a new configuration option mapping 'key' to 'val',
 * prepend it to 'front', and return the newly allocated config_line_t */
372
struct config_line_t *
373
374
375
376
377
config_line_prepend(struct config_line_t *front,
                    const char *key,
                    const char *val)
{
  struct config_line_t *newline;
378

379
380
381
382
383
384
385
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
  newline->next = front;
  return newline;
}

386
387
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
388
389
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
390
391
int
config_get_lines(char *string, struct config_line_t **result)
392
{
393
394
  struct config_line_t *list = NULL;
  char *k, *v;
395

396
397
398
399
400
401
402
403
404
  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);
405

406
  *result = list;
407
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
408
409
}

Nick Mathewson's avatar
Nick Mathewson committed
410
411
412
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
413
void
414
415
config_free_lines(struct config_line_t *front)
{
416
  struct config_line_t *tmp;
417

418
  while (front) {
419
420
421
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
422
423
424
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
425
426
427
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
428
429
430
431
/** 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.
 */
432
433
434
static config_var_t *config_find_option(const char *key)
{
  int i;
Nick Mathewson's avatar
Nick Mathewson committed
435
  /* First, check for an exact (case-insensitive) match */
436
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
437
    if (!strcasecmp(key, config_vars[i].name))
438
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
439
440
441
442
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
    if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
443
444
445
446
447
448
      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
449
  /* Okay, unrecogized options */
450
451
452
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
453
/** If <b>c</b> is a syntactically valid configuration line, update
454
455
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
456
457
458
459
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
460
static int
461
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
462
{
463
  int i, ok;
464
465
  config_var_t *var;
  void *lvalue;
466

467
468
469
470
471
472
473
  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)) {
474
    tor_free(c->key);
475
    c->key = tor_strdup(var->name);
476
477
  }

478
  if (reset && !strlen(c->value)) {
479
    option_reset(options, var);
480
481
482
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
483
  lvalue = ((char*)options) + var->var_offset;
484
  switch(var->type) {
485

486
487
488
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
489
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
490
          c->key,c->value);
491
      return -2;
492
    }
493
    *(int *)lvalue = i;
494
495
496
497
498
    break;

  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
499
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
500
      return -2;
501
    }
502
    *(int *)lvalue = i;
503
504
505
    break;

  case CONFIG_TYPE_STRING:
506
507
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
508
509
510
    break;

  case CONFIG_TYPE_DOUBLE:
511
    *(double *)lvalue = atof(c->value);
512
513
514
    break;

  case CONFIG_TYPE_CSV:
515
516
    if (*(smartlist_t**)lvalue == NULL)
      *(smartlist_t**)lvalue = smartlist_create();
517

518
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
519
520
521
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

522
523
524
525
526
527
528
529
  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;
530
531
532
533

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
534
535
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
536
    return -2;
537
538
539
  default:
    tor_assert(0);
    break;
540
  }
541
  return 0;
542
543
}

544
545
546
547
548
549
550
551
552
553
/** 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. */

554
  option_reset(options, var);
555
556
}

557
558
559
560
561
562
563
564
/** Return true iff key is a valid configuration option. */
int
config_option_is_recognized(const char *key)
{
  config_var_t *var = config_find_option(key);
  return (var != NULL);
}

565
566
567
568
569
570
571
572
573
/** 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;
574
  tor_assert(options && key);
575
576
577
578
579

  var = config_find_option(key);
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
580
581
582
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
583
584
585
  }
  value = ((char*)options) + var->var_offset;

586
587
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
588
    /* Linelist requires special handling: we just copy and return it. */
Roger Dingledine's avatar
Roger Dingledine committed
589
    const struct config_line_t *next_in = *(const struct config_line_t**)value;
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
    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:
607
608
609
610
611
612
613
      if (*(char**)value) {
        result->value = tor_strdup(*(char**)value);
      } else {
        tor_free(result->key);
        tor_free(result);
        return NULL;
      }
614
615
      break;
    case CONFIG_TYPE_UINT:
616
      /* This means every or_options_t uint or bool element
617
       * needs to be an int. Not, say, a uint16_t or char. */
618
619
620
621
622
623
624
625
626
627
628
      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:
Roger Dingledine's avatar
Roger Dingledine committed
629
630
      if (*(smartlist_t**)value)
        result->value = smartlist_join_strings(*(smartlist_t**)value,",",0,NULL);
631
632
633
      else
        result->value = tor_strdup("");
      break;
634
635
636
637
638
    case CONFIG_TYPE_OBSOLETE:
      log_fn(LOG_WARN,"You asked me for the value of an obsolete config option %s.", key);
      tor_free(result->key);
      tor_free(result);
      return NULL;
639
640
641
    default:
      tor_free(result->key);
      tor_free(result);
642
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
643
644
645
646
647
648
      return NULL;
    }

  return result;
}

649
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
650
 * For each item, convert as appropriate and assign to <b>options</b>.
651
 * If an item is unrecognized, return -1 immediately,
652
653
654
655
 * 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
656
657
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
658
 */
659
static int
660
config_assign(or_options_t *options, struct config_line_t *list, int reset)
661
{
662
  struct config_line_t *p;
663
  tor_assert(options);
664
665
666
667
668
669
670

  /* 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);
671
    }
672
673
  }

674
  /* pass 2: if we're reading from a resetting source, clear all mentioned
675
676
677
678
679
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
680

681
682
  /* pass 3: assign. */
  while (list) {
683
684
685
    int r;
    if ((r=config_assign_line(options, list, reset)))
      return r;
686
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
687
  }
688
  return 0;
689
690
}

691
/** Try assigning <b>list</b> to the global options. You do this by duping
692
 * options, assigning list to the new one, then validating it. If it's
693
 * ok, then throw out the old one and stick with the new one. Else,
694
695
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
696
697
 */
int
698
config_trial_assign(struct config_line_t *list, int reset)
699
{
700
  int r;
701
  or_options_t *trial_options = options_dup(get_options());
702

703
  if ((r=config_assign(trial_options, list, reset)) < 0) {
704
    options_free(trial_options);
705
    return r;
706
707
708
709
  }

  if (options_validate(trial_options) < 0) {
    options_free(trial_options);
710
    return -2;
711
712
  }

713
  if (options_transition_allowed(get_options(), trial_options) < 0) {
714
    options_free(trial_options);
715
    return -3;
716
717
  }

718
  set_options(trial_options); /* we liked it. put it in place. */
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
749
750
751
752
753
754
755
756
757
758
759
760
  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) {
761
    c = tor_malloc_zero(sizeof(struct config_line_t));
762
763
764
765
766
767
768
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

769
/** Set <b>options</b>-&gt;DirServers to contain the default directory
770
 * servers. */
771
static void
772
add_default_trusted_dirservers(or_options_t *options)
773
{
Nick Mathewson's avatar
Nick Mathewson committed
774
  /* moria1 */
775
776
  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
777
  /* moria2 */
778
779
  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
780
  /* tor26 */
781
782
  options->DirServers = config_line_prepend(options->DirServers, "DirServer",
     "62.116.124.106:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
783
784
}

Nick Mathewson's avatar
Nick Mathewson committed
785
/** Print a usage message for tor. */
786
787
788
static void
print_usage(void)
{
789
  printf("tor -f <torrc> [args]\n"
790
791
         "See man page for more options. This -h is obsolete.\n");
#if 0
792
         "-b <bandwidth>\t\tbytes/second rate limiting\n"
793
         "-d <file>\t\tDebug file\n"
794
795
796
797
         "-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"
798
         "-s <IP>\t\t\tPort to bind to for Socks\n");
799
800
  printf("\nServer options:\n"
         "-n <nick>\t\tNickname of router\n"
801
         "-o <port>\t\tOR port to bind to\n"
802
         "-p <file>\t\tPID file\n");
803
#endif
804
805
}

Nick Mathewson's avatar
Nick Mathewson committed
806
/**
807
808
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
809
 */
810
811
812
int
resolve_my_address(const char *address, uint32_t *addr)
{
813
814
  struct in_addr in;
  struct hostent *rent;
815
  char hostname[256];
816
  int explicit_ip=1;
817

818
819
  tor_assert(addr);

820
821
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
822
  } else { /* then we need to guess our address */
823
    explicit_ip = 0; /* it's implicit */
824

825
    if (gethostname(hostname, sizeof(hostname)) < 0) {
826
827
828
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
829
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
830
831
  }

832
  /* now we know hostname. resolve it and keep only the IP */
833

834
  if (tor_inet_aton(hostname, &in) == 0) {
835
836
    /* then we have to resolve it */
    explicit_ip = 0;
837
    rent = (struct hostent *)gethostbyname(hostname);
838
    if (!rent) {
839
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
840
841
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
842
    tor_assert(rent->h_length == 4);
843
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
844
  }
845
846

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
847
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
848
           "Please set the Address config option to be the IP you want to use.",
849
           hostname, inet_ntoa(in));
850
851
    return -1;
  }
852
853

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
854
  *addr = ntohl(in.s_addr);
855
856
857
  return 0;
}

858
859
/** Called when we don't have a nickname set.  Try to guess a good
 * nickname based on the hostname, and return it. */
860
861
static char *
get_default_nickname(void)
862
863
864
865
{
  char localhostname[256];
  char *cp, *out, *outp;

866
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
867
868
869
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
870

871
  /* Put it in lowercase; stop at the first dot. */
872
  for (cp = localhostname; *cp; ++cp) {
873
874
875
876
877
878
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
879

880
881
  /* Strip invalid characters. */
  cp = localhostname;
882
  out = outp = tor_malloc(strlen(localhostname) + 1);
883
884
885
886
887
888
889
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
890

891
892
893
894
895
896
897
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
898
/** Release storage held by <b>options</b> */
899
static void
900
options_free(or_options_t *options)
901
{
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  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:
917
      case CONFIG_TYPE_LINELIST_V:
918
919
920
921
922
923
924
925
926
927
        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;
928
929
930
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
931
932
    }
  }
933
}
934

935
936
937
/** 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)
938
{
Roger Dingledine's avatar
Roger Dingledine committed
939
  or_options_t *newopts;
940
941
  int i;
  struct config_line_t *line;
942

Roger Dingledine's avatar
Roger Dingledine committed
943
  newopts = tor_malloc_zero(sizeof(or_options_t));
944
  for (i=0; config_vars[i].name; ++i) {
945
946
947
948
    if(config_vars[i].type == CONFIG_TYPE_LINELIST_S)
      continue;
    if(config_vars[i].type == CONFIG_TYPE_OBSOLETE)
      continue;
949
950
    line = config_get_assigned_option(old, config_vars[i].name);
    if (line) {
Roger Dingledine's avatar
Roger Dingledine committed
951
      if (config_assign(newopts, line, 0) < 0) {
952
953
954
        log_fn(LOG_WARN,"Bug: config_get_assigned_option() generated "
               "something we couldn't config_assign().");
        tor_assert(0);
955
      }
956
957
    }
    config_free_lines(line);
958
  }
Roger Dingledine's avatar
Roger Dingledine committed
959
  return newopts;
960
961
}

962
963
/** Set <b>options</b> to hold reasonable defaults for most options.
 * Each option defaults to zero. */
964
965
void
options_init(or_options_t *options)
966
{
967
968
969
970
971
972
973
  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 */
974
    option_reset(options, var);
975
  }
976
977
}

978
979
980
/** 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
981
static int
982
options_validate(or_options_t *options)
Roger Dingledine's avatar
Roger Dingledine committed
983
984
985
986
{
  int i;
  int result = 0;
  struct config_line_t *cl;
987

988
989
  if (options->ORPort < 0 || options->ORPort > 65535) {
    log(LOG_WARN, "ORPort option out of bounds.");
990
991
992
    result = -1;
  }

993
994
995
996
997
  if (validate_data_directory(options)<0) {
    log(LOG_WARN, "Invalid DataDirectory");
    result = -1;
  }

998
  if (options->Nickname == NULL) {
999
    if (server_mode(options)) {
1000
      if (!(options->Nickname = get_default_nickname()))
For faster browsing, not all history is shown. View entire blame