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, 0},
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, 0},
  { "DirBindAddress", "DirListenAddress", 0, 0},
  { "SocksBindAddress", "SocksListenAddress", 0, 0},
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),
194
  VAR("TestSocks",           BOOL,     TestSocks,            "0"),
Nick Mathewson's avatar
Nick Mathewson committed
195
196
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
197
  OBSOLETE("TrafficShaping"),
198
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
199
  VAR("User",                STRING,   User,                 NULL),
200
  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "0"),
201
  VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
202
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
203
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
204
};
205
206
207
#undef VAR

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

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

225
226
227
#undef VAR
#undef OBSOLETE

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

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

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

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

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

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

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

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

323
324
#define OR_OPTIONS_MAGIC 9090909

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

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

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

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

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

377
378
379
/** 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.
380
 */
381
int
382
383
set_options(or_options_t *new_val)
{
384
  or_options_t *old_options = global_options;
385
  global_options = new_val;
386
387
  /* Note that we pass the *old* options below, for comparison. It
   * pulls the new options directly out of global_options. */
388
389
390
391
  if (options_act_reversible(old_options)<0) {
    global_options = old_options;
    return -1;
  }
392
  if (options_act(old_options) < 0) { /* acting on the options failed. die. */
393
394
    err(LD_CONFIG,
        "Acting on config options left us in a broken state. Dying.");
395
396
397
    exit(1);
  }
  if (old_options)
398
    config_free(&options_format, old_options);
399
400

  return 0;
401
402
}

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

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

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
/** 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) {
472
    err(LD_FS, "Couldn't access/create private data directory \"%s\"",
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
           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) {
490
    err(LD_CONFIG, "Failed to bind one of the listener ports.");
491
492
493
494
495
496
497
    goto rollback;
  }

 commit:
  r = 0;
  SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn,
  {
498
    notice(LD_NET, "Closing old %s on %s:%d",
499
500
501
502
503
504
505
506
507
508
509
510
511
512
           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,
  {
513
    notice(LD_NET, "Closing %s on %s:%d",
514
515
516
517
518
519
520
521
522
523
524
           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;
}

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

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

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

558
559
560
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

561
562
563
564
565
  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) {
566
567
      err(LD_CONFIG,
          "Couldn't access/create private data directory \"%s\"", fn);
568
569
570
      tor_free(fn);
      return -1;
    }
571
572
    tor_free(fn);
  }
573

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

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

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

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

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

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

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

614
615
616
  /* Register addressmap directives */
  config_register_addressmaps(options);

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

623
624
  init_cookie_authentication(options->CookieAuthentication);

625
626
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
627
    err(LD_GENERAL,"Error loading rendezvous service keys");
628
629
630
    return -1;
  }

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

639
640
641
  if (!running_tor)
    return 0;

642
643
  /* Check for transitions that need action. */
  if (old_options) {
644
    if (options->UseHelperNodes && !old_options->UseHelperNodes) {
645
      info(LD_CIRC,"Switching to helper nodes; abandoning previous circuits");
646
647
648
649
      circuit_mark_all_unused_circs();
      circuit_expire_all_dirty_circs();
    }

650
    if (options_transition_affects_workers(old_options, options)) {
651
      info(LD_GENERAL,"Worker-related options changed. Rotating workers.");
652
653
654
655
656
      cpuworkers_rotate();
      dnsworkers_rotate();
    }
  }

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

663
  return 0;
664
665
666
667
668
669
}

/*
 * Functions to parse config options
 */

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

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

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

728
    *new = tor_malloc_zero(sizeof(config_line_t));
729
    s = argv[i];
730

731
    while (*s == '-')
732
      s++;
733

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

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

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

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

  (*lst) = newline;
764
765
}

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

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

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

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

807
  while (front) {
808
809
810
    tmp = front;
    front = tmp->next;

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

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

859
860
861
862
/*
 * Functions to assign config options.
 */

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

876
877
878
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
879
  tor_assert(var);
880

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

883
  switch (var->type) {
884

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