config.c 57.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
  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);
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
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. */
  if (config_init_logs(options)<0) /* Configure the log(s) */
261
262
263
264
    return -1;
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
265
  add_callback_log(LOG_NOTICE, LOG_ERR, control_event_logmsg);
266
267
268

  /* Start backgrounding the process, if requested. */
  if (options->RunAsDaemon) {
269
    start_daemon(options->DataDirectory);
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
  }

  /* 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;
295
296
297
298
299
300
}

/*
 * Functions to parse config options
 */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

540
  option_reset(options, var);
541
542
}

543
544
545
546
547
548
549
550
/** 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);
}

551
552
553
554
555
556
557
558
559
/** 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;
560
  tor_assert(options && key);
561
562
563
564
565

  var = config_find_option(key);
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
566
567
568
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
569
570
571
  }
  value = ((char*)options) + var->var_offset;

572
573
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
574
    /* Linelist requires special handling: we just copy and return it. */
Roger Dingledine's avatar
Roger Dingledine committed
575
    const struct config_line_t *next_in = *(const struct config_line_t**)value;
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
    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:
593
594
595
596
597
598
599
      if (*(char**)value) {
        result->value = tor_strdup(*(char**)value);
      } else {
        tor_free(result->key);
        tor_free(result);
        return NULL;
      }
600
601
      break;
    case CONFIG_TYPE_UINT:
602
603
      /* XXX This means every or_options_t uint or bool element
       * needs to be an int. Not, say, a uint16_t or char. */
604
605
606
607
608
609
610
611
612
613
614
      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
615
616
      if (*(smartlist_t**)value)
        result->value = smartlist_join_strings(*(smartlist_t**)value,",",0,NULL);
617
618
619
      else
        result->value = tor_strdup("");
      break;
620
621
622
623
624
    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;
625
626
627
    default:
      tor_free(result->key);
      tor_free(result);
628
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
629
630
631
632
633
634
      return NULL;
    }

  return result;
}

635
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
636
 * For each item, convert as appropriate and assign to <b>options</b>.
637
 * If an item is unrecognized, return -1 immediately,
638
639
640
641
 * 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
642
643
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
644
 */
645
static int
646
config_assign(or_options_t *options, struct config_line_t *list, int reset)
647
{
648
  struct config_line_t *p;
649
  tor_assert(options);
650
651
652
653
654
655
656

  /* 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);
657
    }
658
659
  }

660
  /* pass 2: if we're reading from a resetting source, clear all mentioned
661
662
663
664
665
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
666

667
668
  /* pass 3: assign. */
  while (list) {
669
670
671
    int r;
    if ((r=config_assign_line(options, list, reset)))
      return r;
672
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
673
  }
674
  return 0;
675
676
}

677
/** Try assigning <b>list</b> to the global options. You do this by duping
678
679
 * 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,
680
681
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
682
683
 */
int
684
config_trial_assign(struct config_line_t *list, int reset)
685
{
686
  int r;
687
  or_options_t *trial_options = options_dup(get_options());
688

689
  if ((r=config_assign(trial_options, list, reset)) < 0) {
690
    options_free(trial_options);
691
    return r;
692
693
694
695
  }

  if (options_validate(trial_options) < 0) {
    options_free(trial_options);
696
    return -2;
697
698
  }

699
  if (options_transition_allowed(get_options(), trial_options) < 0) {
700
    options_free(trial_options);
701
    return -3;
702
703
  }

704
  set_options(trial_options); /* we liked it. put it in place. */
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
  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) {
747
    c = tor_malloc_zero(sizeof(struct config_line_t));
748
749
750
751
752
753
754
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

755
756
/** Set <b>options</b>-&gt;DirServers to contain the default directory 
 * servers. */
757
static void
758
add_default_trusted_dirservers(or_options_t *options)
759
{
Nick Mathewson's avatar
Nick Mathewson committed
760
  /* moria1 */
761
762
  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
763
  /* moria2 */
764
765
  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
766
  /* tor26 */
767
768
  options->DirServers = config_line_prepend(options->DirServers, "DirServer",
     "62.116.124.106:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
769
770
}

Nick Mathewson's avatar
Nick Mathewson committed
771
/** Print a usage message for tor. */
772
773
774
static void
print_usage(void)
{
775
  printf("tor -f <torrc> [args]\n"
776
777
         "See man page for more options. This -h is obsolete.\n");
#if 0
778
         "-b <bandwidth>\t\tbytes/second rate limiting\n"
779
         "-d <file>\t\tDebug file\n"
780
781
782
783
         "-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"
784
         "-s <IP>\t\t\tPort to bind to for Socks\n");
785
786
  printf("\nServer options:\n"
         "-n <nick>\t\tNickname of router\n"
787
         "-o <port>\t\tOR port to bind to\n"
788
         "-p <file>\t\tPID file\n");
789
#endif
790
791
}

Nick Mathewson's avatar
Nick Mathewson committed
792
/**
793
794
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
795
 */
796
797
798
int
resolve_my_address(const char *address, uint32_t *addr)
{
799
800
  struct in_addr in;
  struct hostent *rent;
801
  char hostname[256];
802
  int explicit_ip=1;
803

804
805
  tor_assert(addr);

806
807
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
808
  } else { /* then we need to guess our address */
809
    explicit_ip = 0; /* it's implicit */
810

811
    if (gethostname(hostname, sizeof(hostname)) < 0) {
812
813
814
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
815
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
816
817
  }

818
  /* now we know hostname. resolve it and keep only the IP */
819

820
  if (tor_inet_aton(hostname, &in) == 0) {
821
822
    /* then we have to resolve it */
    explicit_ip = 0;
823
    rent = (struct hostent *)gethostbyname(hostname);
824
    if (!rent) {
825
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
826
827
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
828
    tor_assert(rent->h_length == 4);
829
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
830
  }
831
832

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
833
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
834
           "Please set the Address config option to be the IP you want to use.",
835
           hostname, inet_ntoa(in));
836
837
    return -1;
  }
838
839

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
840
  *addr = ntohl(in.s_addr);
841
842
843
  return 0;
}

844
845
/** Called when we don't have a nickname set.  Try to guess a good
 * nickname based on the hostname, and return it. */
846
847
static char *
get_default_nickname(void)
848
849
850
851
{
  char localhostname[256];
  char *cp, *out, *outp;

852
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
853
854
855
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
856

857
  /* Put it in lowercase; stop at the first dot. */
858
  for (cp = localhostname; *cp; ++cp) {
859
860
861
862
863
864
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
865

866
867
  /* Strip invalid characters. */
  cp = localhostname;
868
  out = outp = tor_malloc(strlen(localhostname) + 1);
869
870
871
872
873
874
875
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
876

877
878
879
880
881
882
883
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
884
/** Release storage held by <b>options</b> */
885
static void
886
options_free(or_options_t *options)
887
{
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
  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:
903
      case CONFIG_TYPE_LINELIST_V:
904
905
906
907
908
909
910
911
912
913
        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;
914
915
916
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
917
918
919
    }
  }
  /* XXX this last part is an exception. can we make it not needed? */
920
  if (options->RedirectExitList) {
Nick Mathewson's avatar
Nick Mathewson committed
921
922
    SMARTLIST_FOREACH(options->RedirectExitList,
                      exit_redirect_t *, p, tor_free(p));
Roger Dingledine's avatar
Roger Dingledine committed
923
    smartlist_free(options->RedirectExitList);
924
    options->RedirectExitList = NULL;
925
  }
926
}
927

928
929
930
/** 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)
931
{
Roger Dingledine's avatar
Roger Dingledine committed
932
  or_options_t *newopts;
933
934
  int i;
  struct config_line_t *line;
935

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

955
956
/** Set <b>options</b> to hold reasonable defaults for most options.
 * Each option defaults to zero. */
957
958
void
options_init(or_options_t *options)
959
{
960
961
962
963
964
965
966
  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 */
967
    option_reset(options, var);
968
  }
969
970
}

971
972
973
/** 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
974
static int
975
options_validate(or_options_t *options)
Roger Dingledine's avatar
Roger Dingledine committed
976
977
978
979
{
  int i;
  int result = 0;
  struct config_line_t *cl;
980

981
982
  if (options->ORPort < 0 || options->ORPort > 65535) {
    log(LOG_WARN, "ORPort option out of bounds.");
983
984
985
    result = -1;
  }

986
987
988
989
990
  if (validate_data_directory(options)<0) {
    log(LOG_WARN, "Invalid DataDirectory");
    result = -1;
  }

991
  if (options->Nickname == NULL) {
992
    if (server_mode(options)) {
993
994
995
996
      if (!(options->Nickname = get_default_nickname()))
        return -1;
      log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
    }
997
998
999
1000
  } else {
    if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
        strlen(options->Nickname)) {
      log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);