config.c 104 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
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
105
106
  /* XXXX 011 change this default on 0.1.1.x */
  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "1"),
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"),
Nick Mathewson's avatar
Nick Mathewson committed
155
156
157
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
158
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
Nick Mathewson's avatar
Nick Mathewson committed
159
  VAR("NumHelperNodes",      UINT,     NumHelperNodes,       "3"),
160
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
161
  VAR("ORPort",              UINT,     ORPort,               "0"),
162
163
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
164
  VAR("PidFile",             STRING,   PidFile,              NULL),
165
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
Nick Mathewson's avatar
Nick Mathewson committed
166
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
167
168
  VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions,  NULL),
  VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions,  NULL),
169
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
170
171
172
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "20 minutes"),
173
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
174
  OBSOLETE("RouterFile"),
175
176
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
177
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
178
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
179
180
  VAR("SocksBindAddress",    LINELIST, SocksBindAddress,     NULL),
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
181
182
183
184
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),  /** DOCDOC */
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
185
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
186
187
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
188
  OBSOLETE("TrafficShaping"),
189
  VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
Nick Mathewson's avatar
Nick Mathewson committed
190
  VAR("User",                STRING,   User,                 NULL),
191
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
192
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
193
};
194
195
196
#undef VAR

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

211
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
212
213
};

214
215
216
#undef VAR
#undef OBSOLETE

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

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

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

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

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

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

306
307
/*static*/ or_options_t *options_new(void);

308
309
#define OR_OPTIONS_MAGIC 9090909

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

332
333
334
335
336
/*
 * Functions to read and write the global options pointer.
 */

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

345
346
347
348
349
350
351
352
353
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;
}

354
355
/** Return the currently configured options. */
or_options_t *
356
357
get_options(void)
{
358
359
360
  tor_assert(global_options);
  return global_options;
}
361

362
363
364
/** 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.
365
366
 */
void
367
368
set_options(or_options_t *new_val)
{
369
  or_options_t *old_options = global_options;
370
  global_options = new_val;
371
372
  /* Note that we pass the *old* options below, for comparison. It
   * pulls the new options directly out of global_options. */
373
374
375
376
377
  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)
378
    config_free(&options_format, old_options);
379
380
}

381
382
383
void
config_free_all(void)
{
384
  config_free(&options_format, global_options);
385
  tor_free(torrc_fname);
386
387
  addr_policy_free(reachable_addr_policy);
  reachable_addr_policy = NULL;
388
389
}

390
391
392
393
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
394
395
safe_str(const char *address)
{
396
397
398
399
400
401
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

402
403
404
/** 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.
405
 *
406
 * Return 0 if all goes well, return -1 if it's time to die.
407
408
409
 *
 * Note 2: We haven't moved all the "act on new configuration" logic
 * here yet.  Some is still in do_hup() and other places.
410
 */
411
412
static int
options_act(or_options_t *old_options)
413
{
414
  config_line_t *cl;
415
416
  char *fn;
  size_t len;
417
  or_options_t *options = get_options();
418
  int running_tor = options->command == CMD_RUN_TOR;
419
420
  static int libevent_initialized = 0;

421
  if (running_tor && options->RunAsDaemon) {
422
    start_daemon();
423
  }
424
425

  clear_trusted_dir_servers();
426
  for (cl = options->DirServers; cl; cl = cl->next) {
427
428
    if (parse_dir_server_line(cl->value, 0)<0) {
      log_fn(LOG_ERR,
429
             "Bug: Previously validated DirServer line could not be added!");
430
      return -1;
431
432
433
    }
  }

434
  if (running_tor && rend_config_services(options, 0)<0) {
435
    log_fn(LOG_ERR,
436
           "Bug: Previously validated hidden services line could not be added!");
437
    return -1;
438
  }
439

440
441
442
  if (options->EntryNodes && strlen(options->EntryNodes))
    options->UseHelperNodes = 0;

443
  /* Setuid/setgid as appropriate */
444
445
  if (options->User || options->Group) {
    if (switch_id(options->User, options->Group) != 0) {
446
447
448
449
450
      return -1;
    }
  }

  /* Ensure data directory is private; create if possible. */
451
  if (check_private_dir(options->DataDirectory, CPD_CREATE) != 0) {
452
    log_fn(LOG_ERR, "Couldn't access/create private data directory \"%s\"",
453
           options->DataDirectory);
454
455
    return -1;
  }
456
457
458
459
460
461
462
463
464
465
  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;
    }
466
467
    tor_free(fn);
  }
468

469
470
  /* 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. */
471
472
473
  if (options->command != CMD_RUN_TOR)
    return 0;

474
  mark_logs_temp(); /* Close current logs once new logs are open. */
475
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
476
    return -1;
477

478
479
480
  /* Close the temporary log we used while starting up, if it isn't already
   * gone. */
  close_temp_logs();
481
  add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
482
  control_adjust_event_log_severity();
483

484
  /* Set up libevent. */
485
  if (running_tor && !libevent_initialized) {
486
487
488
489
490
    if (init_libevent())
      return -1;
    libevent_initialized = 1;
  }

491
492
493
494
495
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

496
  options->_ConnLimit =
497
    set_max_file_descriptors((unsigned)options->ConnLimit, MAXCONNECTIONS);
498
  if (options->_ConnLimit < 0)
499
500
    return -1;

501
502
503
504
505
506
507
508
509
  {
    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);
  }

510
  /* Finish backgrounding the process */
511
  if (running_tor && options->RunAsDaemon) {
512
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
513
    finish_daemon(options->DataDirectory);
514
515
516
517
  }

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

521
522
523
  /* Register addressmap directives */
  config_register_addressmaps(options);

524
525
526
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
527
  parse_reachable_addresses();
528

529
530
  init_cookie_authentication(options->CookieAuthentication);

531
532
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
533
    log_fn(LOG_ERR,"Error loading rendezvous service keys");
534
535
536
    return -1;
  }

537
  /* Set up accounting */
538
  if (accounting_parse_options(options, 0)<0) {
539
    log_fn(LOG_ERR,"Error in accounting options");
540
541
    return -1;
  }
542
  if (accounting_is_enabled(options))
543
544
    configure_accounting(time(NULL));

545
546
547
  if (!running_tor)
    return 0;

548
  if (!we_are_hibernating() && retry_all_listeners(0) < 0) {
549
550
551
552
    log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
    return -1;
  }

553
554
555
556
557
558
559
560
561
  /* 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();
    }
  }

562
  /* Since our options changed, we might need to regenerate and upload our
563
   * server descriptor.
564
   */
565
566
  if (!old_options || options_transition_affects_descriptor(old_options, options))
    mark_my_descriptor_dirty();
567

568
  return 0;
569
570
571
572
573
574
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
575
/** If <b>option</b> is an official abbreviation for a longer option,
576
577
578
 * 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. */
579
static const char *
580
expand_abbrev(config_format_t *fmt, const char *option, int command_line)
581
582
{
  int i;
583
584
585
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
586
    /* Abbreviations aren't casei. */
587
588
589
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
      return fmt->abbrevs[i].full;
590
    }
591
592
593
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
594

595
596
597
598
599
/** 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)
600
{
601
602
  config_line_t *front = NULL;
  config_line_t **new = &front;
603
604
605
  char *s;
  int i = 1;

606
  while (i < argc) {
607
608
609
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
610
      continue;
611
612
    } else if (!strcmp(argv[i],"--list-fingerprint")) {
      i += 1; /* command-line option. ignore it. */
613
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
614
615
616
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
617
    }
618
619
620
621
622
623
    if (i == argc-1) {
      log_fn(LOG_WARN,"Command-line option '%s' with no value. Failing.",
             argv[i]);
      config_free_lines(front);
      return -1;
    }
624

625
    *new = tor_malloc_zero(sizeof(config_line_t));
626
    s = argv[i];
627

628
    while (*s == '-')
629
      s++;
630

631
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1));
632
633
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
634
    log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
635
636
637
        (*new)->key, (*new)->value);

    new = &((*new)->next);
638
639
    i += 2;
  }
640
641
  *result = front;
  return 0;
642
643
}

Nick Mathewson's avatar
Nick Mathewson committed
644
/** Helper: allocate a new configuration option mapping 'key' to 'val',
645
646
 * append it to *<b>lst</b>. */
static void
647
config_line_append(config_line_t **lst,
648
649
                   const char *key,
                   const char *val)
650
{
651
  config_line_t *newline;
652

653
  newline = tor_malloc(sizeof(config_line_t));
654
655
  newline->key = tor_strdup(key);
  newline->value = tor_strdup(val);
656
657
658
659
660
  newline->next = NULL;
  while (*lst)
    lst = &((*lst)->next);

  (*lst) = newline;
661
662
}

663
664
/** Helper: parse the config string and strdup into key/value
 * strings. Set *result to the list, or NULL if parsing the string
665
666
 * failed.  Return 0 on success, -1 on failure. Warn and ignore any
 * misformatted lines. */
667
int
668
config_get_lines(char *string, config_line_t **result)
669
{
670
  config_line_t *list = NULL, **next;
671
  char *k, *v;
672

673
  next = &list;
674
675
676
677
678
679
  do {
    string = parse_line_from_str(string, &k, &v);
    if (!string) {
      config_free_lines(list);
      return -1;
    }
680
681
682
683
    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. */
684
      *next = tor_malloc(sizeof(config_line_t));
685
686
687
688
689
      (*next)->key = tor_strdup(k);
      (*next)->value = tor_strdup(v);
      (*next)->next = NULL;
      next = &((*next)->next);
    }
690
  } while (*string);
691

692
  *result = list;
693
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
694
695
}

Nick Mathewson's avatar
Nick Mathewson committed
696
697
698
/**
 * Free all the configuration lines on the linked list <b>front</b>.
 */
699
void
700
config_free_lines(config_line_t *front)
701
{
702
  config_line_t *tmp;
703

704
  while (front) {
705
706
707
    tmp = front;
    front = tmp->next;

Roger Dingledine's avatar
Roger Dingledine committed
708
709
710
    tor_free(tmp->key);
    tor_free(tmp->value);
    tor_free(tmp);
711
712
713
  }
}

714
715
716
717
718
719
720
721
722
723
724
725
/** 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
726
727
728
729
/** 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.
 */
730
static config_var_t *
731
config_find_option(config_format_t *fmt, const char *key)
732
733
{
  int i;
734
  size_t keylen = strlen(key);
735
  if (!keylen)
736
    return NULL; /* if they say "--" on the commandline, it's not an option */
Nick Mathewson's avatar
Nick Mathewson committed
737
  /* First, check for an exact (case-insensitive) match */
738
  for (i=0; fmt->vars[i].name; ++i) {
739
    if (!strcasecmp(key, fmt->vars[i].name)) {
740
      return &fmt->vars[i];
741
    }
Nick Mathewson's avatar
Nick Mathewson committed
742
743
  }
  /* If none, check for an abbreviated match */
744
745
  for (i=0; fmt->vars[i].name; ++i) {
    if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
746
      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
747
          "Please use '%s' instead",
748
749
             key, fmt->vars[i].name);
      return &fmt->vars[i];
750
751
    }
  }
752
  /* Okay, unrecognized options */
753
754
755
  return NULL;
}

756
757
/** <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.
758
 */
759
static int
760
761
config_assign_value(config_format_t *fmt, or_options_t *options,
                    config_line_t *c)
762
{
763
  int i, ok;
764
765
  config_var_t *var;
  void *lvalue;
766

767
768
769
  CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
770
  tor_assert(var);
771

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

774
  switch (var->type) {
775

776
777
778
  case CONFIG_TYPE_UINT:
    i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
    if (!ok) {
779
      log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds.",
780
          c->key,c->value);
781
      return -1;
782
    }
783
    *(int *)lvalue = i;
784
785
    break;

786
787
788
  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
789
      return -1;
790
791
792
793
794
795
796
797
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
798
      return -1;
799
800
801
802
803
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

804
805
806
  case CONFIG_TYPE_BOOL:
    i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
807
      log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1.", c->key);
808
      return -1;
809
    }
810
    *(int *)lvalue = i;
811
812
813
    break;

  case CONFIG_TYPE_STRING:
814
815
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
816
817
818
    break;

  case CONFIG_TYPE_DOUBLE:
819
    *(double *)lvalue = atof(c->value);
820
821
    break;

822
823
824
  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);
825
      return -1;
826
827
828
    }
    break;

829
  case CONFIG_TYPE_CSV:
830
831
832
833
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
834
      *(smartlist_t**)lvalue = smartlist_create();
835
    }
836

837
    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
838
839
840
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    break;

841
842
  case CONFIG_TYPE_LINELIST:
  case CONFIG_TYPE_LINELIST_S:
843
    config_line_append((config_line_t**)lvalue, c->key, c->value);
844
    break;
845
846
847
848

  case CONFIG_TYPE_OBSOLETE:
    log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
    break;
849
850
  case CONFIG_TYPE_LINELIST_V:
    log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
851
    return -1;