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

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
typedef int (*validate_fn_t)(void*);

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

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

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

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

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

317
318
#define OR_OPTIONS_MAGIC 9090909

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

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

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

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

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

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

  return 0;
394
395
}

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

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

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
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.
 *
 * 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;
}

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

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

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

543
544
545
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

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

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

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

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

574
575
576
577
578
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

579
580
581
582
583
584
585
586
587
  {
    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);
  }

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

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

599
600
601
  /* Register addressmap directives */
  config_register_addressmaps(options);

602
603
604
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
605
  parse_authdir_policy();
606
  parse_reachable_addresses();
607

608
609
  init_cookie_authentication(options->CookieAuthentication);

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

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

624
625
626
  if (!running_tor)
    return 0;

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

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

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

648
  return 0;
649
650
651
652
653
654
}

/*
 * Functions to parse config options
 */

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

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

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

705
    *new = tor_malloc_zero(sizeof(config_line_t));
706
    s = argv[i];
707

708
    while (*s == '-')
709
      s++;
710

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

    new = &((*new)->next);
718
719
    i += 2;
  }
720
721
  *result = front;
  return 0;
722
723
}

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

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

  (*lst) = newline;
741
742
}

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

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

772
  *result = list;
773
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
774
775
}

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

784
  while (front) {
785
786
787
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
788
789
790
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
791
792
793
  }
}

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

836
837
838
839
/*
 * Functions to assign config options.
 */

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

853
854
855
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
856
  tor_assert(var);
857

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

860
  switch (var->type) {
861

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

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

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

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

  case CONFIG_TYPE_STRING:
900
901
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
902
903
904
    break;

  case CONFIG_TYPE_DOUBLE:
905
    *(double *)lvalue = atof(c->value);
906
907
    break;

908
909
910
  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);
911
      return -1;
912
913
914
    }
    break;

915
  case CONFIG_TYPE_CSV:
Roger Dingledine's avatar
Roger Dingledine committed
916
    if (*(smartlist_t**)lvalue) {
917
918
919