config.c 99.5 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,        ""),
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
  OBSOLETE("IgnoreVersion"),
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
  OBSOLETE("MonthlyAccountingStart"),
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
  VAR("PidFile",             STRING,   PidFile,              NULL),
162
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
Nick Mathewson's avatar
Nick Mathewson committed
163
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
164
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
165
166
167
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
168
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
169
  OBSOLETE("RouterFile"),
170
171
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
172
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
173
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
174
175
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
176
177
178
179
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),  /** DOCDOC */
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
180
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
181
182
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
183
  OBSOLETE("TrafficShaping"),
184
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
185
  VAR("User",                STRING,   User,                 NULL),
186
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
187
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
188
};
189
190
191
192
193
#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
194
  VAR("AccountingBytesReadInterval", MEMUNIT, AccountingBytesReadInInterval,NULL),
195
196
197
  VAR("AccountingBytesWrittenInInterval", MEMUNIT,
      AccountingBytesWrittenInInterval, NULL),
  VAR("AccountingExpectedUsage", MEMUNIT,     AccountingExpectedUsage, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
198
199
  VAR("AccountingIntervalStart", ISOTIME,  AccountingIntervalStart, NULL),
  VAR("AccountingSecondsActive", INTERVAL,    AccountingSecondsActive, NULL),
200
201
202
  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
203
204
205
  VAR("HelperNodes",             LINELIST_V,  HelperNodes,          NULL),
  VAR("LastWritten",             ISOTIME,     LastWritten,          NULL),

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

209
210
211
#undef VAR
#undef OBSOLETE

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

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

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

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

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

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

294
295
/*static*/ or_options_t *options_new(void);

296
297
#define OR_OPTIONS_MAGIC 9090909

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

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

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

333
334
335
336
337
338
339
340
341
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;
}

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

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

361
362
363
void
config_free_all(void)
{
364
  config_free(&options_format, global_options);
365
  tor_free(torrc_fname);
366
367
  addr_policy_free(reachable_addr_policy);
  reachable_addr_policy = NULL;
368
369
}

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

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

  if (options->RunAsDaemon) {
400
    start_daemon();
401
  }
402
403

  clear_trusted_dir_servers();
404
  for (cl = options->DirServers; cl; cl = cl->next) {
405
406
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
407
             "Bug: Previously validated DirServer line could not be added!");
408
      return -1;
409
410
411
    }
  }

412
  if (rend_config_services(options, 0)<0) {
413
    log_fn(LOG_ERR,
414
           "Bug: Previously validated hidden services line could not be added!");
415
    return -1;
416
  }
417

418
419
420
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

421
  /* Setuid/setgid as appropriate */
422
423
  if (options->User || options->Group) {
    if (switch_id(options->User, options->Group) != 0) {
424
425
426
427
428
      return -1;
    }
  }

  /* Ensure data directory is private; create if possible. */
429
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
430
    log_fn(LOG_ERR, "Couldn't access/create private data directory %s",
431
           options->DataDirectory);
432
433
434
    return -1;
  }

435
436
  /* Bail out at this point if we're not going to be a client or server:
   * we want to not fork, and to log stuff to stderr. */
437
438
439
  if (options->command != CMD_RUN_TOR)
    return 0;

440
  mark_logs_temp(); /* Close current logs once new logs are open. */
441
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
442
    return -1;
443

444
445
446
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
447
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
448
  control_adjust_event_log_severity();
449

450
451
452
453
454
455
456
  /* Set up libevent. */
  if (!libevent_initialized) {
    if (init_libevent())
      return -1;
    libevent_initialized = 1;
  }

457
458
459
460
461
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

462
  options->_ConnLimit =
463
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
464
  if (options->_ConnLimit < 0)
465
466
    return -1;

467
468
469
470
471
472
473
474
475
  {
    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);
  }

476
  /* Finish backgrounding the process */
477
  if (options->RunAsDaemon) {
478
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
479
    finish_daemon(options->DataDirectory);
480
481
482
483
  }

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

487
488
489
  /* Register addressmap directives */
  config_register_addressmaps(options);

490
491
492
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
493
  parse_reachable_addresses();
494

495
496
  init_cookie_authentication(options->CookieAuthentication);

497
498
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
499
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
500
501
502
    return -1;
  }

503
  /* Set up accounting */
504
  if (accounting_parse_options(options, 0)<0) {
505
    log_fn(LOG_ERR,"Error in accounting options");
506
507
    return -1;
  }
508
  if (accounting_is_enabled(options))
509
510
    configure_accounting(time(NULL));

511
  if (!we_are_hibernating() && retry_all_listeners(0) < 0) {
512
513
514
515
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    return -1;
  }

516
517
518
519
520
521
  /* 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();

522
  return 0;
523
524
525
526
527
528
}

/*
 * Functions to parse config options
 */

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

Nick Mathewson's avatar
Nick Mathewson committed
549
/** Helper: Read a list of configuration options from the command line. */
550
static config_line_t *
551
552
config_get_commandlines(int argc, char **argv)
{
553
554
  config_line_t *front = NULL;
  config_line_t **new = &front;
555
556
557
  char *s;
  int i = 1;

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

571
    *new = tor_malloc_zero(sizeof(config_line_t));
572
    s = argv[i];
573

574
    while (*s == '-')
575
      s++;
576

577
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1));
578
579
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
580
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
581
582
583
        (*new)->key, (*new)->value);

    new = &((*new)->next);
584
585
586
587
588
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
589
/** Helper: allocate a new configuration option mapping 'key' to 'val',
590
591
 * append it to *<b>lst</b>. */
static void
592
config_line_append(config_line_t **lst,
593
594
                   const char *key,
                   const char *val)
595
{
596
  config_line_t *newline;
597

598
  newline = tor_malloc(sizeof(config_line_t));
599
600
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
601
602
603
604
605
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
606
607
}

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

618
  next = &list;
619
620
621
622
623
624
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
625
626
627
628
    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. */
629
      *next = tor_malloc(sizeof(config_line_t));
630
631
632
633
634
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
635
  } while (*string);
636

637
  *result = list;
638
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
639
640
}

Nick Mathewson's avatar
Nick Mathewson committed
641
642
643
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
644
void
645
config_free_lines(config_line_t *front)
646
{
647
  config_line_t *tmp;
648

649
  while (front) {
650
651
652
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
653
654
655
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
656
657
658
  }
}

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

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

716
717
718
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
719
720
721
722
723
724
  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)) {
725
    tor_free(c->key);
726
    c->key = tor_strdup(var->name);
727
728
  }

729
  if (reset && !strlen(c->value)) {
730
    option_reset(fmt, options, var);
731
732
733
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
734
  lvalue = ((char*)options) + var->var_offset;
735
  switch (var->type) {
736

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

747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
  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;
  }

765
766
767
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
768
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
769
      return -2;
770
    }
771
    *(int *)lvalue = i;
772
773
774
    break;

  case CONFIG_TYPE_STRING:
775
776
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
777
778
779
    break;

  case CONFIG_TYPE_DOUBLE:
780
    *(double *)lvalue = atof(c->value);
781
782
    break;

783
784
785
786
787
788
789
  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;

790
  case CONFIG_TYPE_CSV:
791
792
793
794
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
795
      *(smartlist_t**)lvalue = smartlist_create();
796
    }
797

798
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
799
800
801
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

802
803
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
804
    config_line_append((config_line_t**)lvalue, c->key, c->value);
805
    break;
806
807
808
809

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
810
811
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
812
    return -2;
813
814
815
  default:
    tor_assert(0);
    break;
816
  }
817
  return 0;
818
819
}

820
821
/** restore the option named <b>key</b> in options to its default value. */
static void
822
config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
823
824
825
{
  config_var_t *var;

826
827
828
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
829
830
831
  if (!var)
    return; /* give error on next pass. */

832
  option_reset(fmt, options, var);
833
834
}

835
836
/** Return true iff key is a valid configuration option. */
int
837
option_is_recognized(const char *key)
838
{
839
  config_var_t *var = config_find_option(&options_format, key);
840
841
842
  return (var != NULL);
}

843
844
/** Return the canonical name of a configuration option. */
const char *
845
option_get_canonical_name(const char *key)
846
{
847
  config_var_t *var = config_find_option(&options_format, key);
848
849
850
  return var->name;
}

851
852
/** Return a canonicalized list of the options assigned for key.
 */
853
config_line_t *
854
option_get_assignment(or_options_t *options, const char *key)
855
{
856
  return get_assigned_option(&options_format, options, key);
857
858
}

859
static config_line_t *
860
get_assigned_option(config_format_t *fmt, or_options_t *options, const char *key)
861
862
863
864
{
  config_var_t *var;
  const void *value;
  char buf[32];
865
  config_line_t *result;
866
  tor_assert(options && key);