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, 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
  if (options_act(old_options) < 0) { /* acting on the options failed. die. */
392
393
    err(LD_CONFIG,
        "Acting on config options left us in a broken state. Dying.");
394
395
396
    exit(1);
  }
  if (old_options)
397
    config_free(&options_format, old_options);
398
399

  return 0;
400
401
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

622
623
  init_cookie_authentication(options->CookieAuthentication);

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

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

638
639
640
  if (!running_tor)
    return 0;

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

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

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

662
  return 0;
663
664
665
666
667
668
}

/*
 * Functions to parse config options
 */

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

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

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

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

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

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

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

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

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

  (*lst) = newline;
763
764
}

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

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

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

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

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

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

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

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

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

875
876
877
  CHECK(fmt, options);

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

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

882
  switch (var->type) {
883

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