config.c 109 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

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
105
  VAR("AuthDirInvalid",      LINELIST, AuthDirInvalid,       NULL),
  VAR("AuthDirReject",       LINELIST, AuthDirReject,        NULL),
106
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
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"),
155
  VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
Nick Mathewson's avatar
Nick Mathewson committed
156
157
158
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
159
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
Nick Mathewson's avatar
Nick Mathewson committed
160
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
161
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
162
  VAR("ORPort",              UINT,     ORPort,               "0"),
163
164
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
165
  VAR("PidFile",             STRING,   PidFile,              NULL),
166
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
Nick Mathewson's avatar
Nick Mathewson committed
167
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
168
169
  VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions,  NULL),
  VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions,  NULL),
170
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
171
172
173
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
174
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
175
  OBSOLETE("RouterFile"),
176
177
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
178
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
179
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
180
181
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
182
183
184
185
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),  /** DOCDOC */
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
186
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
187
188
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
189
  OBSOLETE("TrafficShaping"),
190
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
191
  VAR("User",                STRING,   User,                 NULL),
192
  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "0"),
193
  VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
194
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
195
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
196
};
197
198
199
#undef VAR

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

214
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
215
216
};

217
218
219
#undef VAR
#undef OBSOLETE

220
221
222
223
224
225
226
/** DOCDOC*/
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

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

241
242
typedef int (*validate_fn_t)(void*);

243
244
245
/** Information on the keys, value types, key-to-struct-member mappings,
 * variable descriptions, validation functions, and abbreviations for a
 * configuration or storage format. */
246
247
248
249
250
251
252
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;
253
  config_var_description_t *descriptions;
254
255
256
257
258
259
260
} 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
261
/** Largest allowed config line */
262
#define CONFIG_LINE_T_MAXLEN 4096
263

264
static void config_line_append(config_line_t **lst,
265
                               const char *key, const char *val);
266
267
static void option_clear(config_format_t *fmt, or_options_t *options,
                         config_var_t *var);
268
static void option_reset(config_format_t *fmt, or_options_t *options,
269
                         config_var_t *var, int use_defaults);
270
static void config_free(config_format_t *fmt, void *options);
271
static int option_is_same(config_format_t *fmt,
272
                          or_options_t *o1, or_options_t *o2, const char *name);
273
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
274
static int options_validate(or_options_t *options);
275
static int options_act_reversible(or_options_t *old_options);
276
static int options_act(or_options_t *old_options);
277
static int options_transition_allowed(or_options_t *old, or_options_t *new);
278
279
280
281
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);
282
static int check_nickname_list(const char *lst, const char *name);
283
static void config_register_addressmaps(or_options_t *options);
284

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

304
305
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
306
static void print_cvs_version(void);
307
static void parse_reachable_addresses(void);
308
static int init_libevent(void);
309
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
310
static void check_libevent_version(const char *m, const char *v, int server);
311
#endif
312

313
314
/*static*/ or_options_t *options_new(void);

315
316
#define OR_OPTIONS_MAGIC 9090909

317
static config_format_t options_format = {
318
319
320
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  _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
337
338
};

339
340
341
342
343
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
344
static or_options_t *global_options = NULL;
Roger Dingledine's avatar
Roger Dingledine committed
345
/** Name of most recently read torrc file. */
346
static char *torrc_fname = NULL;
347
348
/** Persistant serialized state. */
static or_state_t *global_state = NULL;
349
350
/** DOCDOC */
static addr_policy_t *reachable_addr_policy = NULL;
351

352
353
354
355
356
357
358
359
360
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;
}

361
362
/** Return the currently configured options. */
or_options_t *
363
364
get_options(void)
{
365
366
367
  tor_assert(global_options);
  return global_options;
}
368

369
370
371
/** 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.
372
 */
373
int
374
375
set_options(or_options_t *new_val)
{
376
  or_options_t *old_options = global_options;
377
  global_options = new_val;
378
379
  /* Note that we pass the *old* options below, for comparison. It
   * pulls the new options directly out of global_options. */
380
381
382
383
  if (options_act_reversible(old_options)<0) {
    global_options = old_options;
    return -1;
  }
384
385
386
387
388
  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)
389
    config_free(&options_format, old_options);
390
391

  return 0;
392
393
}

394
395
396
void
config_free_all(void)
{
397
  config_free(&options_format, global_options);
398
  config_free(&state_format, global_state);
399
  tor_free(torrc_fname);
400
401
  addr_policy_free(reachable_addr_policy);
  reachable_addr_policy = NULL;
402
403
}

404
405
406
407
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
408
409
safe_str(const char *address)
{
410
411
412
413
414
415
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

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
501
502
503
504
505
506
507
/** 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;
}

508
509
510
/** 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.
511
 *
512
 * Return 0 if all goes well, return -1 if it's time to die.
513
514
515
 *
 * Note 2: We haven't moved all the "act on new configuration" logic
 * here yet.  Some is still in do_hup() and other places.
516
 */
517
518
static int
options_act(or_options_t *old_options)
519
{
520
  config_line_t *cl;
521
522
  char *fn;
  size_t len;
523
  or_options_t *options = get_options();
524
  int running_tor = options->command == CMD_RUN_TOR;
525
526

  clear_trusted_dir_servers();
527
  for (cl = options->DirServers; cl; cl = cl->next) {
528
529
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
530
             "Bug: Previously validated DirServer line could not be added!");
531
      return -1;
532
533
534
    }
  }

535
  if (running_tor && rend_config_services(options, 0)<0) {
536
    log_fn(LOG_ERR,
537
           "Bug: Previously validated hidden services line could not be added!");
538
    return -1;
539
  }
540

541
542
543
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

544
545
546
547
548
549
550
551
552
553
  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;
    }
554
555
    tor_free(fn);
  }
556

557
558
  /* 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. */
559
560
561
  if (options->command != CMD_RUN_TOR)
    return 0;

562
  mark_logs_temp(); /* Close current logs once new logs are open. */
563
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
564
    return -1;
565

566
567
568
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
569
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
570
  control_adjust_event_log_severity();
571

572
573
574
575
576
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

577
578
579
580
581
582
583
584
585
  {
    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);
  }

586
  /* Finish backgrounding the process */
587
  if (running_tor && options->RunAsDaemon) {
588
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
589
    finish_daemon(options->DataDirectory);
590
591
592
593
  }

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

597
598
599
  /* Register addressmap directives */
  config_register_addressmaps(options);

600
601
602
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
603
  parse_authdir_policy();
604
  parse_reachable_addresses();
605

606
607
  init_cookie_authentication(options->CookieAuthentication);

608
609
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
610
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
611
612
613
    return -1;
  }

614
  /* Set up accounting */
615
  if (accounting_parse_options(options, 0)<0) {
616
    log_fn(LOG_ERR,"Error in accounting options");
617
618
    return -1;
  }
619
  if (accounting_is_enabled(options))
620
621
    configure_accounting(time(NULL));

622
623
624
  if (!running_tor)
    return 0;

625
626
  /* Check for transitions that need action. */
  if (old_options) {
627
628
629
630
631
632
    if (options->UseHelperNodes && !old_options->UseHelperNodes) {
      log_fn(LOG_INFO, "Switching to helper nodes; abandoning previous circuits");
      circuit_mark_all_unused_circs();
      circuit_expire_all_dirty_circs();
    }

633
634
635
636
637
638
639
    if (options_transition_affects_workers(old_options, options)) {
      log_fn(LOG_INFO,"Worker-related options changed. Rotating workers.");
      cpuworkers_rotate();
      dnsworkers_rotate();
    }
  }

640
  /* Since our options changed, we might need to regenerate and upload our
641
   * server descriptor.
642
   */
643
644
  if (!old_options || options_transition_affects_descriptor(old_options, options))
    mark_my_descriptor_dirty();
645

646
  return 0;
647
648
649
650
651
652
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
653
/** If <b>option</b> is an official abbreviation for a longer option,
654
655
656
 * 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. */
657
static const char *
658
expand_abbrev(config_format_t *fmt, const char *option, int command_line)
659
660
{
  int i;
661
662
663
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
664
    /* Abbreviations aren't casei. */
665
666
667
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
      return fmt->abbrevs[i].full;
668
    }
669
670
671
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
672

673
674
675
676
677
/** 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)
678
{
679
680
  config_line_t *front = NULL;
  config_line_t **new = &front;
681
682
683
  char *s;
  int i = 1;

684
  while (i < argc) {
685
686
687
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
688
      continue;
689
690
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
691
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
692
693
694
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
695
    }
696
697
698
699
700
701
    if (i == argc-1) {
      log_fn(LOG_WARN,"Command-line option '%s' with no value. Failing.",
             argv[i]);
      config_free_lines(front);
      return -1;
    }
702

703
    *new = tor_malloc_zero(sizeof(config_line_t));
704
    s = argv[i];
705

706
    while (*s == '-')
707
      s++;
708

709
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1));
710
711
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
712
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
713
714
715
        (*new)->key, (*new)->value);

    new = &((*new)->next);
716
717
    i += 2;
  }
718
719
  *result = front;
  return 0;
720
721
}

Nick Mathewson's avatar
Nick Mathewson committed
722
/** Helper: allocate a new configuration option mapping 'key' to 'val',
723
724
 * append it to *<b>lst</b>. */
static void
725
config_line_append(config_line_t **lst,
726
727
                   const char *key,
                   const char *val)
728
{
729
  config_line_t *newline;
730

731
  newline = tor_malloc(sizeof(config_line_t));
732
733
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
734
735
736
737
738
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
739
740
}

741
742
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
743
744
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
745
int
746
config_get_lines(char *string, config_line_t **result)
747
{
748
  config_line_t *list = NULL, **next;
749
  char *k, *v;
750

751
  next = &list;
752
753
754
755
756
757
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
758
759
760
761
    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. */
762
      *next = tor_malloc(sizeof(config_line_t));
763
764
765
766
767
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
768
  } while (*string);
769

770
  *result = list;
771
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
772
773
}

Nick Mathewson's avatar
Nick Mathewson committed
774
775
776
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
777
void
778
config_free_lines(config_line_t *front)
779
{
780
  config_line_t *tmp;
781

782
  while (front) {
783
784
785
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
786
787
788
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
789
790
791
  }
}

792
793
794
795
796
797
798
799
800
801
802
803
/** 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
804
805
806
807
/** 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.
 */
808
static config_var_t *
809
config_find_option(config_format_t *fmt, const char *key)
810
811
{
  int i;
812
  size_t keylen = strlen(key);
813
  if (!keylen)
814
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
815
  /* First, check for an exact (case-insensitive) match */
816
  for (i=0; fmt->vars[i].name; ++i) {
817
    if (!strcasecmp(key, fmt->vars[i].name)) {
818
      return &fmt->vars[i];
819
    }
Nick Mathewson's avatar
Nick Mathewson committed
820
821
  }
  /* If none, check for an abbreviated match */
822
823
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
824
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
825
          "Please use '%s' instead",
826
827
             key, fmt->vars[i].name);
      return &fmt->vars[i];
828
829
    }
  }
830
  /* Okay, unrecognized options */
831
832
833
  return NULL;
}

834
835
836
837
/*
 * Functions to assign config options.
 */

838
839
/** <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.
840
841
 *
 * Called from config_assign_line() and option_reset().
842
 */
843
static int
844
845
config_assign_value(config_format_t *fmt, or_options_t *options,
                    config_line_t *c)
846
{
847
  int i, ok;
848
849
  config_var_t *var;
  void *lvalue;
850

851
852
853
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
854
  tor_assert(var);
855

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

858
  switch (var->type) {
859

860
861
862
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
863
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
864
          c->key,c->value);
865
      return -1;
866
    }
867
    *(int *)lvalue = i;
868
869
    break;

870
871
872
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
873
      return -1;
874
875
876
877
878
879
880
881
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
882
      return -1;
883
884
885
886
887
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

888
889
890
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
891
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
892
      return -1;
893
    }
894
    *(int *)lvalue = i;
895
896
897
    break;

  case CONFIG_TYPE_STRING:
898
899
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
900
901
902
    break;

  case CONFIG_TYPE_DOUBLE:
903
    *(double *)lvalue = atof(c->value);
904
905
    break;

906
907
908
  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);
909
      return -1;
910
911
912
    }
    break;

913
  case CONFIG_TYPE_CSV: