config.c 98.9 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
  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
  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
#define OR_OPTIONS_MAGIC 9090909

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

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

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

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

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

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

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

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

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

  if (options->RunAsDaemon) {
398
    start_daemon();
399
  }
400
401

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

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

416
417
418
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

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

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

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

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

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

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

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

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

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

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

485
486
487
  /* Register addressmap directives */
  config_register_addressmaps(options);

488
489
490
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
491
  parse_reachable_addresses();
492

493
494
  init_cookie_authentication(options->CookieAuthentication);

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

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

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

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

520
  return 0;
521
522
523
524
525
526
}

/*
 * Functions to parse config options
 */

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

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

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

569
    *new = tor_malloc_zero(sizeof(config_line_t));
570
    s = argv[i];
571

572
    while (*s == '-')
573
      s++;
574

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

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

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

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

  (*lst) = newline;
604
605
}

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

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

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

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

647
  while (front) {
648
649
650
    tmp = front;
    front = tmp->next;

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

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

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

714
715
716
  CHECK(fmt, options);

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

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

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

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

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

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

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

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

781
782
783
784
785
786
787
  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;

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

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

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

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

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

824
825
826
  CHECK(fmt, options);

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

830
  option_reset(fmt, options, var);
831
832
}

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

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

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

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

866
867
868
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
869
870
871
  if (!var) {
    log_fn(LOG_WARN,