config.c 107 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, NULL }
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, 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[] = {
Roger Dingledine's avatar
Roger Dingledine committed
98
  VAR("AccountingMax",       MEMUNIT,  AccountingMax,        "0 bytes"),
Nick Mathewson's avatar
Nick Mathewson committed
99
  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("AssumeReachable",     BOOL,     AssumeReachable,      "0"),
104
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
105
106
  /* XXXX 011 change this default on 0.1.1.x */
  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "1"),
107
  VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "5 MB"),
Nick Mathewson's avatar
Nick Mathewson committed
108
  VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "2 MB"),
109
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
Nick Mathewson's avatar
Nick Mathewson committed
110
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
111
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
112
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
113
  VAR("CookieAuthentication",BOOL,     CookieAuthentication, "0"),
114
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
115
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
116
  VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
117
  VAR("DirBindAddress",      LINELIST, DirBindAddress,       NULL),
Nick Mathewson's avatar
Nick Mathewson committed
118
  VAR("DirFetchPeriod",      INTERVAL, DirFetchPeriod,       "0 seconds"),  /** DOCDOC **/
119
  VAR("DirPolicy",           LINELIST, DirPolicy,            NULL),
Nick Mathewson's avatar
Nick Mathewson committed
120
  VAR("DirPort",             UINT,     DirPort,              "0"),
121
  OBSOLETE("DirPostPeriod"),
122
123
124
  VAR("DirServer",           LINELIST, DirServers,           NULL),
  VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
125
126
  VAR("ExitNodes",           STRING,   ExitNodes,            NULL),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
127
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
128
  VAR("FirewallPorts",       CSV,      FirewallPorts,        ""),
129
  VAR("Group",               STRING,   Group,                NULL),
Nick Mathewson's avatar
Nick Mathewson committed
130
  VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
131
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
132
133
134
135
136
  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),
137
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
138
  VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL),
139
  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
140
  VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL),
141
  OBSOLETE("IgnoreVersion"),
142
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
143
  VAR("Log",                 LINELIST, Logs,                 NULL),
144
  OBSOLETE("LinkPadding"),
Nick Mathewson's avatar
Nick Mathewson committed
145
146
147
148
149
150
  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"),
151
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
152
  OBSOLETE("MonthlyAccountingStart"),
Nick Mathewson's avatar
Nick Mathewson committed
153
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
154
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
Nick Mathewson's avatar
Nick Mathewson committed
155
156
157
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
158
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
Nick Mathewson's avatar
Nick Mathewson committed
159
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
160
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
161
  VAR("ORPort",              UINT,     ORPort,               "0"),
162
163
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
164
  VAR("PidFile",             STRING,   PidFile,              NULL),
165
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
Nick Mathewson's avatar
Nick Mathewson committed
166
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
167
168
  VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions,  NULL),
  VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions,  NULL),
169
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
170
171
172
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
173
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
174
  OBSOLETE("RouterFile"),
175
176
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
177
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
178
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
179
180
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
181
182
183
184
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),  /** DOCDOC */
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
185
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
186
187
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
188
  OBSOLETE("TrafficShaping"),
189
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
190
  VAR("User",                STRING,   User,                 NULL),
191
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
192
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
193
};
194
195
196
#undef VAR

#define VAR(name,conftype,member,initvalue) \
197
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member), initvalue, NULL }
198
static config_var_t _state_vars[] = {
Nick Mathewson's avatar
Nick Mathewson committed
199
  VAR("AccountingBytesReadInterval", MEMUNIT, AccountingBytesReadInInterval,NULL),
200
201
202
  VAR("AccountingBytesWrittenInInterval", MEMUNIT,
      AccountingBytesWrittenInInterval, NULL),
  VAR("AccountingExpectedUsage", MEMUNIT,     AccountingExpectedUsage, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
203
204
  VAR("AccountingIntervalStart", ISOTIME,  AccountingIntervalStart, NULL),
  VAR("AccountingSecondsActive", INTERVAL,    AccountingSecondsActive, NULL),
205
206
207
  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
208
209
210
  VAR("HelperNodes",             LINELIST_V,  HelperNodes,          NULL),
  VAR("LastWritten",             ISOTIME,     LastWritten,          NULL),

211
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
212
213
};

214
215
216
#undef VAR
#undef OBSOLETE

217
218
219
220
221
222
223
/** DOCDOC*/
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

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

238
239
240
241
242
243
244
245
246
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;
247
  config_var_description_t *descriptions;
248
249
250
251
252
253
254
} 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
255
/** Largest allowed config line */
256
#define CONFIG_LINE_T_MAXLEN 4096
257

258
static void config_line_append(config_line_t **lst,
259
                               const char *key, const char *val);
260
261
static void option_clear(config_format_t *fmt, or_options_t *options,
                         config_var_t *var);
262
static void option_reset(config_format_t *fmt, or_options_t *options,
263
                         config_var_t *var, int use_defaults);
264
static void config_free(config_format_t *fmt, void *options);
265
static int option_is_same(config_format_t *fmt,
266
                          or_options_t *o1, or_options_t *o2, const char *name);
267
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
268
static int options_validate(or_options_t *options);
269
static int options_act_reversible(or_options_t *old_options);
270
static int options_act(or_options_t *old_options);
271
static int options_transition_allowed(or_options_t *old, or_options_t *new);
272
273
274
275
static int options_transition_affects_workers(or_options_t *old_options,
                                              or_options_t *new_options);
static int options_transition_affects_descriptor(or_options_t *old_options,
                                                 or_options_t *new_options);
276
static int check_nickname_list(const char *lst, const char *name);
277
static void config_register_addressmaps(or_options_t *options);
278

279
static int parse_dir_server_line(const char *line, int validate_only);
280
static int parse_redirect_line(smartlist_t *result,
281
                               config_line_t *line);
282
283
284
static int parse_log_severity_range(const char *range, int *min_out,
                                    int *max_out);
static int convert_log_option(or_options_t *options,
285
286
                              config_line_t *level_opt,
                              config_line_t *file_opt, int isDaemon);
287
288
289
290
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);
291
static int validate_data_directory(or_options_t *options);
292
static int write_configuration_file(const char *fname, or_options_t *options);
293
static config_line_t *get_assigned_option(config_format_t *fmt,
294
                                     or_options_t *options, const char *key);
295
296
static void config_init(config_format_t *fmt, void *options);
static int or_state_validate(or_state_t *options);
297

298
299
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
300
static void print_cvs_version(void);
301
static void parse_reachable_addresses(void);
302
static int init_libevent(void);
303
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
304
static void check_libevent_version(const char *m, const char *v, int server);
305
#endif
306

307
308
/*static*/ or_options_t *options_new(void);

309
310
#define OR_OPTIONS_MAGIC 9090909

311
static config_format_t options_format = {
312
313
314
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  _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
331
332
};

333
334
335
336
337
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
338
static or_options_t *global_options = NULL;
Roger Dingledine's avatar
Roger Dingledine committed
339
/** Name of most recently read torrc file. */
340
static char *torrc_fname = NULL;
341
342
/** Persistant serialized state. */
static or_state_t *global_state = NULL;
343
344
/** DOCDOC */
static addr_policy_t *reachable_addr_policy = NULL;
345

346
347
348
349
350
351
352
353
354
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;
}

355
356
/** Return the currently configured options. */
or_options_t *
357
358
get_options(void)
{
359
360
361
  tor_assert(global_options);
  return global_options;
}
362

363
364
365
/** Change the current global options to contain <b>new_val</b> instead of
 * their current value; take action based on the new value; free the old value
 * as necessary.
366
 */
367
int
368
369
set_options(or_options_t *new_val)
{
370
  or_options_t *old_options = global_options;
371
  global_options = new_val;
372
373
  /* Note that we pass the *old* options below, for comparison. It
   * pulls the new options directly out of global_options. */
374
375
376
377
  if (options_act_reversible(old_options)<0) {
    global_options = old_options;
    return -1;
  }
378
379
380
381
382
  if (options_act(old_options) < 0) { /* acting on the options failed. die. */
    log_fn(LOG_ERR,"Acting on config options left us in a broken state. Dying.");
    exit(1);
  }
  if (old_options)
383
    config_free(&options_format, old_options);
384
385

  return 0;
386
387
}

388
389
390
void
config_free_all(void)
{
391
  config_free(&options_format, global_options);
392
  tor_free(torrc_fname);
393
394
  addr_policy_free(reachable_addr_policy);
  reachable_addr_policy = NULL;
395
396
}

397
398
399
400
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
401
402
safe_str(const char *address)
{
403
404
405
406
407
408
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
/** Fetch the active option list, and take actions based on it. All of the
 * things we do should survive being done repeatedly.  If present,
 * <b>old_options</b> contains the previous value of the options.
 *
 * Return 0 if all goes well, return -1 if things went badly.
 */
static int
options_act_reversible(or_options_t *old_options)
{
  smartlist_t *new_listeners = smartlist_create();
  smartlist_t *replaced_listeners = smartlist_create();
  static int libevent_initialized = 0;
  or_options_t *options = get_options();
  int running_tor = options->command == CMD_RUN_TOR;
  int set_conn_limit = 0;
  int r = -1;

  if (running_tor && options->RunAsDaemon) {
    /* No need to roll back, since you can't change the value. */
    start_daemon();
  }

  /* Setuid/setgid as appropriate */
  if (options->User || options->Group) {
    if (switch_id(options->User, options->Group) != 0) {
      /* No need to roll back, since you can't change the value. */
      goto done;
    }
  }

  /* Set up libevent. */
  if (running_tor && !libevent_initialized) {
    if (init_libevent())
      goto done;
    libevent_initialized = 1;
  }

  /* Ensure data directory is private; create if possible. */
  if (check_private_dir(options->DataDirectory, CPD_CREATE)<0) {
    log_fn(LOG_ERR, "Couldn't access/create private data directory \"%s\"",
           options->DataDirectory);
    /* No need to roll back, since you can't change the value. */
    goto done;
  }

  /* Bail out at this point if we're not going to be a client or server:
   * we don't run  */
  if (options->command != CMD_RUN_TOR)
    goto commit;

  options->_ConnLimit =
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
  if (options->_ConnLimit < 0)
    goto rollback;
  set_conn_limit = 1;

  if (retry_all_listeners(0, replaced_listeners, new_listeners) < 0) {
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    goto rollback;
  }

 commit:
  r = 0;
  SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn,
  {
    log_fn(LOG_NOTICE, "Closing old %s on %s:%d",
           conn_type_to_string(conn->type), conn->address, conn->port);
    connection_close_immediate(conn);
    connection_mark_for_close(conn);
  });
  goto done;

 rollback:
  r = -1;

  if (set_conn_limit && old_options)
    set_max_file_descriptors((unsigned)old_options->ConnLimit,MAXCONNECTIONS);

  SMARTLIST_FOREACH(new_listeners, connection_t *, conn,
  {
    log_fn(LOG_NOTICE, "Closing %s on %s:%d",
           conn_type_to_string(conn->type), conn->address, conn->port);
    connection_close_immediate(conn);
    connection_mark_for_close(conn);
  });

 done:
  smartlist_free(new_listeners);
  smartlist_free(replaced_listeners);
  return r;
}

501
502
503
/** Fetch the active option list, and take actions based on it. All of the
 * things we do should survive being done repeatedly.  If present,
 * <b>old_options</b> contains the previous value of the options.
504
 *
505
 * Return 0 if all goes well, return -1 if it's time to die.
506
507
508
 *
 * Note 2: We haven't moved all the "act on new configuration" logic
 * here yet.  Some is still in do_hup() and other places.
509
 */
510
511
static int
options_act(or_options_t *old_options)
512
{
513
  config_line_t *cl;
514
515
  char *fn;
  size_t len;
516
  or_options_t *options = get_options();
517
  int running_tor = options->command == CMD_RUN_TOR;
518
519

  clear_trusted_dir_servers();
520
  for (cl = options->DirServers; cl; cl = cl->next) {
521
522
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
523
             "Bug: Previously validated DirServer line could not be added!");
524
      return -1;
525
526
527
    }
  }

528
  if (running_tor && rend_config_services(options, 0)<0) {
529
    log_fn(LOG_ERR,
530
           "Bug: Previously validated hidden services line could not be added!");
531
    return -1;
532
  }
533

534
535
536
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

537
538
539
540
541
542
543
544
545
546
  if (running_tor) {
    len = strlen(options->DataDirectory)+32;
    fn = tor_malloc(len);
    tor_snprintf(fn, len, "%s/cached-status", options->DataDirectory);
    if (check_private_dir(fn, CPD_CREATE) != 0) {
      log_fn(LOG_ERR, "Couldn't access/create private data directory \"%s\"",
             fn);
      tor_free(fn);
      return -1;
    }
547
548
    tor_free(fn);
  }
549

550
551
  /* 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. */
552
553
554
  if (options->command != CMD_RUN_TOR)
    return 0;

555
  mark_logs_temp(); /* Close current logs once new logs are open. */
556
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
557
    return -1;
558

559
560
561
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
562
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
563
  control_adjust_event_log_severity();
564

565
566
567
568
569
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

570
571
572
573
574
575
576
577
578
  {
    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);
  }

579
  /* Finish backgrounding the process */
580
  if (running_tor && options->RunAsDaemon) {
581
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
582
    finish_daemon(options->DataDirectory);
583
584
585
586
  }

  /* Write our pid to the pid file. If we do not have write permissions we
   * will log a warning */
587
  if (running_tor && options->PidFile)
588
589
    write_pidfile(options->PidFile);

590
591
592
  /* Register addressmap directives */
  config_register_addressmaps(options);

593
594
595
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
596
  parse_reachable_addresses();
597

598
599
  init_cookie_authentication(options->CookieAuthentication);

600
601
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
602
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
603
604
605
    return -1;
  }

606
  /* Set up accounting */
607
  if (accounting_parse_options(options, 0)<0) {
608
    log_fn(LOG_ERR,"Error in accounting options");
609
610
    return -1;
  }
611
  if (accounting_is_enabled(options))
612
613
    configure_accounting(time(NULL));

614
615
616
  if (!running_tor)
    return 0;

617
618
619
620
621
622
623
624
625
  /* Check for transitions that need action. */
  if (old_options) {
    if (options_transition_affects_workers(old_options, options)) {
      log_fn(LOG_INFO,"Worker-related options changed. Rotating workers.");
      cpuworkers_rotate();
      dnsworkers_rotate();
    }
  }

626
  /* Since our options changed, we might need to regenerate and upload our
627
   * server descriptor.
628
   */
629
630
  if (!old_options || options_transition_affects_descriptor(old_options, options))
    mark_my_descriptor_dirty();
631

632
  return 0;
633
634
635
636
637
638
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
639
/** If <b>option</b> is an official abbreviation for a longer option,
640
641
642
 * 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. */
643
static const char *
644
expand_abbrev(config_format_t *fmt, const char *option, int command_line)
645
646
{
  int i;
647
648
649
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
650
    /* Abbreviations aren't casei. */
651
652
653
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
      return fmt->abbrevs[i].full;
654
    }
655
656
657
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
658

659
660
661
662
663
/** Helper: Read a list of configuration options from the command line.
 * If successful, put them in *<b>result</b> and return 0, and return
 * -1 and leave *<b>result</b> alone. */
static int
config_get_commandlines(int argc, char **argv, config_line_t **result)
664
{
665
666
  config_line_t *front = NULL;
  config_line_t **new = &front;
667
668
669
  char *s;
  int i = 1;

670
  while (i < argc) {
671
672
673
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
674
      continue;
675
676
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
677
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
678
679
680
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
681
    }
682
683
684
685
686
687
    if (i == argc-1) {
      log_fn(LOG_WARN,"Command-line option '%s' with no value. Failing.",
             argv[i]);
      config_free_lines(front);
      return -1;
    }
688

689
    *new = tor_malloc_zero(sizeof(config_line_t));
690
    s = argv[i];
691

692
    while (*s == '-')
693
      s++;
694

695
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1));
696
697
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
698
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
699
700
701
        (*new)->key, (*new)->value);

    new = &((*new)->next);
702
703
    i += 2;
  }
704
705
  *result = front;
  return 0;
706
707
}

Nick Mathewson's avatar
Nick Mathewson committed
708
/** Helper: allocate a new configuration option mapping 'key' to 'val',
709
710
 * append it to *<b>lst</b>. */
static void
711
config_line_append(config_line_t **lst,
712
713
                   const char *key,
                   const char *val)
714
{
715
  config_line_t *newline;
716

717
  newline = tor_malloc(sizeof(config_line_t));
718
719
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
720
721
722
723
724
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
725
726
}

727
728
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
729
730
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
731
int
732
config_get_lines(char *string, config_line_t **result)
733
{
734
  config_line_t *list = NULL, **next;
735
  char *k, *v;
736

737
  next = &list;
738
739
740
741
742
743
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
744
745
746
747
    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. */
748
      *next = tor_malloc(sizeof(config_line_t));
749
750
751
752
753
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
754
  } while (*string);
755

756
  *result = list;
757
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
758
759
}

Nick Mathewson's avatar
Nick Mathewson committed
760
761
762
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
763
void
764
config_free_lines(config_line_t *front)
765
{
766
  config_line_t *tmp;
767

768
  while (front) {
769
770
771
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
772
773
774
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
775
776
777
  }
}

778
779
780
781
782
783
784
785
786
787
788
789
/** 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
790
791
792
793
/** 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.
 */
794
static config_var_t *
795
config_find_option(config_format_t *fmt, const char *key)
796
797
{
  int i;
798
  size_t keylen = strlen(key);
799
  if (!keylen)
800
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
801
  /* First, check for an exact (case-insensitive) match */
802
  for (i=0; fmt->vars[i].name; ++i) {
803
    if (!strcasecmp(key, fmt->vars[i].name)) {
804
      return &fmt->vars[i];
805
    }
Nick Mathewson's avatar
Nick Mathewson committed
806
807
  }
  /* If none, check for an abbreviated match */
808
809
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
810
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
811
          "Please use '%s' instead",
812
813
             key, fmt->vars[i].name);
      return &fmt->vars[i];
814
815
    }
  }
816
  /* Okay, unrecognized options */
817
818
819
  return NULL;
}

820
821
822
823
/*
 * Functions to assign config options.
 */

824
825
/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
 * with <b>c</b>-\>value and return 0, or return -1 if bad value.
826
827
 *
 * Called from config_assign_line() and option_reset().
828
 */
829
static int
830
831
config_assign_value(config_format_t *fmt, or_options_t *options,
                    config_line_t *c)
832
{
833
  int i, ok;
834
835
  config_var_t *var;
  void *lvalue;
836

837
838
839
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
840
  tor_assert(var);
841

Nick Mathewson's avatar
Nick Mathewson committed
842
  lvalue = ((char*)options) + var->var_offset;
843

844
  switch (var->type) {
845

846
847
848
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
849
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
850
          c->key,c->value);
851
      return -1;
852
    }
853
    *(int *)lvalue = i;
854
855
    break;

856
857
858
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
859
      return -1;
860
861
862
863
864
865
866
867
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
868
      return -1;
869
870
871
872
873
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

874
875
876
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
877
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
878
      return -1;
879
    }
880
    *(int *)lvalue = i;
881
882
883
    break;

  case CONFIG_TYPE_STRING:
884
885
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
886
887
888
    break;

  case CONFIG_TYPE_DOUBLE:
889
    *(double *)lvalue = atof(c->value);
890
891
    break;

892
893
894
  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);
895
      return -1;
896
897
898
    }
    break;

899
  case CONFIG_TYPE_CSV:
Roger Dingledine's avatar
Roger Dingledine committed
900
    if (*(smartlist_t**)lvalue) {
901
902
903
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
904
      *(smartlist_t**)lvalue = smartlist_create();
905
    }
906

907
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
908
909
910
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

911
912
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
913
    config_line_append((config_line_t**)lvalue, c->key, c->value);