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[] = {
Nick Mathewson's avatar
Nick Mathewson committed
98
99
  VAR("AccountingMax",       MEMUNIT,   AccountingMax,        "0 bytes"),
  VAR("AccountingMaxKB",     UINT,     _AccountingMaxKB,     "0"),
100
  VAR("AccountingStart",     STRING,   AccountingStart,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
101
  VAR("Address",             STRING,   Address,              NULL),
102
  VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes, "middle,rendezvous"),
103
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
104
  VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "5 MB"),
Nick Mathewson's avatar
Nick Mathewson committed
105
  VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "2 MB"),
106
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
Nick Mathewson's avatar
Nick Mathewson committed
107
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
108
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
109
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
110
  VAR("CookieAuthentication",BOOL,     CookieAuthentication, "0"),
111
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
112
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
113
  VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
114
  VAR("DirBindAddress",      LINELIST, DirBindAddress,       NULL),
Nick Mathewson's avatar
Nick Mathewson committed
115
  VAR("DirFetchPeriod",      INTERVAL, DirFetchPeriod,       "0 seconds"),  /** DOCDOC **/
116
  VAR("DirPolicy",           LINELIST, DirPolicy,            NULL),
Nick Mathewson's avatar
Nick Mathewson committed
117
118
  VAR("DirPort",             UINT,     DirPort,              "0"),
  VAR("DirPostPeriod",       INTERVAL, DirPostPeriod,        "20 minutes"),
119
120
121
  VAR("DirServer",           LINELIST, DirServers,           NULL),
  VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
122
123
  VAR("ExitNodes",           STRING,   ExitNodes,            NULL),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
124
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
125
  VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
126
  VAR("Group",               STRING,   Group,                NULL),
Nick Mathewson's avatar
Nick Mathewson committed
127
  VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
128
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
129
130
131
132
133
  VAR("HiddenServiceDir",    LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL),
  VAR("HiddenServiceNodes",  LINELIST_S, RendConfigLines,    NULL),
  VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines,    NULL),
  VAR("HiddenServicePort",   LINELIST_S, RendConfigLines,    NULL),
134
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
135
  VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL),
136
  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
137
  VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL),
138
  VAR("IgnoreVersion",       BOOL,     IgnoreVersion,        "0"),
139
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
140
  VAR("Log",                 LINELIST, Logs,                 NULL),
141
  OBSOLETE("LinkPadding"),
Nick Mathewson's avatar
Nick Mathewson committed
142
143
144
145
146
147
  VAR("LogFile",             LINELIST_S, OldLogOptions,      NULL),
  VAR("LogLevel",            LINELIST_S, OldLogOptions,      NULL),
  VAR("LongLivedPorts",      CSV,      LongLivedPorts,       "21,22,706,1863,5050,5190,5222,5223,6667,8300,8888"),
  VAR("MapAddress",          LINELIST, AddressMap,           NULL),
  VAR("MaxAdvertisedBandwidth",MEMUNIT,MaxAdvertisedBandwidth,"128 TB"),
  VAR("MaxCircuitDirtiness", INTERVAL, MaxCircuitDirtiness,  "10 minutes"),
148
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
149
  VAR("MonthlyAccountingStart",UINT,   _MonthlyAccountingStart,"0"),
Nick Mathewson's avatar
Nick Mathewson committed
150
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
151
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
Nick Mathewson's avatar
Nick Mathewson committed
152
153
154
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
155
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
Nick Mathewson's avatar
Nick Mathewson committed
156
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
157
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
158
  VAR("ORPort",              UINT,     ORPort,               "0"),
159
160
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
161
162
  VAR("PidFile",             STRING,   PidFile,              NULL),
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
163
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
164
165
166
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
167
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
168
  OBSOLETE("RouterFile"),
169
170
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
171
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
172
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
173
174
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
175
176
177
178
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),  /** DOCDOC */
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
179
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
180
181
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
182
  OBSOLETE("TrafficShaping"),
183
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
184
  VAR("User",                STRING,   User,                 NULL),
185
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
186
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
187
};
188
189
190
191
192
#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[] = {
Nick Mathewson's avatar
Nick Mathewson committed
193
  VAR("AccountingBytesReadInterval", MEMUNIT, AccountingBytesReadInInterval,NULL),
194
195
196
  VAR("AccountingBytesWrittenInInterval", MEMUNIT,
      AccountingBytesWrittenInInterval, NULL),
  VAR("AccountingExpectedUsage", MEMUNIT,     AccountingExpectedUsage, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
197
198
  VAR("AccountingIntervalStart", ISOTIME,  AccountingIntervalStart, NULL),
  VAR("AccountingSecondsActive", INTERVAL,    AccountingSecondsActive, NULL),
199
200
201
  VAR("HelperNode",              LINELIST_S,  HelperNodes,          NULL),
  VAR("HelperNodeDownSince",     LINELIST_S,  HelperNodes,          NULL),
  VAR("HelperNodeUnlistedSince", LINELIST_S,  HelperNodes,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
202
203
204
  VAR("HelperNodes",             LINELIST_V,  HelperNodes,          NULL),
  VAR("LastWritten",             ISOTIME,     LastWritten,          NULL),

205
206
207
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};

208
209
210
#undef VAR
#undef OBSOLETE

211
212
213
214
215
216
217
/** DOCDOC*/
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

static config_var_description_t options_description[] = {
218
  { "Address", "The advertised (external) address we should use." },
219
220
221
222
223
224
225
226
227
228
229
230
231
  // { "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 },
};

232
233
234
235
236
237
238
239
240
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;
241
  config_var_description_t *descriptions;
242
243
244
245
246
247
248
} 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
249
/** Largest allowed config line */
250
#define CONFIG_LINE_T_MAXLEN 4096
251

252
static void config_line_append(config_line_t **lst,
253
                               const char *key, const char *val);
254
255
static void option_reset(config_format_t *fmt, or_options_t *options,
                         config_var_t *var);
256
static void config_free(config_format_t *fmt, void *options);
257
258
259
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);
260
261
262
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);
263
static void config_register_addressmaps(or_options_t *options);
264

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

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

292
293
#define OR_OPTIONS_MAGIC 9090909

294
static config_format_t options_format = {
295
296
297
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  _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
314
315
};

316
317
318
319
320
/*
 * Functions to read and write the global options pointer.
 */

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

327
328
329
330
331
332
333
334
335
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;
}

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

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

355
356
357
void
config_free_all(void)
{
358
  config_free(&options_format, global_options);
359
360
361
  tor_free(config_fname);
}

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

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

  if (options->RunAsDaemon) {
392
    start_daemon();
393
  }
394
395

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

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

410
411
412
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

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

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

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

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

442
443
444
445
446
447
448
  /* Set up libevent. */
  if (!libevent_initialized) {
    if (init_libevent())
      return -1;
    libevent_initialized = 1;
  }

449
450
451
452
453
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

454
  options->_ConnLimit =
455
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
456
  if (options->_ConnLimit < 0)
457
458
    return -1;

459
460
461
462
463
464
465
466
467
  {
    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);
  }

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

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

479
480
481
  /* Register addressmap directives */
  config_register_addressmaps(options);

482
483
484
485
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();

486
487
  init_cookie_authentication(options->CookieAuthentication);

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

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

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

507
508
509
510
511
512
  /* 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();

513
  return 0;
514
515
516
517
518
519
}

/*
 * Functions to parse config options
 */

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

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

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

562
    *new = tor_malloc_zero(sizeof(config_line_t));
563
    s = argv[i];
564

565
    while (*s == '-')
566
      s++;
567

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

    new = &((*new)->next);
575
576
577
578
579
    i += 2;
  }
  return front;
}

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

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

  (*lst) = newline;
597
598
}

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

609
  next = &list;
610
611
612
613
614
615
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
616
617
618
619
    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. */
620
      *next = tor_malloc(sizeof(config_line_t));
621
622
623
624
625
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
626
  } while (*string);
627

628
  *result = list;
629
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
630
631
}

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

640
  while (front) {
641
642
643
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
644
645
646
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
647
648
649
  }
}

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

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

707
708
709
  CHECK(fmt, options);

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

720
  if (reset && !strlen(c->value)) {
721
    option_reset(fmt, options, var);
722
723
724
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
725
  lvalue = ((char*)options) + var->var_offset;
726
  switch (var->type) {
727

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

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

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

  case CONFIG_TYPE_STRING:
766
767
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
768
769
770
    break;

  case CONFIG_TYPE_DOUBLE:
771
    *(double *)lvalue = atof(c->value);
772
773
    break;

774
775
776
777
778
779
780
  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;

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

789
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
790
791
792
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

793
794
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
795
    config_line_append((config_line_t**)lvalue, c->key, c->value);
796
    break;
797
798
799
800

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

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

817
818
819
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
820
821
822
  if (!var)
    return; /* give error on next pass. */

823
  option_reset(fmt, options, var);
824
825
}

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

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

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

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

859
860
861
  CHECK(fmt, options);

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

871
872
  if (var->type == CONFIG_TYPE_LINELIST ||
      var->type == CONFIG_TYPE_LINELIST_V) {
873
    /* Linelist requires special handling: we just copy and return it. */
874
875
    const config_line_t *next_in = *(const config_line_t**)value;
    config_line_t **next_out = &result;
876
    while (next_in) {
Nick Mathewson's avatar