config.c 109 KB
Newer Older
Roger Dingledine's avatar
Roger Dingledine committed
1
2
/* Copyright 2001 Matej Pfajfar.
 * Copyright 2001-2004 Roger Dingledine.
Nick Mathewson's avatar
Nick Mathewson committed
3
 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
4
5
/* See LICENSE for licensing information */
/* $Id$ */
6
const char config_c_id[] = "$Id$";
7

Nick Mathewson's avatar
Nick Mathewson committed
8
/**
9
10
 * \file config.c
 * \brief Code to parse and interpret configuration files.
Nick Mathewson's avatar
Nick Mathewson committed
11
12
 **/

Roger Dingledine's avatar
Roger Dingledine committed
13
#include "or.h"
14
15
16
#ifdef MS_WINDOWS
#include <shlobj.h>
#endif
17
#include "../common/aes.h"
Roger Dingledine's avatar
Roger Dingledine committed
18

Nick Mathewson's avatar
Nick Mathewson committed
19
20
/** Enumeration of types which option values can take */
typedef enum config_type_t {
21
22
  CONFIG_TYPE_STRING = 0,   /**< An arbitrary string. */
  CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
23
24
  CONFIG_TYPE_INTERVAL,     /**< A number of seconds, with optional units*/
  CONFIG_TYPE_MEMUNIT,      /**< A number of bytes, with optional units*/
25
26
  CONFIG_TYPE_DOUBLE,       /**< A floating-point value */
  CONFIG_TYPE_BOOL,         /**< A boolean value, expressed as 0 or 1. */
27
  CONFIG_TYPE_ISOTIME,      /**< An ISO-formated time relative to GMT. */
28
29
30
  CONFIG_TYPE_CSV,          /**< A list of strings, separated by commas and optional
                              * whitespace. */
  CONFIG_TYPE_LINELIST,     /**< Uninterpreted config lines */
31
32
33
34
35
  CONFIG_TYPE_LINELIST_S,   /**< Uninterpreted, context-sensitive config lines,
                             * mixed with other keywords. */
  CONFIG_TYPE_LINELIST_V,   /**< Catch-all "virtual" option to summarize
                             * context-sensitive config lines when fetching.
                             */
36
  CONFIG_TYPE_OBSOLETE,     /**< Obsolete (ignored) option. */
Nick Mathewson's avatar
Nick Mathewson committed
37
} config_type_t;
38

Nick Mathewson's avatar
Nick Mathewson committed
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
156
  /* XXXX 011 change this default on 0.1.1.x */
  VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "1"),
Nick Mathewson's avatar
Nick Mathewson committed
157
158
159
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
160
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
Nick Mathewson's avatar
Nick Mathewson committed
161
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
162
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
163
  VAR("ORPort",              UINT,     ORPort,               "0"),
164
165
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
166
  VAR("PidFile",             STRING,   PidFile,              NULL),
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
195
  /* XXXX 011 change this default on 0.1.1.x */
  VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "1"),
196
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
197
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
198
};
199
200
201
#undef VAR

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

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

219
220
221
#undef VAR
#undef OBSOLETE

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

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

243
244
245
246
247
248
249
250
251
typedef int (*validate_fn_t)(void*);

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;
252
  config_var_description_t *descriptions;
253
254
255
256
257
258
259
} 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
260
/** Largest allowed config line */
261
#define CONFIG_LINE_T_MAXLEN 4096
262

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

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

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

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

314
315
#define OR_OPTIONS_MAGIC 9090909

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

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

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

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

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

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

  return 0;
391
392
}

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

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

415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
/** 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;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

605
606
  init_cookie_authentication(options->CookieAuthentication);

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

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

621
622
623
  if (!running_tor)
    return 0;

624
625
  /* Check for transitions that need action. */
  if (old_options) {
626
627
628
629
630
631
    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();
    }

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

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

645
  return 0;
646
647
648
649
650
651
}

/*
 * Functions to parse config options
 */

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

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

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

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

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

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

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

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

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

  (*lst) = newline;
738
739
}

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

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

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

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

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

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

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

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

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

850
851
852
  CHECK(fmt, options);

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

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

857
  switch (var->type) {
858

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

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

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

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

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

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

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

912
  case CONFIG_TYPE_CSV:
Roger Dingledine's avatar
Roger Dingledine committed
913
    if (*(smartlist_t**)lvalue) {
914
915
916
      SMAR