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
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("ProtocolWarnings",    BOOL,     ProtocolWarnings,     "0"),
167
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
Nick Mathewson's avatar
Nick Mathewson committed
168
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
169
170
  VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions,  NULL),
  VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions,  NULL),
171
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
172
173
174
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
175
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
176
  OBSOLETE("RouterFile"),
177
178
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
179
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
180
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
181
182
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
183
184
185
186
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),  /** DOCDOC */
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
187
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
188
189
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
190
  OBSOLETE("TrafficShaping"),
191
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
192
  VAR("User",                STRING,   User,                 NULL),
193
  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "0"),
194
  VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
195
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
196
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
197
};
198
199
200
#undef VAR

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

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

218
219
220
#undef VAR
#undef OBSOLETE

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

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

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

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

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

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

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

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

316
317
#define OR_OPTIONS_MAGIC 9090909

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

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

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

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

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

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

  return 0;
393
394
}

395
396
397
void
config_free_all(void)
{
398
399
400
401
402
403
404
405
  if (global_options) {
    config_free(&options_format, global_options);
    global_options = NULL;
  }
  if (global_state) {
    config_free(&state_format, global_state);
    global_state = NULL;
  }
406
  tor_free(torrc_fname);
407
408
409
410
  if (reachable_addr_policy) {
    addr_policy_free(reachable_addr_policy);
    reachable_addr_policy = NULL;
  }
411
412
}

413
414
415
416
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
417
418
safe_str(const char *address)
{
419
420
421
422
423
424
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

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
508
509
510
511
512
513
514
515
516
/** 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;
}

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

  clear_trusted_dir_servers();
536
  for (cl = options->DirServers; cl; cl = cl->next) {
537
538
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
539
             "Bug: Previously validated DirServer line could not be added!");
540
      return -1;
541
542
543
    }
  }

544
  if (running_tor && rend_config_services(options, 0)<0) {
545
    log_fn(LOG_ERR,
546
           "Bug: Previously validated hidden services line could not be added!");
547
    return -1;
548
  }
549

550
551
552
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

553
554
555
556
557
558
559
560
561
562
  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;
    }
563
564
    tor_free(fn);
  }
565

566
567
  /* 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. */
568
569
570
  if (options->command != CMD_RUN_TOR)
    return 0;

571
  mark_logs_temp(); /* Close current logs once new logs are open. */
572
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
573
    return -1;
574

575
576
577
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
578
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
579
  control_adjust_event_log_severity();
580

581
582
583
584
585
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

586
587
588
589
590
591
592
593
594
  {
    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);
  }

595
  /* Finish backgrounding the process */
596
  if (running_tor && options->RunAsDaemon) {
597
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
598
    finish_daemon(options->DataDirectory);
599
600
601
602
  }

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

606
607
608
  /* Register addressmap directives */
  config_register_addressmaps(options);

609
610
611
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
612
  parse_authdir_policy();
613
  parse_reachable_addresses();
614

615
616
  init_cookie_authentication(options->CookieAuthentication);

617
618
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
619
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
620
621
622
    return -1;
  }

623
  /* Set up accounting */
624
  if (accounting_parse_options(options, 0)<0) {
625
    log_fn(LOG_ERR,"Error in accounting options");
626
627
    return -1;
  }
628
  if (accounting_is_enabled(options))
629
630
    configure_accounting(time(NULL));

631
632
633
  if (!running_tor)
    return 0;

634
635
  /* Check for transitions that need action. */
  if (old_options) {
636
637
638
639
640
641
    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();
    }

642
643
644
645
646
647
648
    if (options_transition_affects_workers(old_options, options)) {
      log_fn(LOG_INFO,"Worker-related options changed. Rotating workers.");
      cpuworkers_rotate();
      dnsworkers_rotate();
    }
  }

649
  /* Since our options changed, we might need to regenerate and upload our
650
   * server descriptor.
651
   */
652
653
  if (!old_options || options_transition_affects_descriptor(old_options, options))
    mark_my_descriptor_dirty();
654

655
  return 0;
656
657
658
659
660
661
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
662
/** If <b>option</b> is an official abbreviation for a longer option,
663
664
665
 * 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. */
666
static const char *
667
expand_abbrev(config_format_t *fmt, const char *option, int command_line)
668
669
{
  int i;
670
671
672
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
673
    /* Abbreviations aren't casei. */
674
675
676
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
      return fmt->abbrevs[i].full;
677
    }
678
679
680
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
681

682
683
684
685
686
/** 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)
687
{
688
689
  config_line_t *front = NULL;
  config_line_t **new = &front;
690
691
692
  char *s;
  int i = 1;

693
  while (i < argc) {
694
695
696
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
697
      continue;
698
699
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
700
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
701
702
703
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
704
    }
705
706
707
708
709
710
    if (i == argc-1) {
      log_fn(LOG_WARN,"Command-line option '%s' with no value. Failing.",
             argv[i]);
      config_free_lines(front);
      return -1;
    }
711

712
    *new = tor_malloc_zero(sizeof(config_line_t));
713
    s = argv[i];
714

715
    while (*s == '-')
716
      s++;
717

718
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1));
719
720
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
721
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
722
723
724
        (*new)->key, (*new)->value);

    new = &((*new)->next);
725
726
    i += 2;
  }
727
728
  *result = front;
  return 0;
729
730
}

Nick Mathewson's avatar
Nick Mathewson committed
731
/** Helper: allocate a new configuration option mapping 'key' to 'val',
732
733
 * append it to *<b>lst</b>. */
static void
734
config_line_append(config_line_t **lst,
735
736
                   const char *key,
                   const char *val)
737
{
738
  config_line_t *newline;
739

740
  newline = tor_malloc(sizeof(config_line_t));
741
742
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
743
744
745
746
747
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
748
749
}

750
751
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
752
753
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
754
int
755
config_get_lines(char *string, config_line_t **result)
756
{
757
  config_line_t *list = NULL, **next;
758
  char *k, *v;
759

760
  next = &list;
761
762
763
764
765
766
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
767
768
769
770
    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. */
771
      *next = tor_malloc(sizeof(config_line_t));
772
773
774
775
776
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
777
  } while (*string);
778

779
  *result = list;
780
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
781
782
}

Nick Mathewson's avatar
Nick Mathewson committed
783
784
785
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
786
void
787
config_free_lines(config_line_t *front)
788
{
789
  config_line_t *tmp;
790

791
  while (front) {
792
793
794
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
795
796
797
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
798
799
800
  }
}

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

843
844
845
846
/*
 * Functions to assign config options.
 */

847
848
/** <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.
849
850
 *
 * Called from config_assign_line() and option_reset().
851
 */
852
static int
853
854
config_assign_value(config_format_t *fmt, or_options_t *options,
                    config_line_t *c)
855
{
856
  int i, ok;
857
858
  config_var_t *var;
  void *lvalue;
859

860
861
862
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
863
  tor_assert(var);
864

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

867
  switch (var->type) {
868

869
870
871
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
872
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
873
          c->key,c->value);
874
      return -1;
875
    }
876
    *(int *)lvalue = i;
877
878
    break;

879
880
881
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
882
      return -1;
883
884
885
886
887
888
889
890
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
891
      return -1;
892
893
894
895
896
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

897
898
899
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
900
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
901
      return -1;
902
    }
903
    *(int *)lvalue = i;
904
905
906
    break;

  case CONFIG_TYPE_STRING:
907
908
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
909
910
911
    break;

  case CONFIG_TYPE_DOUBLE:
912
    *(double *)lvalue = atof(c->value);
913
914
    break;

915
916
917
  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);
918
      return -1;
919
920
921