config.c 65.3 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
  { "DirFetchPostPeriod", "DirFetchPeriod", 0},
61
  { NULL, NULL , 0},
62
};
63
#undef PLURAL
64

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

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

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

Nick Mathewson's avatar
Nick Mathewson committed
162
/** Largest allowed config line */
163
#define CONFIG_LINE_T_MAXLEN 4096
164

165
166
static void option_reset(or_options_t *options, config_var_t *var);
static void options_free(or_options_t *options);
167
static int option_is_same(or_options_t *o1, or_options_t *o2,const char *name);
168
169
170
171
172
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);

173
static int parse_dir_server_line(const char *line, int validate_only);
174
static int parse_redirect_line(smartlist_t *result,
Roger Dingledine's avatar
Roger Dingledine committed
175
                               struct config_line_t *line);
176
177
178
179
180
181
182
183
184
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);
185
static int validate_data_directory(or_options_t *options);
186
static int write_configuration_file(const char *fname, or_options_t *options);
187

188
189
190
191
192
193
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
static or_options_t *global_options=NULL;
Roger Dingledine's avatar
Roger Dingledine committed
194
/** Name of most recently read torrc file. */
195
static char *config_fname = NULL;
196

197
198
199
/** Return the currently configured options. */
or_options_t *
get_options(void) {
200
201
202
  tor_assert(global_options);
  return global_options;
}
203

Roger Dingledine's avatar
Roger Dingledine committed
204
205
206
/** 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
207
208
209
210
211
212
213
214
215
216
217
218
219
 * 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;
220
221
222
223
224
225
226
227
228
229
}

/** 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();
230
231

  clear_trusted_dir_servers();
232
  for (cl = options->DirServers; cl; cl = cl->next) {
233
234
235
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
             "Previously validated DirServer line could not be added!");
236
      return -1;
237
238
239
    }
  }

240
  if (rend_config_services(options, 0)<0) {
241
242
    log_fn(LOG_ERR,
           "Previously validated hidden services line could not be added!");
243
    return -1;
244
  }
245
246
247
248
249
250
251
252
253

  /* 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. */
254
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
255
    log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
256
           options->DataDirectory);
257
258
259
260
261
262
263
264
    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;

265
  if (set_max_file_descriptors(options->MaxConn) < 0)
266
267
    return -1;

268
  mark_logs_temp(); /* Close current logs once new logs are open. */
269
  if (config_init_logs(options, 0)<0) /* Configure the log(s) */
270
271
272
273
    return -1;
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
274
  add_callback_log(LOG_NOTICE, LOG_ERR, control_event_logmsg);
275

276
277
278
279
280
281
282
283
284
  {
    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);
  }

285
  /* Start backgrounding the process, if requested. */
286

287
288
289
  /* 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 */
290
  if (options->RunAsDaemon) {
291
    start_daemon(options->DataDirectory);
292
293
294
295
  }

  /* Finish backgrounding the process */
  if(options->RunAsDaemon) {
296
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
297
298
299
300
301
302
303
304
    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);

305
306
307
308
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();

309
310
  init_cookie_authentication(options->CookieAuthentication);

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

317
  /* Set up accounting */
318
  if (accounting_is_enabled(options))
319
320
    configure_accounting(time(NULL));

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

326
327
328
329
330
331
#if 0
  {
    char *smin, *smax;
    smin = config_dump_options(options, 1);
    smax = config_dump_options(options, 0);
    log_fn(LOG_DEBUG, "These are our options:\n%s",smax);
Roger Dingledine's avatar
Roger Dingledine committed
332
    log_fn(LOG_DEBUG, "We changed these options:\n%s",smin);
333
334
335
336
337
    tor_free(smin);
    tor_free(smax);
  }
#endif

338
339
340
341
342
343
  /* Since our options changed, we might need to regenerate and upload our
   * server descriptor.  (We could probably be more clever about only calling
   * this when something significant changed.)
   */
  mark_my_descriptor_dirty();

344
  return 0;
345
346
347
348
349
350
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
351
/** If <b>option</b> is an official abbreviation for a longer option,
352
353
354
 * 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. */
355
static const char *
356
expand_abbrev(const char *option, int command_line)
357
358
359
360
{
  int i;
  for (i=0; config_abbrevs[i].abbreviated; ++i) {
    /* Abbreviations aren't casei. */
361
    if (!strcasecmp(option,config_abbrevs[i].abbreviated) &&
362
        (command_line || !config_abbrevs[i].commandline_only)) {
363
      return config_abbrevs[i].full;
364
    }
365
366
367
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
368

Nick Mathewson's avatar
Nick Mathewson committed
369
/** Helper: Read a list of configuration options from the command line. */
370
371
372
static struct config_line_t *
config_get_commandlines(int argc, char **argv)
{
373
374
  struct config_line_t *new;
  struct config_line_t *front = NULL;
375
376
377
  char *s;
  int i = 1;

378
  while (i < argc-1) {
379
380
381
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
382
      continue;
383
384
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
385
      continue;
386
387
    }

388
    new = tor_malloc(sizeof(struct config_line_t));
389
    s = argv[i];
390

391
392
    while(*s == '-')
      s++;
393

394
    new->key = tor_strdup(expand_abbrev(s, 1));
395
    new->value = tor_strdup(argv[i+1]);
396
397

    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
398
        new->key, new->value);
399
400
401
402
403
404
405
    new->next = front;
    front = new;
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
406
407
/** Helper: allocate a new configuration option mapping 'key' to 'val',
 * prepend it to 'front', and return the newly allocated config_line_t */
408
struct config_line_t *
409
410
411
412
413
config_line_prepend(struct config_line_t *front,
                    const char *key,
                    const char *val)
{
  struct config_line_t *newline;
414

415
416
417
418
419
420
421
  newline = tor_malloc(sizeof(struct config_line_t));
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
  newline->next = front;
  return newline;
}

422
423
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
424
425
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
426
427
int
config_get_lines(char *string, struct config_line_t **result)
428
{
429
430
  struct config_line_t *list = NULL;
  char *k, *v;
431

432
433
434
435
436
437
438
439
440
  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);
441

442
  *result = list;
443
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
444
445
}

Nick Mathewson's avatar
Nick Mathewson committed
446
447
448
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
449
void
450
451
config_free_lines(struct config_line_t *front)
{
452
  struct config_line_t *tmp;
453

454
  while (front) {
455
456
457
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
458
459
460
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
461
462
463
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
464
465
466
467
/** 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.
 */
468
469
470
static config_var_t *config_find_option(const char *key)
{
  int i;
Nick Mathewson's avatar
Nick Mathewson committed
471
  /* First, check for an exact (case-insensitive) match */
472
  for (i=0; config_vars[i].name; ++i) {
Nick Mathewson's avatar
Nick Mathewson committed
473
    if (!strcasecmp(key, config_vars[i].name))
474
      return &config_vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
475
476
477
478
  }
  /* If none, check for an abbreviated match */
  for (i=0; config_vars[i].name; ++i) {
    if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
479
480
481
482
483
484
      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
485
  /* Okay, unrecogized options */
486
487
488
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
489
/** If <b>c</b> is a syntactically valid configuration line, update
490
491
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
492
493
494
495
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
496
static int
497
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
498
{
499
  int i, ok;
500
501
  config_var_t *var;
  void *lvalue;
502

503
504
505
506
507
508
509
  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)) {
510
    tor_free(c->key);
511
    c->key = tor_strdup(var->name);
512
513
  }

514
  if (reset && !strlen(c->value)) {
515
    option_reset(options, var);
516
517
518
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
519
  lvalue = ((char*)options) + var->var_offset;
520
  switch(var->type) {
521

522
523
524
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
525
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
526
          c->key,c->value);
527
      return -2;
528
    }
529
    *(int *)lvalue = i;
530
531
532
533
534
    break;

  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
535
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
536
      return -2;
537
    }
538
    *(int *)lvalue = i;
539
540
541
    break;

  case CONFIG_TYPE_STRING:
542
543
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
544
545
546
    break;

  case CONFIG_TYPE_DOUBLE:
547
    *(double *)lvalue = atof(c->value);
548
549
550
    break;

  case CONFIG_TYPE_CSV:
551
552
    if (*(smartlist_t**)lvalue == NULL)
      *(smartlist_t**)lvalue = smartlist_create();
553

554
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
555
556
557
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

558
559
560
561
562
563
564
565
  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;
566
567
568
569

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
570
571
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
572
    return -2;
573
574
575
  default:
    tor_assert(0);
    break;
576
  }
577
  return 0;
578
579
}

580
581
582
583
584
585
586
587
588
589
/** 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. */

590
  option_reset(options, var);
591
592
}

593
594
595
596
597
598
599
600
/** 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);
}

601
602
603
604
605
606
607
608
609
/** 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;
610
  tor_assert(options && key);
611
612
613
614
615

  var = config_find_option(key);
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
616
617
618
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
619
620
621
  }
  value = ((char*)options) + var->var_offset;

622
623
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
624
    /* Linelist requires special handling: we just copy and return it. */
Roger Dingledine's avatar
Roger Dingledine committed
625
    const struct config_line_t *next_in = *(const struct config_line_t**)value;
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
    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:
643
644
645
646
647
648
649
      if (*(char**)value) {
        result->value = tor_strdup(*(char**)value);
      } else {
        tor_free(result->key);
        tor_free(result);
        return NULL;
      }
650
651
      break;
    case CONFIG_TYPE_UINT:
652
      /* This means every or_options_t uint or bool element
653
       * needs to be an int. Not, say, a uint16_t or char. */
654
655
656
657
658
659
660
661
662
663
664
      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
665
666
      if (*(smartlist_t**)value)
        result->value = smartlist_join_strings(*(smartlist_t**)value,",",0,NULL);
667
668
669
      else
        result->value = tor_strdup("");
      break;
670
671
672
673
674
    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;
675
676
677
    default:
      tor_free(result->key);
      tor_free(result);
678
      log_fn(LOG_WARN,"Bug: unknown type %d for known key %s", var->type, key);
679
680
681
682
683
684
      return NULL;
    }

  return result;
}

685
/** Iterate through the linked list of requested options <b>list</b>.
Nick Mathewson's avatar
Nick Mathewson committed
686
 * For each item, convert as appropriate and assign to <b>options</b>.
687
 * If an item is unrecognized, return -1 immediately,
688
689
690
691
 * 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
692
693
 * extending) their previous values.  Return 0 on success, -1 on bad key,
 * -2 on bad value.
694
 */
695
static int
696
config_assign(or_options_t *options, struct config_line_t *list, int reset)
697
{
698
  struct config_line_t *p;
699
  tor_assert(options);
700
701
702
703
704
705
706

  /* 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);
707
    }
708
709
  }

710
  /* pass 2: if we're reading from a resetting source, clear all mentioned
711
712
713
714
715
   * linelists. */
  if (reset) {
    for (p = list; p; p = p->next)
      config_reset_line(options, p->key);
  }
716

717
718
  /* pass 3: assign. */
  while (list) {
719
720
721
    int r;
    if ((r=config_assign_line(options, list, reset)))
      return r;
722
    list = list->next;
Roger Dingledine's avatar
Roger Dingledine committed
723
  }
724
  return 0;
725
726
}

727
/** Try assigning <b>list</b> to the global options. You do this by duping
728
 * options, assigning list to the new one, then validating it. If it's
729
 * ok, then throw out the old one and stick with the new one. Else,
730
731
 * revert to old and return failure.  Return 0 on success, -1 on bad
 * keys, -2 on bad values, -3 on bad transition.
732
733
 */
int
734
config_trial_assign(struct config_line_t *list, int reset)
735
{
736
  int r;
737
  or_options_t *trial_options = options_dup(get_options());
738

739
  if ((r=config_assign(trial_options, list, reset)) < 0) {
740
    options_free(trial_options);
741
    return r;
742
743
744
745
  }

  if (options_validate(trial_options) < 0) {
    options_free(trial_options);
746
    return -2;
747
748
  }

749
  if (options_transition_allowed(get_options(), trial_options) < 0) {
750
    options_free(trial_options);
751
    return -3;
752
753
  }

754
  set_options(trial_options); /* we liked it. put it in place. */
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  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) {
797
    c = tor_malloc_zero(sizeof(struct config_line_t));
798
799
800
801
802
803
804
    c->key = tor_strdup(var->name);
    c->value = tor_strdup(var->initvalue);
    config_assign_line(options,c,0);
    config_free_lines(c);
  }
}

805
/** Set <b>options</b>-&gt;DirServers to contain the default directory
806
 * servers. */
807
static void
808
add_default_trusted_dirservers(or_options_t *options)
809
{
Nick Mathewson's avatar
Nick Mathewson committed
810
  /* moria1 */
811
812
  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
813
  /* moria2 */
814
815
  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
816
  /* tor26 */
817
818
  options->DirServers = config_line_prepend(options->DirServers, "DirServer",
     "62.116.124.106:9030 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
819
820
}

Nick Mathewson's avatar
Nick Mathewson committed
821
/** Print a usage message for tor. */
822
823
824
static void
print_usage(void)
{
825
826
827
828
  printf(
"Copyright 2001-2004 Roger Dingledine, Nick Mathewson, Matej Pfajfar.\n\n"
"tor -f <torrc> [args]\n"
"See man page for options, or http://freehaven.net/tor/ for documentation.\n");
829
830
}

Nick Mathewson's avatar
Nick Mathewson committed
831
/**
832
833
 * Based on <b>address</b>, guess our public IP address and put it
 * in <b>addr</b>.
Nick Mathewson's avatar
Nick Mathewson committed
834
 */
835
836
837
int
resolve_my_address(const char *address, uint32_t *addr)
{
838
839
  struct in_addr in;
  struct hostent *rent;
840
  char hostname[256];
841
  int explicit_ip=1;
842

843
844
  tor_assert(addr);

845
846
  if (address) {
    strlcpy(hostname, address, sizeof(hostname));
847
  } else { /* then we need to guess our address */
848
    explicit_ip = 0; /* it's implicit */
849

850
    if (gethostname(hostname, sizeof(hostname)) < 0) {
851
852
853
      log_fn(LOG_WARN,"Error obtaining local hostname");
      return -1;
    }
854
    log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
855
856
  }

857
  /* now we know hostname. resolve it and keep only the IP */
858

859
  if (tor_inet_aton(hostname, &in) == 0) {
860
861
    /* then we have to resolve it */
    explicit_ip = 0;
862
    rent = (struct hostent *)gethostbyname(hostname);
863
    if (!rent) {
864
      log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
865
866
      return -1;
    }
Roger Dingledine's avatar
Roger Dingledine committed
867
    tor_assert(rent->h_length == 4);
868
    memcpy(&in.s_addr, rent->h_addr, rent->h_length);
869
  }
870
871

  if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
872
    log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
873
           "Please set the Address config option to be the IP you want to use.",
874
           hostname, inet_ntoa(in));
875
876
    return -1;
  }
877
878

  log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
879
  *addr = ntohl(in.s_addr);
880
881
882
  return 0;
}

883
884
/** Called when we don't have a nickname set.  Try to guess a good
 * nickname based on the hostname, and return it. */
885
886
static char *
get_default_nickname(void)
887
888
889
890
{
  char localhostname[256];
  char *cp, *out, *outp;

891
  if (gethostname(localhostname, sizeof(localhostname)) < 0) {
892
893
894
    log_fn(LOG_WARN,"Error obtaining local hostname");
    return NULL;
  }
895

896
  /* Put it in lowercase; stop at the first dot. */
897
  for (cp = localhostname; *cp; ++cp) {
898
899
900
901
902
903
    if (*cp == '.') {
      *cp = '\0';
      break;
    }
    *cp = tolower(*cp);
  }
904

905
906
  /* Strip invalid characters. */
  cp = localhostname;
907
  out = outp = tor_malloc(strlen(localhostname) + 1);
908
909
910
911
912
913
914
  while (*cp) {
    if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
      *outp++ = *cp++;
    else
      cp++;
  }
  *outp = '\0';
915

916
917
918
919
920
921
922
  /* Enforce length. */
  if (strlen(out) > MAX_NICKNAME_LEN)
    out[MAX_NICKNAME_LEN]='\0';

  return out;
}

Nick Mathewson's avatar
Nick Mathewson committed
923
/** Release storage held by <b>options</b> */
924
static void
925
options_free(or_options_t *options)
926
{
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
  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:
942
      case CONFIG_TYPE_LINELIST_V:
943
944
945
946
947
948
949
950
951
952
        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;
953
954
955
      case CONFIG_TYPE_LINELIST_S:
        /* will be freed by corresponding LINELIST_V. */
        break;
956
957
    }
  }
958
}
959

960
961
962
963
/** Return true iff the option <b>var</b> has the same value in <b>o1</b>
 * and <b>o2</b>.  Must not be called for LINELIST_S or OBSOLETE options.
 */
static int
964
option_is_same(or_options_t *o1, or_options_t *o2, const char *name)
965
{
966
967
968
969
970
971
972
973
974
  struct config_line_t *c1, *c2;
  int r = 1;
  c1 = config_get_assigned_option(o1, name);
  c2 = config_get_assigned_option(o2, name);
  while (c1 && c2) {
    if (strcasecmp(c1->key, c2->key) ||
        strcmp(c1->value, c2->value)) {
      r = 0;
      break;
975
    }
976
977
978
979
980
981
982
983
984
    c1 = c1->next;
    c2 = c2->next;
  }
  if (r && (c1 || c2)) {
    r = 0;
  }
  config_free_lines(c1);
  config_free_lines(c2);
  return r;
985
986
}

987
988
989
/** 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)
990
{
Roger Dingledine's avatar
Roger Dingledine committed
991
  or_options_t *newopts;
992
993
  int i;
  struct config_line_t *line;
994

Roger Dingledine's avatar
Roger Dingledine committed
995
  newopts = tor_malloc_zero(sizeof(or_options_t));
996
  for (i=0; config_vars[i].name; ++i) {
997
998
999
1000
    if(config_vars[i].type == CONFIG_TYPE_LINELIST_S)
      continue;
    if(config_vars[i].type == CONFIG_TYPE_OBSOLETE)
      continue;
For faster browsing, not all history is shown. View entire blame