config.c 102 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 }
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 }
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[] = {
Nick Mathewson's avatar
Nick Mathewson committed
98
99
  VAR("AccountingMax",       MEMUNIT,   AccountingMax,        "0 bytes"),
  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
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
105
  VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "5 MB"),
Nick Mathewson's avatar
Nick Mathewson committed
106
  VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "2 MB"),
107
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
Nick Mathewson's avatar
Nick Mathewson committed
108
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
109
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
110
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
111
  VAR("CookieAuthentication",BOOL,     CookieAuthentication, "0"),
112
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
113
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
114
  VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
115
  VAR("DirBindAddress",      LINELIST, DirBindAddress,       NULL),
Nick Mathewson's avatar
Nick Mathewson committed
116
  VAR("DirFetchPeriod",      INTERVAL, DirFetchPeriod,       "0 seconds"),  /** DOCDOC **/
117
  VAR("DirPolicy",           LINELIST, DirPolicy,            NULL),
Nick Mathewson's avatar
Nick Mathewson committed
118
  VAR("DirPort",             UINT,     DirPort,              "0"),
119
  OBSOLETE("DirPostPeriod"),
120
121
122
  VAR("DirServer",           LINELIST, DirServers,           NULL),
  VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
123
124
  VAR("ExitNodes",           STRING,   ExitNodes,            NULL),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
125
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
126
  VAR("FirewallPorts",       CSV,      FirewallPorts,        ""),
127
  VAR("Group",               STRING,   Group,                NULL),
Nick Mathewson's avatar
Nick Mathewson committed
128
  VAR("HardwareAccel",       BOOL,     HardwareAccel,        "1"),
129
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
130
131
132
133
134
  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),
135
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
136
  VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL),
137
  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
138
  VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL),
139
  OBSOLETE("IgnoreVersion"),
140
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
141
  VAR("Log",                 LINELIST, Logs,                 NULL),
142
  OBSOLETE("LinkPadding"),
Nick Mathewson's avatar
Nick Mathewson committed
143
144
145
146
147
148
  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"),
149
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
150
  OBSOLETE("MonthlyAccountingStart"),
Nick Mathewson's avatar
Nick Mathewson committed
151
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
152
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
Nick Mathewson's avatar
Nick Mathewson committed
153
154
155
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
156
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
Nick Mathewson's avatar
Nick Mathewson committed
157
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
158
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
159
  VAR("ORPort",              UINT,     ORPort,               "0"),
160
161
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
162
  VAR("PidFile",             STRING,   PidFile,              NULL),
163
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
Nick Mathewson's avatar
Nick Mathewson committed
164
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
165
166
  VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions,  NULL),
  VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions,  NULL),
167
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
168
169
170
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
171
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
172
  OBSOLETE("RouterFile"),
173
174
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
175
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
176
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
177
178
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
179
180
181
182
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),  /** DOCDOC */
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
183
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
184
185
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
186
  OBSOLETE("TrafficShaping"),
187
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
188
  VAR("User",                STRING,   User,                 NULL),
189
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
190
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
191
};
192
193
194
195
196
#undef VAR

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

209
210
211
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};

212
213
214
#undef VAR
#undef OBSOLETE

215
216
217
218
219
220
221
/** DOCDOC*/
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

static config_var_description_t options_description[] = {
222
  { "Address", "The advertised (external) address we should use." },
223
224
225
226
227
228
229
230
231
232
233
234
235
  // { "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 },
};

236
237
238
239
240
241
242
243
244
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;
245
  config_var_description_t *descriptions;
246
247
248
249
250
251
252
} 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
253
/** Largest allowed config line */
254
#define CONFIG_LINE_T_MAXLEN 4096
255

256
static void config_line_append(config_line_t **lst,
257
                               const char *key, const char *val);
258
259
static void option_reset(config_format_t *fmt, or_options_t *options,
                         config_var_t *var);
260
static void config_free(config_format_t *fmt, void *options);
261
262
263
static int option_is_same(config_format_t *fmt,
                          or_options_t *o1, or_options_t *o2,const char *name);
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
264
static int options_validate(or_options_t *options);
265
static int options_act(or_options_t *old_options);
266
static int options_transition_allowed(or_options_t *old, or_options_t *new);
267
268
269
270
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);
271
static int check_nickname_list(const char *lst, const char *name);
272
static void config_register_addressmaps(or_options_t *options);
273

274
static int parse_dir_server_line(const char *line, int validate_only);
275
static int parse_redirect_line(smartlist_t *result,
276
                               config_line_t *line);
277
278
279
static int parse_log_severity_range(const char *range, int *min_out,
                                    int *max_out);
static int convert_log_option(or_options_t *options,
280
281
                              config_line_t *level_opt,
                              config_line_t *file_opt, int isDaemon);
282
283
284
285
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);
286
static int validate_data_directory(or_options_t *options);
287
static int write_configuration_file(const char *fname, or_options_t *options);
288
static config_line_t *get_assigned_option(config_format_t *fmt,
289
                                     or_options_t *options, const char *key);
290
291
static void config_init(config_format_t *fmt, void *options);
static int or_state_validate(or_state_t *options);
292

293
294
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
295
static void print_cvs_version(void);
296
static void parse_reachable_addresses(void);
297
static int init_libevent(void);
298
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
299
static void check_libevent_version(const char *m, const char *v, int server);
300
#endif
301

302
303
/*static*/ or_options_t *options_new(void);

304
305
#define OR_OPTIONS_MAGIC 9090909

306
static config_format_t options_format = {
307
308
309
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  _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
326
327
};

328
329
330
331
332
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
333
static or_options_t *global_options = NULL;
Roger Dingledine's avatar
Roger Dingledine committed
334
/** Name of most recently read torrc file. */
335
static char *torrc_fname = NULL;
336
337
/** Persistant serialized state. */
static or_state_t *global_state = NULL;
338
339
/** DOCDOC */
static addr_policy_t *reachable_addr_policy = NULL;
340

341
342
343
344
345
346
347
348
349
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;
}

350
351
/** Return the currently configured options. */
or_options_t *
352
353
get_options(void)
{
354
355
356
  tor_assert(global_options);
  return global_options;
}
357

358
359
360
/** 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.
361
362
 */
void
363
364
set_options(or_options_t *new_val)
{
365
  or_options_t *old_options = global_options;
366
  global_options = new_val;
367
368
369
370
371
372
  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)
    config_free(&options_format, global_options);
373
374
}

375
376
377
void
config_free_all(void)
{
378
  config_free(&options_format, global_options);
379
  tor_free(torrc_fname);
380
381
  addr_policy_free(reachable_addr_policy);
  reachable_addr_policy = NULL;
382
383
}

384
385
386
387
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
388
389
safe_str(const char *address)
{
390
391
392
393
394
395
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

396
397
398
/** 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.
399
 *
400
 * Return 0 if all goes well, return -1 if it's time to die.
401
402
403
 *
 * Note 2: We haven't moved all the "act on new configuration" logic
 * here yet.  Some is still in do_hup() and other places.
404
 */
405
406
static int
options_act(or_options_t *old_options)
407
{
408
  config_line_t *cl;
409
  or_options_t *options = get_options();
410
411
412
  static int libevent_initialized = 0;

  if (options->RunAsDaemon) {
413
    start_daemon();
414
  }
415
416

  clear_trusted_dir_servers();
417
  for (cl = options->DirServers; cl; cl = cl->next) {
418
419
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
420
             "Bug: Previously validated DirServer line could not be added!");
421
      return -1;
422
423
424
    }
  }

425
  if (rend_config_services(options, 0)<0) {
426
    log_fn(LOG_ERR,
427
           "Bug: Previously validated hidden services line could not be added!");
428
    return -1;
429
  }
430

431
432
433
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

434
  /* Setuid/setgid as appropriate */
435
436
  if (options->User || options->Group) {
    if (switch_id(options->User, options->Group) != 0) {
437
438
439
440
441
      return -1;
    }
  }

  /* Ensure data directory is private; create if possible. */
442
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
443
    log_fn(LOG_ERR, "Couldn't access/create private data directory \"%s\"",
444
           options->DataDirectory);
445
446
447
    return -1;
  }

448
449
  /* 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. */
450
451
452
  if (options->command != CMD_RUN_TOR)
    return 0;

453
  mark_logs_temp(); /* Close current logs once new logs are open. */
454
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
455
    return -1;
456

457
458
459
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
460
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
461
  control_adjust_event_log_severity();
462

463
464
465
466
467
468
469
  /* Set up libevent. */
  if (!libevent_initialized) {
    if (init_libevent())
      return -1;
    libevent_initialized = 1;
  }

470
471
472
473
474
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

475
  options->_ConnLimit =
476
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
477
  if (options->_ConnLimit < 0)
478
479
    return -1;

480
481
482
483
484
485
486
487
488
  {
    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);
  }

489
  /* Finish backgrounding the process */
490
  if (options->RunAsDaemon) {
491
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
492
    finish_daemon(options->DataDirectory);
493
494
495
496
  }

  /* Write our pid to the pid file. If we do not have write permissions we
   * will log a warning */
497
  if (options->PidFile)
498
499
    write_pidfile(options->PidFile);

500
501
502
  /* Register addressmap directives */
  config_register_addressmaps(options);

503
504
505
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
506
  parse_reachable_addresses();
507

508
509
  init_cookie_authentication(options->CookieAuthentication);

510
511
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
512
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
513
514
515
    return -1;
  }

516
  /* Set up accounting */
517
  if (accounting_parse_options(options, 0)<0) {
518
    log_fn(LOG_ERR,"Error in accounting options");
519
520
    return -1;
  }
521
  if (accounting_is_enabled(options))
522
523
    configure_accounting(time(NULL));

524
  if (!we_are_hibernating() && retry_all_listeners(0) < 0) {
525
526
527
528
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    return -1;
  }

529
530
531
532
533
534
535
536
537
  /* Check for transitions that need action. */
  if (old_options) {
    if (options_transition_affects_workers(old_options, options)) {
      log_fn(LOG_INFO,"Worker-related options changed. Rotating workers.");
      cpuworkers_rotate();
      dnsworkers_rotate();
    }
  }

538
  /* Since our options changed, we might need to regenerate and upload our
539
   * server descriptor.
540
   */
541
542
  if (!old_options || options_transition_affects_descriptor(old_options, options))
    mark_my_descriptor_dirty();
543

544
  return 0;
545
546
547
548
549
550
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
551
/** If <b>option</b> is an official abbreviation for a longer option,
552
553
554
 * 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. */
555
static const char *
556
expand_abbrev(config_format_t *fmt, const char *option, int command_line)
557
558
{
  int i;
559
560
561
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
562
    /* Abbreviations aren't casei. */
563
564
565
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
      return fmt->abbrevs[i].full;
566
    }
567
568
569
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
570

Nick Mathewson's avatar
Nick Mathewson committed
571
/** Helper: Read a list of configuration options from the command line. */
572
static config_line_t *
573
574
config_get_commandlines(int argc, char **argv)
{
575
576
  config_line_t *front = NULL;
  config_line_t **new = &front;
577
578
579
  char *s;
  int i = 1;

580
  while (i < argc-1) {
581
582
583
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
584
      continue;
585
586
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
587
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
588
589
590
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
591
592
    }

593
    *new = tor_malloc_zero(sizeof(config_line_t));
594
    s = argv[i];
595

596
    while (*s == '-')
597
      s++;
598

599
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1));
600
601
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
602
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
603
604
605
        (*new)->key, (*new)->value);

    new = &((*new)->next);
606
607
608
609
610
    i += 2;
  }
  return front;
}

Nick Mathewson's avatar
Nick Mathewson committed
611
/** Helper: allocate a new configuration option mapping 'key' to 'val',
612
613
 * append it to *<b>lst</b>. */
static void
614
config_line_append(config_line_t **lst,
615
616
                   const char *key,
                   const char *val)
617
{
618
  config_line_t *newline;
619

620
  newline = tor_malloc(sizeof(config_line_t));
621
622
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
623
624
625
626
627
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
628
629
}

630
631
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
632
633
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
634
int
635
config_get_lines(char *string, config_line_t **result)
636
{
637
  config_line_t *list = NULL, **next;
638
  char *k, *v;
639

640
  next = &list;
641
642
643
644
645
646
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
647
648
649
650
    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. */
651
      *next = tor_malloc(sizeof(config_line_t));
652
653
654
655
656
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
657
  } while (*string);
658

659
  *result = list;
660
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
661
662
}

Nick Mathewson's avatar
Nick Mathewson committed
663
664
665
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
666
void
667
config_free_lines(config_line_t *front)
668
{
669
  config_line_t *tmp;
670

671
  while (front) {
672
673
674
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
675
676
677
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
678
679
680
  }
}

681
682
683
684
685
686
687
688
689
690
691
692
/** 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
693
694
695
696
/** 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.
 */
697
static config_var_t *
698
config_find_option(config_format_t *fmt, const char *key)
699
700
{
  int i;
701
  size_t keylen = strlen(key);
702
  if (!keylen)
703
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
704
  /* First, check for an exact (case-insensitive) match */
705
  for (i=0; fmt->vars[i].name; ++i) {
706
    if (!strcasecmp(key, fmt->vars[i].name)) {
707
      return &fmt->vars[i];
708
    }
Nick Mathewson's avatar
Nick Mathewson committed
709
710
  }
  /* If none, check for an abbreviated match */
711
712
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
713
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
714
          "Please use '%s' instead",
715
716
             key, fmt->vars[i].name);
      return &fmt->vars[i];
717
718
    }
  }
719
  /* Okay, unrecognized options */
720
721
722
  return NULL;
}

Nick Mathewson's avatar
Nick Mathewson committed
723
/** If <b>c</b> is a syntactically valid configuration line, update
724
725
 * <b>options</b> with its value and return 0.  Otherwise return -1 for bad key,
 * -2 for bad value.
726
727
728
729
 *
 * If 'reset' is set, and we get a line containing no value, restore the
 * option to its default value.
 */
730
static int
731
config_assign_line(config_format_t *fmt,
732
                   or_options_t *options, config_line_t *c, int reset)
733
{
734
  int i, ok;
735
736
  config_var_t *var;
  void *lvalue;
737

738
739
740
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
741
742
743
744
745
746
  if (!var) {
    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", c->key);
    return -1;
  }
  /* Put keyword into canonical case. */
  if (strcmp(var->name, c->key)) {
747
    tor_free(c->key);
748
    c->key = tor_strdup(var->name);
749
750
  }

751
  if (reset && !strlen(c->value)) {
752
    option_reset(fmt, options, var);
753
754
755
    return 0;
  }

Nick Mathewson's avatar
Nick Mathewson committed
756
  lvalue = ((char*)options) + var->var_offset;
757
  switch (var->type) {
758

759
760
761
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
762
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
763
          c->key,c->value);
764
      return -2;
765
    }
766
    *(int *)lvalue = i;
767
768
    break;

769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
      return -2;
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
      return -2;
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

787
788
789
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
790
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
791
      return -2;
792
    }
793
    *(int *)lvalue = i;
794
795
796
    break;

  case CONFIG_TYPE_STRING:
797
798
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
799
800
801
    break;

  case CONFIG_TYPE_DOUBLE:
802
    *(double *)lvalue = atof(c->value);
803
804
    break;

805
806
807
808
809
810
811
  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);
      return -2;
    }
    break;

812
  case CONFIG_TYPE_CSV:
813
814
815
816
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
817
      *(smartlist_t**)lvalue = smartlist_create();
818
    }
819

820
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
821
822
823
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

824
825
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
826
    config_line_append((config_line_t**)lvalue, c->key, c->value);
827
    break;
828
829
830
831

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
832
833
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
834
    return -2;
835
836
837
  default:
    tor_assert(0);
    break;
838
  }
839
  return 0;
840
841
}

842
843
/** restore the option named <b>key</b> in options to its default value. */
static void
844
config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
845
846
847
{
  config_var_t *var;

848
849
850
  CHECK(fmt, options);

  var = config_find_option(fmt, key);
851
852
853
  if (!var)
    return; /* give error on next pass. */

854
  option_reset(fmt, options, var);
855
856
}

857
858
/** Return true iff key is a valid configuration option. */
int
859
option_is_recognized(const char *key)
860
{
861
  config_var_t *var = config_find_option(&options_format, key);
862
863
864
  return (var != NULL);
}

865
866
/** Return the canonical name of a configuration option. */
const char *