config.c 56.2 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
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
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
296

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

/*
 * Functions to parse config options
 */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

542
  option_reset(options, var);
543
544
}

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

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

  return result;
}

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

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

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

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

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

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

  if (options_transition_allowed(*options, trial_options) < 0) {
    options_free(trial_options);
682
    return -3;
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
726
  }

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

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

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

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

784
785
  tor_assert(addr);

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

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

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

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

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

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

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

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

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

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

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

  return out;
}

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

908
909
910
/** 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)
911
{
Roger Dingledine's avatar
Roger Dingledine committed
912
  or_options_t *newopts;
913
914
  int i;
  struct config_line_t *line;
915

Roger Dingledine's avatar
Roger Dingledine committed
916
  newopts = tor_malloc_zero(sizeof(or_options_t));
917
918
919
  for (i=0; config_vars[i].name; ++i) {
    line = config_get_assigned_option(old, config_vars[i].name);
    if (line) {
Roger Dingledine's avatar
Roger Dingledine committed
920
      if (config_assign(newopts, line, 0) < 0) {
921
922
923
        log_fn(LOG_WARN,"Bug: config_get_assigned_option() generated "
               "something we couldn't config_assign().");
        tor_assert(0);
924
      }
925
926
    }
    config_free_lines(line);
927
  }
Roger Dingledine's avatar
Roger Dingledine committed
928
  return newopts;
929
930
}

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

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

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

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

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

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

998
  if (server_mode(options)) {
999
1000
    /* confirm that our address isn't broken, so we can complain now */
    uint32_t tmp;
For faster browsing, not all history is shown. View entire blame