config.c 95.4 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
/** DOCDOC*/
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

static config_var_description_t options_description[] = {
221
  { "Address", "The advertised (external) address we should use." },
222
223
224
225
226
227
228
229
230
231
232
233
234
  // { "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
#define OR_OPTIONS_MAGIC 9090909

297
static config_format_t options_format = {
298
299
300
  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(&options_format, global_options);
355
  global_options = new_val;
356
357
}

358
359
360
void
config_free_all(void)
{
361
  config_free(&options_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(&options_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
  }
}

653
654
655
656
657
658
659
660
661
662
663
664
/** DOCDOC */
static const char *
config_find_description(config_format_t *fmt, const char *name)
{
  int i;
  for (i=0; fmt->descriptions[i].name; ++i) {
    if (!strcasecmp(name, fmt->descriptions[i].name))
      return fmt->descriptions[i].description;
  }
  return NULL;
}

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

Nick Mathewson's avatar
Nick Mathewson committed
695
/** If <b>c</b> is a syntactically valid configuration line, update
696
697
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
698
699
700
701
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
702
static int
703
config_assign_line(config_format_t *fmt,
704
                   or_options_t *options, config_line_t *c, int reset)
705
{
706
  int i, ok;
707
708
  config_var_t *var;
  void *lvalue;
709

710
711
712
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
713
714
715
716
717
718
  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)) {
719
    tor_free(c->key);
720
    c->key = tor_strdup(var->name);
721
722
  }

723
  if (reset && !strlen(c->value)) {
724
    option_reset(fmt, options, var);
725
726
727
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
728
  lvalue = ((char*)options) + var->var_offset;
729
  switch (var->type) {
730

731
732
733
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
734
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
735
          c->key,c->value);
736
      return -2;
737
    }
738
    *(int *)lvalue = i;
739
740
    break;

741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
  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;
  }

759
760
761
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
762
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
763
      return -2;
764
    }
765
    *(int *)lvalue = i;
766
767
768
    break;

  case CONFIG_TYPE_STRING:
769
770
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
771
772
773
    break;

  case CONFIG_TYPE_DOUBLE:
774
    *(double *)lvalue = atof(c->value);
775
776
    break;

777
778
779
780
781
782
783
  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;

784
  case CONFIG_TYPE_CSV:
785
786
787
788
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
789
      *(smartlist_t**)lvalue = smartlist_create();
790
    }
791

792
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
793
794
795
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

796
797
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
798
    config_line_append((config_line_t**)lvalue, c->key, c->value);
799
    break;
800
801
802
803

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
804
805
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
806
    return -2;
807
808
809
  default:
    tor_assert(0);
    break;
810
  }
811
  return 0;
812
813
}

814
815
/** restore the option named <b>key</b> in options to its default value. */
static void
816
config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
817
818
819
{
  config_var_t *var;

820
821
822
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
823
824
825
  if (!var)
    return; /* give error on next pass. */

826
  option_reset(fmt, options, var);
827
828
}

829
830
/** Return true iff key is a valid configuration option. */
int
831
option_is_recognized(const char *key)
832
{
833
  config_var_t *var = config_find_option(&options_format, key);
834
835
836
  return (var != NULL);
}

837
838
/** Return the canonical name of a configuration option. */
const char *
839
option_get_canonical_name(const char *key)
840
{
841
  config_var_t *var = config_find_option(&options_format, key);
842
843
844
  return var->name;
}

845
846
/** Return a canonicalized list of the options assigned for key.
 */
847
config_line_t *
848
option_get_assignment(or_options_t *options, const char *key)
849
{
850
  return get_assigned_option(&options_format, options, key);
851
852
}

853
static config_line_t *
854
get_assigned_option(config_format_t *fmt, or_options_t *options, const char *key)
855
856
857
858
{
  config_var_t *var;
  const void *value;
  char buf[32];
859
  config_line_t *result;
860
  tor_assert(options && key);
861

862
863
864
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
865
866
867
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", key);
    return NULL;
868
869
870
  } else if (var->type == CONFIG_TYPE_LINELIST_S) {
    log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
    return NULL;
871
872
873
  }
  value = ((char*)options) + var->var_offset;

874
875
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
876
    /* Linelist requires special handling: we just copy and return it. */
877
878
    const config_line_t *next_in = *(const config_line_t**)value;
    config_line_t **next_out = &result;
879
    while (next_in) {
880
      *next_out = tor_malloc(sizeof(config_line_t));
881
882
883
884
885
886
887
888
889
      (*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;
  }

890
  result = tor_malloc_zero(sizeof(config_line_t));
891
  result->key = tor_strdup(var->name);
892
  switch (var->type)
893
894
    {
    case CONFIG_TYPE_STRING:
895
896
897
898
899
900
901
      if (*(char**)value) {
        result->value = tor_strdup(*(char**)value);
      } else {