config.c 93.6 KB
Newer Older
Roger Dingledine's avatar
Roger Dingledine committed
1
2
/* Copyright 2001 Matej Pfajfar.
 * Copyright 2001-2004 Roger Dingledine.
Nick Mathewson's avatar
Nick Mathewson committed
3
 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
4
5
/* See LICENSE for licensing information */
/* $Id$ */
6
const char config_c_id[] = "$Id$";
7

Nick Mathewson's avatar
Nick Mathewson committed
8
/**
9
10
 * \file config.c
 * \brief Code to parse and interpret configuration files.
Nick Mathewson's avatar
Nick Mathewson committed
11
12
 **/

Roger Dingledine's avatar
Roger Dingledine committed
13
#include "or.h"
14
15
16
#ifdef MS_WINDOWS
#include <shlobj.h>
#endif
17
#include "../common/aes.h"
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
  CONFIG_TYPE_STRING = 0,   /**< An arbitrary string. */
  CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
23
24
  CONFIG_TYPE_INTERVAL,     /**< A number of seconds, with optional units*/
  CONFIG_TYPE_MEMUNIT,      /**< A number of bytes, with optional units*/
25
26
  CONFIG_TYPE_DOUBLE,       /**< A floating-point value */
  CONFIG_TYPE_BOOL,         /**< A boolean value, expressed as 0 or 1. */
27
  CONFIG_TYPE_ISOTIME,      /**< An ISO-formated time relative to GMT. */
28
29
30
  CONFIG_TYPE_CSV,          /**< A list of strings, separated by commas and optional
                              * whitespace. */
  CONFIG_TYPE_LINELIST,     /**< Uninterpreted config lines */
31
32
33
34
35
  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.
                             */
36
  CONFIG_TYPE_OBSOLETE,     /**< Obsolete (ignored) option. */
Nick Mathewson's avatar
Nick Mathewson committed
37
} config_type_t;
38

Nick Mathewson's avatar
Nick Mathewson committed
39
/* An abbreviation for a configuration option allowed on the command line */
40
typedef struct config_abbrev_t {
41
42
  const char *abbreviated;
  const char *full;
43
  int commandline_only;
44
45
} config_abbrev_t;

46
47
48
49
/* 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
50
/* A list of command-line abbreviations. */
51
static config_abbrev_t _option_abbrevs[] = {
52
  PLURAL(ExitNode),
53
  PLURAL(EntryNode),
54
55
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
56
  PLURAL(LongLivedPort),
57
58
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
59
  PLURAL(NumCpu),
60
61
  PLURAL(RendNode),
  PLURAL(RendExcludeNode),
62
63
  PLURAL(StrictEntryNode),
  PLURAL(StrictExitNode),
64
  { "l", "Log", 1},
65
66
  { "BandwidthRateBytes", "BandwidthRate", 0},
  { "BandwidthBurstBytes", "BandwidthBurst", 0},
67
  { "DirFetchPostPeriod", "StatusFetchPeriod", 0},
68
  { "MaxConn", "ConnLimit", 0},
69
  { NULL, NULL , 0},
70
};
71
#undef PLURAL
72

73
/** A variable allowed in the configuration file or on the command line. */
74
typedef struct config_var_t {
75
76
77
78
  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. */
79
  const char *description;
80
81
} config_var_t;

Nick Mathewson's avatar
Nick Mathewson committed
82
/** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
Nick Mathewson's avatar
Nick Mathewson committed
83
#define STRUCT_OFFSET(tp, member) ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
Nick Mathewson's avatar
Nick Mathewson committed
84
85
86
87
/** 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>"
 */
88
#define VAR(name,conftype,member,initvalue)                            \
89
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member), initvalue }
Nick Mathewson's avatar
Nick Mathewson committed
90
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
91
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL }
92

Nick Mathewson's avatar
Nick Mathewson committed
93
94
95
96
/** Array of configuration options.  Until we disallow nonstandard
 * abbreviations, order is significant, since the first matching option will
 * be chosen first.
 */
97
static config_var_t _option_vars[] = {
98
  VAR("Address",             STRING,   Address,              NULL),
99
  VAR("AccountingStart",     STRING,   AccountingStart,      NULL),
100
  VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes, "middle,rendezvous"),
101
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
102
  VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "2 MB"),
103
  VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "5 MB"),
104
  VAR("MaxAdvertisedBandwidth",MEMUNIT,MaxAdvertisedBandwidth,"128 TB"),
105
106
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
107
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
108
  VAR("CookieAuthentication",BOOL,     CookieAuthentication, "0"),
109
110
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
111
  VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
112
113
  VAR("DirPort",             UINT,     DirPort,              "0"),
  VAR("DirBindAddress",      LINELIST, DirBindAddress,       NULL),
114
115
  /** DOCDOC **/
  VAR("DirFetchPeriod",      INTERVAL, DirFetchPeriod,       "0 seconds"),
116
117
  VAR("DirPostPeriod",       INTERVAL, DirPostPeriod,        "20 minutes"),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
118
119
120
121
122
123
124
125
  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),
126
127
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
128
  VAR("MapAddress",          LINELIST, AddressMap,           NULL),
129
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
130
  VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
131
132
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
Roger Dingledine's avatar
Roger Dingledine committed
133
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
134
  VAR("Group",               STRING,   Group,                NULL),
135
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
136
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
137
  VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL),
138
  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
139
  VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL),
140
  VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
141
142
143
144
145
  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),
146
  VAR("IgnoreVersion",       BOOL,     IgnoreVersion,        "0"),
147
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
148
149
150
  VAR("Log",                 LINELIST, Logs,                 NULL),
  VAR("LogLevel",            LINELIST_S, OldLogOptions,      NULL),
  VAR("LogFile",             LINELIST_S, OldLogOptions,      NULL),
151
  OBSOLETE("LinkPadding"),
152
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
153
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
154
  VAR("MonthlyAccountingStart",UINT,   _MonthlyAccountingStart,"0"),
155
156
  VAR("AccountingMaxKB",     UINT,     _AccountingMaxKB,     "0"),
  VAR("AccountingMax",       MEMUNIT,   AccountingMax,        "0 bytes"),
157
  VAR("Nickname",            STRING,   Nickname,             NULL),
158
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
159
  VAR("MaxCircuitDirtiness", INTERVAL, MaxCircuitDirtiness,  "10 minutes"),
160
161
162
163
164
  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),
165
  VAR("LongLivedPorts",      CSV,      LongLivedPorts,       "21,22,706,1863,5050,5190,5222,5223,6667,8300,8888"),
166
167
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
168
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
169
  OBSOLETE("RouterFile"),
170
171
172
173
174
  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),
175
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
176
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
177
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
178
179
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
180
181
  /** DOCDOC */
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),
182
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
183
  OBSOLETE("TrafficShaping"),
184
  VAR("User",                STRING,   User,                 NULL),
185
186
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
187
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
188
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
189
};
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#undef VAR

#define VAR(name,conftype,member,initvalue) \
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member), initvalue }
static config_var_t _state_vars[] = {
  VAR("LastWritten",             ISOTIME,     LastWritten,          NULL),

  VAR("AccountingIntervalStart", ISOTIME,  AccountingIntervalStart, NULL),
  VAR("AccountingBytesWrittenInInterval", MEMUNIT,
      AccountingBytesWrittenInInterval, NULL),
  VAR("AccountingBytesReadInterval", MEMUNIT, AccountingBytesReadInInterval,NULL),
  VAR("AccountingSecondsActive", INTERVAL,    AccountingSecondsActive, NULL),
  VAR("AccountingExpectedUsage", MEMUNIT,     AccountingExpectedUsage, NULL),

  VAR("HelperNodes",             LINELIST_V,  HelperNodes,          NULL),
  VAR("HelperNode",              LINELIST_S,  HelperNodes,          NULL),
  VAR("HelperNodeDownSince",     LINELIST_S,  HelperNodes,          NULL),
  VAR("HelperNodeUnlistedSince", LINELIST_S,  HelperNodes,          NULL),
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};

211
212
213
#undef VAR
#undef OBSOLETE

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/** DOCDOC*/
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

static config_var_description_t options_description[] = {
  { "Address", "The advertised (external) address we should use" },
  // { "AccountingStart", ""},
  { NULL, NULL },
};

static config_var_description_t state_description[] = {
  { "HelperNode", "One of the nodes we have chosen as a fixed entry" },
  { "HelperNodeDownSince",
    "The last helper node has been down since this time." },
  { "HelperNodeUnlistedSince",
    "The last helper node has been unlisted since this time." },
  { NULL, NULL },
};

235
236
237
238
239
240
241
242
243
typedef int (*validate_fn_t)(void*);

typedef struct {
  size_t size;
  uint32_t magic;
  off_t magic_offset;
  config_abbrev_t *abbrevs;
  config_var_t *vars;
  validate_fn_t validate_fn;
244
  config_var_description_t *descriptions;
245
246
247
248
249
250
251
} config_format_t;

#define CHECK(fmt, cfg) do {                                            \
    tor_assert(fmt && cfg);                                             \
    tor_assert((fmt)->magic == *(uint32_t*)(((char*)(cfg))+fmt->magic_offset)); \
  } while (0)

Nick Mathewson's avatar
Nick Mathewson committed
252
/** Largest allowed config line */
253
#define CONFIG_LINE_T_MAXLEN 4096
254

255
static void config_line_append(config_line_t **lst,
256
                               const char *key, const char *val);
257
258
static void option_reset(config_format_t *fmt, or_options_t *options,
                         config_var_t *var);
259
static void config_free(config_format_t *fmt, void *options);
260
261
262
static int option_is_same(config_format_t *fmt,
                          or_options_t *o1, or_options_t *o2,const char *name);
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
263
264
265
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);
266
static void config_register_addressmaps(or_options_t *options);
267

268
static int parse_dir_server_line(const char *line, int validate_only);
269
static int parse_redirect_line(smartlist_t *result,
270
                               config_line_t *line);
271
272
273
static int parse_log_severity_range(const char *range, int *min_out,
                                    int *max_out);
static int convert_log_option(or_options_t *options,
274
275
                              config_line_t *level_opt,
                              config_line_t *file_opt, int isDaemon);
276
277
278
279
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);
280
static int validate_data_directory(or_options_t *options);
281
static int write_configuration_file(const char *fname, or_options_t *options);
282
static config_line_t *get_assigned_option(config_format_t *fmt,
283
                                     or_options_t *options, const char *key);
284
285
static void config_init(config_format_t *fmt, void *options);
static int or_state_validate(or_state_t *options);
286

287
288
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
289
static void print_cvs_version(void);
290
static int init_libevent(void);
291
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
292
static void check_libevent_version(const char *m, const char *v, int server);
293
#endif
294

295
296
297
298
299
300
#define OR_OPTIONS_MAGIC 9090909

static config_format_t config_format = {
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  _option_abbrevs,
  _option_vars,
  (validate_fn_t)options_validate,
  options_description
};

#define OR_STATE_MAGIC 0x57A73f57

static config_format_t state_format = {
  sizeof(or_state_t),
  OR_STATE_MAGIC,
  STRUCT_OFFSET(or_state_t, _magic),
  NULL,
  _state_vars,
  (validate_fn_t)or_state_validate,
  state_description
317
318
};

319
320
321
322
323
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
324
static or_options_t *global_options = NULL;
Roger Dingledine's avatar
Roger Dingledine committed
325
/** Name of most recently read torrc file. */
326
static char *config_fname = NULL;
327
328
/** Persistant serialized state. */
static or_state_t *global_state = NULL;
329

330
331
332
333
334
335
336
337
338
static void *
config_alloc(config_format_t *fmt)
{
  void *opts = opts = tor_malloc_zero(fmt->size);
  *(uint32_t*)(((char*)opts)+fmt->magic_offset) = fmt->magic;
  CHECK(fmt, opts);
  return opts;
}

339
340
/** Return the currently configured options. */
or_options_t *
341
342
get_options(void)
{
343
344
345
  tor_assert(global_options);
  return global_options;
}
346

Roger Dingledine's avatar
Roger Dingledine committed
347
/** Change the current global options to contain <b>new_val</b> instead
348
 * of their current value; free the old value as necessary.
349
350
 */
void
351
352
set_options(or_options_t *new_val)
{
353
  if (global_options)
354
    config_free(&config_format, global_options);
355
  global_options = new_val;
356
357
}

358
359
360
void
config_free_all(void)
{
361
  config_free(&config_format, global_options);
362
363
364
  tor_free(config_fname);
}

365
366
367
368
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
369
370
safe_str(const char *address)
{
371
372
373
374
375
376
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

377
378
379
/** 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.
380
381
382
383
384
385
 *
 * 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.
386
387
 */
int
388
389
options_act(void)
{
390
  config_line_t *cl;
391
  or_options_t *options = get_options();
392
393
394
  static int libevent_initialized = 0;

  if (options->RunAsDaemon) {
395
    start_daemon();
396
  }
397
398

  clear_trusted_dir_servers();
399
  for (cl = options->DirServers; cl; cl = cl->next) {
400
401
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
402
             "Bug: Previously validated DirServer line could not be added!");
403
      return -1;
404
405
406
    }
  }

407
  if (rend_config_services(options, 0)<0) {
408
    log_fn(LOG_ERR,
409
           "Bug: Previously validated hidden services line could not be added!");
410
    return -1;
411
  }
412

413
414
415
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

416
  /* Setuid/setgid as appropriate */
417
418
  if (options->User || options->Group) {
    if (switch_id(options->User, options->Group) != 0) {
419
420
421
422
423
      return -1;
    }
  }

  /* Ensure data directory is private; create if possible. */
424
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
425
    log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
426
           options->DataDirectory);
427
428
429
430
431
432
433
434
    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;

435
  mark_logs_temp(); /* Close current logs once new logs are open. */
436
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
437
    return -1;
438

439
440
441
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
442
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
443
  control_adjust_event_log_severity();
444

445
446
447
448
449
450
451
  /* Set up libevent. */
  if (!libevent_initialized) {
    if (init_libevent())
      return -1;
    libevent_initialized = 1;
  }

452
453
454
455
456
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

457
  options->_ConnLimit =
458
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
459
  if (options->_ConnLimit < 0)
460
461
    return -1;

462
463
464
465
466
467
468
469
470
  {
    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);
  }

471
  /* Finish backgrounding the process */
472
  if (options->RunAsDaemon) {
473
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
474
    finish_daemon(options->DataDirectory);
475
476
477
478
  }

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

482
483
484
  /* Register addressmap directives */
  config_register_addressmaps(options);

485
486
487
488
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();

489
490
  init_cookie_authentication(options->CookieAuthentication);

491
492
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
493
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
494
495
496
    return -1;
  }

497
  /* Set up accounting */
498
  if (accounting_parse_options(options, 0)<0) {
499
    log_fn(LOG_ERR,"Error in accounting options");
500
501
    return -1;
  }
502
  if (accounting_is_enabled(options))
503
504
    configure_accounting(time(NULL));

505
  if (!we_are_hibernating() && retry_all_listeners(0) < 0) {
506
507
508
509
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    return -1;
  }

510
511
512
513
514
515
  /* 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();

516
  return 0;
517
518
519
520
521
522
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
523
/** If <b>option</b> is an official abbreviation for a longer option,
524
525
526
 * 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. */
527
static const char *
528
expand_abbrev(config_format_t *fmt, const char *option, int command_line)
529
530
{
  int i;
531
532
533
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
534
    /* Abbreviations aren't casei. */
535
536
537
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
      return fmt->abbrevs[i].full;
538
    }
539
540
541
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
542

Nick Mathewson's avatar
Nick Mathewson committed
543
/** Helper: Read a list of configuration options from the command line. */
544
static config_line_t *
545
546
config_get_commandlines(int argc, char **argv)
{
547
548
  config_line_t *front = NULL;
  config_line_t **new = &front;
549
550
551
  char *s;
  int i = 1;

552
  while (i < argc-1) {
553
554
555
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
556
      continue;
557
558
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
559
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
560
561
562
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
563
564
    }

565
    *new = tor_malloc_zero(sizeof(config_line_t));
566
    s = argv[i];
567

568
    while (*s == '-')
569
      s++;
570

571
    (*new)->key = tor_strdup(expand_abbrev(&config_format, s, 1));
572
573
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
574
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
575
576
577
        (*new)->key, (*new)->value);

    new = &((*new)->next);
578
579
580
581
582
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
583
/** Helper: allocate a new configuration option mapping 'key' to 'val',
584
585
 * append it to *<b>lst</b>. */
static void
586
config_line_append(config_line_t **lst,
587
588
                   const char *key,
                   const char *val)
589
{
590
  config_line_t *newline;
591

592
  newline = tor_malloc(sizeof(config_line_t));
593
594
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
595
596
597
598
599
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
600
601
}

602
603
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
604
605
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
606
int
607
config_get_lines(char *string, config_line_t **result)
608
{
609
  config_line_t *list = NULL, **next;
610
  char *k, *v;
611

612
  next = &list;
613
614
615
616
617
618
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
619
620
621
622
    if (k && v) {
      /* This list can get long, so we keep a pointer to the end of it
       * rather than using config_line_append over and over and getting n^2
       * performance.  This is the only really long list. */
623
      *next = tor_malloc(sizeof(config_line_t));
624
625
626
627
628
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
629
  } while (*string);
630

631
  *result = list;
632
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
633
634
}

Nick Mathewson's avatar
Nick Mathewson committed
635
636
637
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
638
void
639
config_free_lines(config_line_t *front)
640
{
641
  config_line_t *tmp;
642

643
  while (front) {
644
645
646
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
647
648
649
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
650
651
652
  }
}

Nick Mathewson's avatar
Nick Mathewson committed
653
654
655
656
/** 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.
 */
657
static config_var_t *
658
config_find_option(config_format_t *fmt, const char *key)
659
660
{
  int i;
661
  size_t keylen = strlen(key);
662
  if (!keylen)
663
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
664
  /* First, check for an exact (case-insensitive) match */
665
666
667
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strcasecmp(key, fmt->vars[i].name))
      return &fmt->vars[i];
Nick Mathewson's avatar
Nick Mathewson committed
668
669
  }
  /* If none, check for an abbreviated match */
670
671
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
672
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
673
          "Please use '%s' instead",
674
675
             key, fmt->vars[i].name);
      return &fmt->vars[i];
676
677
    }
  }
678
  /* Okay, unrecognized options */
679
680
681
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
682
/** If <b>c</b> is a syntactically valid configuration line, update
683
684
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
685
686
687
688
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
689
static int
690
config_assign_line(config_format_t *fmt,
691
                   or_options_t *options, config_line_t *c, int reset)
692
{
693
  int i, ok;
694
695
  config_var_t *var;
  void *lvalue;
696

697
698
699
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
700
701
702
703
704
705
  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)) {
706
    tor_free(c->key);
707
    c->key = tor_strdup(var->name);
708
709
  }

710
  if (reset && !strlen(c->value)) {
711
    option_reset(fmt, options, var);
712
713
714
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
715
  lvalue = ((char*)options) + var->var_offset;
716
  switch (var->type) {
717

718
719
720
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
721
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
722
          c->key,c->value);
723
      return -2;
724
    }
725
    *(int *)lvalue = i;
726
727
    break;

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
      return -2;
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
      return -2;
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

746
747
748
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
749
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
750
      return -2;
751
    }
752
    *(int *)lvalue = i;
753
754
755
    break;

  case CONFIG_TYPE_STRING:
756
757
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
758
759
760
    break;

  case CONFIG_TYPE_DOUBLE:
761
    *(double *)lvalue = atof(c->value);
762
763
    break;

764
765
766
767
768
769
770
  case CONFIG_TYPE_ISOTIME:
    if (parse_iso_time(c->value, (time_t *)lvalue)) {
      log(LOG_WARN, "Invalid time '%s' for keyword '%s'", c->value, c->key);
      return -2;
    }
    break;

771
  case CONFIG_TYPE_CSV:
772
773
774
775
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
776
      *(smartlist_t**)lvalue = smartlist_create();
777
    }
778

779
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
780
781
782
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

783
784
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
785
    config_line_append((config_line_t**)lvalue, c->key, c->value);
786
    break;
787
788
789
790

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
791
792
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
793
    return -2;
794
795
796
  default:
    tor_assert(0);
    break;
797
  }
798
  return 0;
799
800
}

801
802
/** restore the option named <b>key</b> in options to its default value. */
static void
803
config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
804
805
806
{
  config_var_t *var;

807
808
809
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
810
811
812
  if (!var)
    return; /* give error on next pass. */

813
  option_reset(fmt, options, var);
814
815
}

816
817
/** Return true iff key is a valid configuration option. */
int
818
option_is_recognized(const char *key)
819
{
820
  config_var_t *var = config_find_option(&config_format, key);
821
822
823
  return (var != NULL);
}

824
825
/** Return the canonical name of a configuration option. */
const char *
826
option_get_canonical_name(const char *key)
827
{
828
  config_var_t *var = config_find_option(&config_format, key);
829
830
831
  return var->name;
}

832
833
/** Return a canonicalized list of the options assigned for key.
 */
834
config_line_t *
835
option_get_assignment(or_options_t *options, const char *key)
836
837
838
839
{
  return get_assigned_option(&config_format, options, key);
}

840
static config_line_t *
841
get_assigned_option(config_format_t *fmt, or_options_t *options, const char *key)
842
843
844
845
{
  config_var_t *var;
  const void *value;
  char buf[32];
846
  config_line_t *result;
847
  tor_assert(options && key);
848

849
850
851
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
852
853
854
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
855
856
857
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
858
859
860
  }
  value = ((char*)options) + var->var_offset;

861
862
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
863
    /* Linelist requires special handling: we just copy and return it. */
864
865
    const config_line_t *next_in = *(const config_line_t**)value;
    config_line_t **next_out = &result;
866
    while (next_in) {
867
      *next_out = tor_malloc(sizeof(config_line_t));
868
869
870
871
872
873
874
875
876
      (*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;
  }

877
  result = tor_malloc_zero(sizeof(config_line_t));
878
  result->key = tor_strdup(var->name);
879
  switch (var->type)
880
881
    {
    case CONFIG_TYPE_STRING:
882
883
884
885
886
887
888
      if (*(char**)value) {
        result->value = tor_strdup(*(char**)value);
      } else {
        tor_free(result->key);
        tor_free(result);
        return NULL;
      }
889
      break;
890
891
892
893
894
895
896
897
898
    case CONFIG_TYPE_ISOTIME:
      if (*(time_t*)value) {
        result->value = tor_malloc(ISO_TIME_LEN+1);
        format_iso_time(result->value, *(time_t*)value);
      } else {
        tor_free(result->key);
        tor_free(result);
      }
      break;
899
    case CONFIG_TYPE_INTERVAL:
900
    case CONFIG_TYPE_UINT:
901
      /* This means every or_options_t uint or bool element
902
       * needs to be an int. Not, say, a uint16_t or char. */
903
904
905