config.c 110 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
  int warn;
45
46
} config_abbrev_t;

47
48
/* Handy macro for declaring "In the config file or on the command line,
 * you can abbreviate <b>tok</b>s as <b>tok</b>". */
49
#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
50

Nick Mathewson's avatar
Nick Mathewson committed
51
/* A list of command-line abbreviations. */
52
static config_abbrev_t _option_abbrevs[] = {
53
  PLURAL(ExitNode),
54
  PLURAL(EntryNode),
55
56
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
57
  PLURAL(LongLivedPort),
58
59
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
60
  PLURAL(NumCpu),
61
62
  PLURAL(RendNode),
  PLURAL(RendExcludeNode),
63
64
  PLURAL(StrictEntryNode),
  PLURAL(StrictExitNode),
65
  { "l", "Log", 1},
66
67
68
69
  { "BandwidthRateBytes", "BandwidthRate", 0, 0},
  { "BandwidthBurstBytes", "BandwidthBurst", 0, 0},
  { "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0},
  { "MaxConn", "ConnLimit", 0, 1},
70
71
72
  { "ORBindAddress", "ORListenAddress", 0, 1},
  { "DirBindAddress", "DirListenAddress", 0, 1},
  { "SocksBindAddress", "SocksListenAddress", 0, 1},
73
  { NULL, NULL, 0, 0},
74
};
75
#undef PLURAL
76

77
/** A variable allowed in the configuration file or on the command line. */
78
typedef struct config_var_t {
79
80
81
82
  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. */
83
  const char *description;
84
85
} config_var_t;

Nick Mathewson's avatar
Nick Mathewson committed
86
/** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
Nick Mathewson's avatar
Nick Mathewson committed
87
#define STRUCT_OFFSET(tp, member) ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
Nick Mathewson's avatar
Nick Mathewson committed
88
89
90
91
/** 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>"
 */
92
#define VAR(name,conftype,member,initvalue)                            \
93
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member), initvalue, NULL }
Nick Mathewson's avatar
Nick Mathewson committed
94
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
95
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
96

Nick Mathewson's avatar
Nick Mathewson committed
97
98
99
100
/** Array of configuration options.  Until we disallow nonstandard
 * abbreviations, order is significant, since the first matching option will
 * be chosen first.
 */
101
static config_var_t _option_vars[] = {
Roger Dingledine's avatar
Roger Dingledine committed
102
  VAR("AccountingMax",       MEMUNIT,  AccountingMax,        "0 bytes"),
Nick Mathewson's avatar
Nick Mathewson committed
103
  VAR("AccountingMaxKB",     UINT,     _AccountingMaxKB,     "0"),
104
  VAR("AccountingStart",     STRING,   AccountingStart,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
105
  VAR("Address",             STRING,   Address,              NULL),
106
  VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes, "middle,rendezvous"),
107
  VAR("AssumeReachable",     BOOL,     AssumeReachable,      "0"),
108
109
  VAR("AuthDirInvalid",      LINELIST, AuthDirInvalid,       NULL),
  VAR("AuthDirReject",       LINELIST, AuthDirReject,        NULL),
110
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
111
  VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "5 MB"),
Nick Mathewson's avatar
Nick Mathewson committed
112
  VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "2 MB"),
113
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
Nick Mathewson's avatar
Nick Mathewson committed
114
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
115
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
116
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
117
  VAR("CookieAuthentication",BOOL,     CookieAuthentication, "0"),
118
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
119
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
120
  VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
121
122
123
  VAR("DirListenAddress",    LINELIST, DirListenAddress,     NULL),
  /* if DirFetchPeriod is 0, see get_dir_fetch_period() in main.c */
  VAR("DirFetchPeriod",      INTERVAL, DirFetchPeriod,       "0 seconds"),
124
  VAR("DirPolicy",           LINELIST, DirPolicy,            NULL),
Nick Mathewson's avatar
Nick Mathewson committed
125
  VAR("DirPort",             UINT,     DirPort,              "0"),
126
  OBSOLETE("DirPostPeriod"),
127
128
129
  VAR("DirServer",           LINELIST, DirServers,           NULL),
  VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
130
131
  VAR("ExitNodes",           STRING,   ExitNodes,            NULL),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
132
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
133
  VAR("FirewallPorts",       CSV,      FirewallPorts,        ""),
134
  VAR("Group",               STRING,   Group,                NULL),
Nick Mathewson's avatar
Nick Mathewson committed
135
  VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
136
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
137
138
139
140
141
  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),
142
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
143
  VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL),
144
  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
145
  VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL),
146
  OBSOLETE("IgnoreVersion"),
147
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
148
  VAR("Log",                 LINELIST, Logs,                 NULL),
149
  OBSOLETE("LinkPadding"),
Nick Mathewson's avatar
Nick Mathewson committed
150
151
152
153
154
155
  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"),
156
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
157
  OBSOLETE("MonthlyAccountingStart"),
Nick Mathewson's avatar
Nick Mathewson committed
158
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
159
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
160
  VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
Nick Mathewson's avatar
Nick Mathewson committed
161
162
163
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
164
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
Nick Mathewson's avatar
Nick Mathewson committed
165
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
166
  VAR("ORListenAddress",     LINELIST, ORListenAddress,     NULL),
Nick Mathewson's avatar
Nick Mathewson committed
167
  VAR("ORPort",              UINT,     ORPort,               "0"),
168
169
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
170
  VAR("PidFile",             STRING,   PidFile,              NULL),
171
  VAR("ProtocolWarnings",    BOOL,     ProtocolWarnings,     "0"),
172
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
Nick Mathewson's avatar
Nick Mathewson committed
173
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
174
175
  VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions,  NULL),
  VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions,  NULL),
176
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
177
178
179
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
180
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
181
  OBSOLETE("RouterFile"),
182
183
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
184
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
185
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
186
  VAR("SocksListenAddress",  LINELIST, SocksListenAddress,   NULL),
187
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
188
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
189
190
  /* if StatusFetchPeriod is 0, see get_status_fetch_period() in main.c */
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),
Nick Mathewson's avatar
Nick Mathewson committed
191
192
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
193
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
194
195
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
196
  OBSOLETE("TrafficShaping"),
197
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
198
  VAR("User",                STRING,   User,                 NULL),
199
  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "0"),
200
  VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
201
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
202
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
203
};
204
205
206
#undef VAR

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

221
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
222
223
};

224
225
226
#undef VAR
#undef OBSOLETE

227
228
229
230
231
232
233
/** DOCDOC*/
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

static config_var_description_t options_description[] = {
234
  { "Address", "The advertised (external) address we should use." },
235
236
237
238
239
240
241
242
243
244
245
246
247
  // { "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 },
};

248
249
typedef int (*validate_fn_t)(void*);

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

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

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

311
312
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
313
static void print_cvs_version(void);
314
static void parse_reachable_addresses(void);
315
static int init_libevent(void);
316
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
317
static void check_libevent_version(const char *m, const char *v, int server);
318
#endif
319

320
321
/*static*/ or_options_t *options_new(void);

322
323
#define OR_OPTIONS_MAGIC 9090909

324
static config_format_t options_format = {
325
326
327
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  _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
344
345
};

346
347
348
349
350
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
351
static or_options_t *global_options = NULL;
Roger Dingledine's avatar
Roger Dingledine committed
352
/** Name of most recently read torrc file. */
353
static char *torrc_fname = NULL;
354
355
/** Persistant serialized state. */
static or_state_t *global_state = NULL;
356
357
/** DOCDOC */
static addr_policy_t *reachable_addr_policy = NULL;
358

359
360
361
362
363
364
365
366
367
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;
}

368
369
/** Return the currently configured options. */
or_options_t *
370
371
get_options(void)
{
372
373
374
  tor_assert(global_options);
  return global_options;
}
375

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

  return 0;
399
400
}

401
402
403
void
config_free_all(void)
{
404
405
406
407
408
409
410
411
  if (global_options) {
    config_free(&options_format, global_options);
    global_options = NULL;
  }
  if (global_state) {
    config_free(&state_format, global_state);
    global_state = NULL;
  }
412
  tor_free(torrc_fname);
413
414
415
416
  if (reachable_addr_policy) {
    addr_policy_free(reachable_addr_policy);
    reachable_addr_policy = NULL;
  }
417
418
}

419
420
421
422
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
423
424
safe_str(const char *address)
{
425
426
427
428
429
430
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

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
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
/** 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;
}

523
524
525
/** 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.
526
 *
527
 * Return 0 if all goes well, return -1 if it's time to die.
528
529
530
 *
 * Note 2: We haven't moved all the "act on new configuration" logic
 * here yet.  Some is still in do_hup() and other places.
531
 */
532
533
static int
options_act(or_options_t *old_options)
534
{
535
  config_line_t *cl;
536
537
  char *fn;
  size_t len;
538
  or_options_t *options = get_options();
539
  int running_tor = options->command == CMD_RUN_TOR;
540
541

  clear_trusted_dir_servers();
542
  for (cl = options->DirServers; cl; cl = cl->next) {
543
544
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
545
             "Bug: Previously validated DirServer line could not be added!");
546
      return -1;
547
548
549
    }
  }

550
  if (running_tor && rend_config_services(options, 0)<0) {
551
    log_fn(LOG_ERR,
552
           "Bug: Previously validated hidden services line could not be added!");
553
    return -1;
554
  }
555

556
557
558
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

559
560
561
562
563
564
565
566
567
568
  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;
    }
569
570
    tor_free(fn);
  }
571

572
573
  /* 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. */
574
575
576
  if (options->command != CMD_RUN_TOR)
    return 0;

577
  mark_logs_temp(); /* Close current logs once new logs are open. */
578
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
579
    return -1;
580

581
582
583
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
584
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
585
  control_adjust_event_log_severity();
586

587
588
589
590
591
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

592
593
594
595
596
597
598
599
600
  {
    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);
  }

601
  /* Finish backgrounding the process */
602
  if (running_tor && options->RunAsDaemon) {
603
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
604
    finish_daemon(options->DataDirectory);
605
606
607
608
  }

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

612
613
614
  /* Register addressmap directives */
  config_register_addressmaps(options);

615
616
617
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
618
  parse_authdir_policy();
619
  parse_reachable_addresses();
620

621
622
  init_cookie_authentication(options->CookieAuthentication);

623
624
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
625
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
626
627
628
    return -1;
  }

629
  /* Set up accounting */
630
  if (accounting_parse_options(options, 0)<0) {
631
    log_fn(LOG_ERR,"Error in accounting options");
632
633
    return -1;
  }
634
  if (accounting_is_enabled(options))
635
636
    configure_accounting(time(NULL));

637
638
639
  if (!running_tor)
    return 0;

640
641
  /* Check for transitions that need action. */
  if (old_options) {
642
643
644
645
646
647
    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();
    }

648
649
650
651
652
653
654
    if (options_transition_affects_workers(old_options, options)) {
      log_fn(LOG_INFO,"Worker-related options changed. Rotating workers.");
      cpuworkers_rotate();
      dnsworkers_rotate();
    }
  }

655
  /* Since our options changed, we might need to regenerate and upload our
656
   * server descriptor.
657
   */
658
659
  if (!old_options || options_transition_affects_descriptor(old_options, options))
    mark_my_descriptor_dirty();
660

661
  return 0;
662
663
664
665
666
667
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
668
/** If <b>option</b> is an official abbreviation for a longer option,
669
670
 * return the longer option.  Otherwise return <b>option</b>.
 * If <b>command_line</b> is set, apply all abbreviations.  Otherwise, only
671
672
 * apply abbreviations that work for the config file and the command line.
 * If <b>warn_obsolete</b> is set, warn about deprecated names. */
673
static const char *
674
675
expand_abbrev(config_format_t *fmt, const char *option, int command_line,
              int warn_obsolete)
676
677
{
  int i;
678
679
680
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
681
    /* Abbreviations are casei. */
682
683
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
684
685
686
687
688
689
      if (warn_obsolete && fmt->abbrevs[i].warn) {
        log_fn(LOG_WARN,
            "The configuration option '%s' is deprecated; use '%s' instead.",
               fmt->abbrevs[i].abbreviated,
               fmt->abbrevs[i].full);
      }
690
      return fmt->abbrevs[i].full;
691
    }
692
693
694
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
695

696
697
698
699
700
/** 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)
701
{
702
703
  config_line_t *front = NULL;
  config_line_t **new = &front;
704
705
706
  char *s;
  int i = 1;

707
  while (i < argc) {
708
709
710
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
711
      continue;
712
713
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
714
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
715
716
717
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
718
    }
719
720
721
722
723
724
    if (i == argc-1) {
      log_fn(LOG_WARN,"Command-line option '%s' with no value. Failing.",
             argv[i]);
      config_free_lines(front);
      return -1;
    }
725

726
    *new = tor_malloc_zero(sizeof(config_line_t));
727
    s = argv[i];
728

729
    while (*s == '-')
730
      s++;
731

732
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1, 1));
733
734
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
735
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
736
737
738
        (*new)->key, (*new)->value);

    new = &((*new)->next);
739
740
    i += 2;
  }
741
742
  *result = front;
  return 0;
743
744
}

Nick Mathewson's avatar
Nick Mathewson committed
745
/** Helper: allocate a new configuration option mapping 'key' to 'val',
746
747
 * append it to *<b>lst</b>. */
static void
748
config_line_append(config_line_t **lst,
749
750
                   const char *key,
                   const char *val)
751
{
752
  config_line_t *newline;
753

754
  newline = tor_malloc(sizeof(config_line_t));
755
756
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
757
758
759
760
761
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
762
763
}

764
765
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
766
767
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
768
int
769
config_get_lines(char *string, config_line_t **result)
770
{
771
  config_line_t *list = NULL, **next;
772
  char *k, *v;
773

774
  next = &list;
775
776
777
778
779
780
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
781
782
783
784
    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. */
785
      *next = tor_malloc(sizeof(config_line_t));
786
787
788
789
790
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
791
  } while (*string);
792

793
  *result = list;
794
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
795
796
}

Nick Mathewson's avatar
Nick Mathewson committed
797
798
799
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
800
void
801
config_free_lines(config_line_t *front)
802
{
803
  config_line_t *tmp;
804

805
  while (front) {
806
807
808
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
809
810
811
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
812
813
814
  }
}

815
816
817
818
819
820
821
822
823
824
825
826
/** 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
827
828
829
830
/** 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.
 */
831
static config_var_t *
832
config_find_option(config_format_t *fmt, const char *key)
833
834
{
  int i;
835
  size_t keylen = strlen(key);
836
  if (!keylen)
837
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
838
  /* First, check for an exact (case-insensitive) match */
839
  for (i=0; fmt->vars[i].name; ++i) {
840
    if (!strcasecmp(key, fmt->vars[i].name)) {
841
      return &fmt->vars[i];
842
    }
Nick Mathewson's avatar
Nick Mathewson committed
843
844
  }
  /* If none, check for an abbreviated match */
845
846
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
847
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
848
          "Please use '%s' instead",
849
850
             key, fmt->vars[i].name);
      return &fmt->vars[i];
851
852
    }
  }
853
  /* Okay, unrecognized options */
854
855
856
  return NULL;
}

857
858
859
860
/*
 * Functions to assign config options.
 */

861
862
/** <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.
863
864
 *
 * Called from config_assign_line() and option_reset().
865
 */
866
static int
867
868
config_assign_value(config_format_t *fmt, or_options_t *options,
                    config_line_t *c)
869
{
870
  int i, ok;
871
872
  config_var_t *var;
  void *lvalue;
873

874
875
876
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
877
  tor_assert(var);
878

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

881
  switch (var->type) {
882

883
884
885
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
886
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
887
          c->key,c->value);
888
      return -1;
889
    }
890
    *(int *)lvalue = i;
891
892
    break;

893
894
895
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
896
      return -1;
897
898
899
900
901
902
903
904
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
905
      return -1;
906
907
908
909
910
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

911
912
913
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
914
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
915
      return -1;
916
    }
917
    *(int *)lvalue = i;
918
919
920
    break;

  case CONFIG_TYPE