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

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

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

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

40
/** An abbreviation for a configuration option allowed on the command line. */
41
typedef struct config_abbrev_t {
42
43
  const char *abbreviated;
  const char *full;
44
  int commandline_only;
45
  int warn;
46
47
} config_abbrev_t;

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>". */
50
#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
51

Nick Mathewson's avatar
Nick Mathewson committed
52
/* A list of command-line abbreviations. */
53
static config_abbrev_t _option_abbrevs[] = {
54
  PLURAL(ExitNode),
55
  PLURAL(EntryNode),
56
57
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
58
  PLURAL(LongLivedPort),
59
60
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
61
  PLURAL(NumCpu),
62
63
  PLURAL(RendNode),
  PLURAL(RendExcludeNode),
64
65
  PLURAL(StrictEntryNode),
  PLURAL(StrictExitNode),
66
  { "l", "Log", 1, 0},
67
  { "AllowUnverifiedNodes", "AllowInvalidNodes", 0, 0},
68
69
70
71
  { "BandwidthRateBytes", "BandwidthRate", 0, 0},
  { "BandwidthBurstBytes", "BandwidthBurst", 0, 0},
  { "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0},
  { "MaxConn", "ConnLimit", 0, 1},
72
73
74
  { "ORBindAddress", "ORListenAddress", 0, 0},
  { "DirBindAddress", "DirListenAddress", 0, 0},
  { "SocksBindAddress", "SocksListenAddress", 0, 0},
75
76
77
78
  { "UseHelperNodes", "UseEntryGuards", 0, 0},
  { "NumHelperNodes", "NumEntryGuards", 0, 0},
  { "UseEntryNodes", "UseEntryGuards", 0, 0},
  { "NumEntryNodes", "NumEntryGuards", 0, 0},
79
80
81
82
  { NULL, NULL, 0, 0},
};
/* A list of state-file abbreviations, for compatibility. */
static config_abbrev_t _state_abbrevs[] = {
83
  { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 },
84
85
86
87
88
89
  { "HelperNode", "EntryGuard", 0, 0 },
  { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 },
  { "HelperNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
  { "EntryNode", "EntryGuard", 0, 0 },
  { "EntryNodeDownSince", "EntryGuardDownSince", 0, 0 },
  { "EntryNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
90
  { NULL, NULL, 0, 0},
91
};
92
#undef PLURAL
93

94
/** A variable allowed in the configuration file or on the command line. */
95
typedef struct config_var_t {
96
  const char *name; /**< The full keyword (case insensitive). */
97
98
  config_type_t type; /**< How to interpret the type and turn it into a
                       * value. */
99
100
  off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
  const char *initvalue; /**< String (or null) describing initial value. */
101
102
} config_var_t;

Nick Mathewson's avatar
Nick Mathewson committed
103
/** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
104
105
#define STRUCT_OFFSET(tp, member) \
  ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
106
107
108
109

#define STRUCT_VAR_P(st, off) \
  ((void*) ( ((char*)st) + off ) )

Nick Mathewson's avatar
Nick Mathewson committed
110
111
112
113
/** 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>"
 */
114
115
#define VAR(name,conftype,member,initvalue)                             \
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member), \
116
      initvalue }
Nick Mathewson's avatar
Nick Mathewson committed
117
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
118
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL }
119

Nick Mathewson's avatar
Nick Mathewson committed
120
121
122
123
/** Array of configuration options.  Until we disallow nonstandard
 * abbreviations, order is significant, since the first matching option will
 * be chosen first.
 */
124
static config_var_t _option_vars[] = {
Roger Dingledine's avatar
Roger Dingledine committed
125
  VAR("AccountingMax",       MEMUNIT,  AccountingMax,        "0 bytes"),
Nick Mathewson's avatar
Nick Mathewson committed
126
  VAR("AccountingMaxKB",     UINT,     _AccountingMaxKB,     "0"),
127
  VAR("AccountingStart",     STRING,   AccountingStart,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
128
  VAR("Address",             STRING,   Address,              NULL),
129
  VAR("__AllDirActionsPrivate",BOOL,   AllDirActionsPrivate, "0"),
130
  VAR("AllowInvalidNodes",   CSV,      AllowInvalidNodes,
131
                                                        "middle,rendezvous"),
132
  VAR("AssumeReachable",     BOOL,     AssumeReachable,      "0"),
133
134
  VAR("AuthDirInvalid",      LINELIST, AuthDirInvalid,       NULL),
  VAR("AuthDirReject",       LINELIST, AuthDirReject,        NULL),
135
  VAR("AuthDirRejectUnlisted",BOOL,    AuthDirRejectUnlisted,"0"),
136
  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir,     "0"),
137
138
  VAR("BandwidthBurst",      MEMUNIT,  BandwidthBurst,       "6 MB"),
  VAR("BandwidthRate",       MEMUNIT,  BandwidthRate,        "3 MB"),
139
  VAR("ClientOnly",          BOOL,     ClientOnly,           "0"),
Nick Mathewson's avatar
Nick Mathewson committed
140
  VAR("ConnLimit",           UINT,     ConnLimit,            "1024"),
141
  VAR("ContactInfo",         STRING,   ContactInfo,          NULL),
142
  VAR("ControlListenAddress",LINELIST, ControlListenAddress, NULL),
143
  VAR("ControlPort",         UINT,     ControlPort,          "0"),
144
  VAR("CookieAuthentication",BOOL,     CookieAuthentication, "0"),
145
  VAR("DataDirectory",       STRING,   DataDirectory,        NULL),
Nick Mathewson's avatar
Nick Mathewson committed
146
  VAR("DebugLogFile",        STRING,   DebugLogFile,         NULL),
147
  VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
148
149
150
  VAR("DirListenAddress",    LINELIST, DirListenAddress,     NULL),
  /* if DirFetchPeriod is 0, see get_dir_fetch_period() in main.c */
  VAR("DirFetchPeriod",      INTERVAL, DirFetchPeriod,       "0 seconds"),
151
  VAR("DirPolicy",           LINELIST, DirPolicy,            NULL),
Nick Mathewson's avatar
Nick Mathewson committed
152
  VAR("DirPort",             UINT,     DirPort,              "0"),
153
  OBSOLETE("DirPostPeriod"),
154
155
156
  VAR("DirServer",           LINELIST, DirServers,           NULL),
  VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
157
158
  VAR("ExitNodes",           STRING,   ExitNodes,            NULL),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
159
  VAR("ExitPolicyRejectPrivate", BOOL, ExitPolicyRejectPrivate, "1"),
160
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
161
  VAR("FirewallPorts",       CSV,      FirewallPorts,        ""),
162
  VAR("FastFirstHopPK",      BOOL,     FastFirstHopPK,       "1"),
163
164
  VAR("FetchServerDescriptors",BOOL,   FetchServerDescriptors,"1"),
  VAR("FetchHidServDescriptors",BOOL,  FetchHidServDescriptors, "1"),
165
  VAR("Group",               STRING,   Group,                NULL),
166
  VAR("HardwareAccel",       BOOL,     HardwareAccel,        "0"),
167
  VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
168
169
170
171
172
  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),
173
  VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
174
  VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL),
175
  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
176
  VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL),
177
  OBSOLETE("IgnoreVersion"),
178
  VAR("KeepalivePeriod",     INTERVAL, KeepalivePeriod,      "5 minutes"),
179
  VAR("Log",                 LINELIST, Logs,                 NULL),
180
  OBSOLETE("LinkPadding"),
Nick Mathewson's avatar
Nick Mathewson committed
181
182
  VAR("LogFile",             LINELIST_S, OldLogOptions,      NULL),
  VAR("LogLevel",            LINELIST_S, OldLogOptions,      NULL),
183
184
  VAR("LongLivedPorts",      CSV,      LongLivedPorts,
                         "21,22,706,1863,5050,5190,5222,5223,6667,8300,8888"),
Nick Mathewson's avatar
Nick Mathewson committed
185
186
187
  VAR("MapAddress",          LINELIST, AddressMap,           NULL),
  VAR("MaxAdvertisedBandwidth",MEMUNIT,MaxAdvertisedBandwidth,"128 TB"),
  VAR("MaxCircuitDirtiness", INTERVAL, MaxCircuitDirtiness,  "10 minutes"),
188
  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending,     "100"),
189
  OBSOLETE("MonthlyAccountingStart"),
Nick Mathewson's avatar
Nick Mathewson committed
190
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
191
  VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
192
  VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
Nick Mathewson's avatar
Nick Mathewson committed
193
194
195
  VAR("Nickname",            STRING,   Nickname,             NULL),
  VAR("NoPublish",           BOOL,     NoPublish,            "0"),
  VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
196
  VAR("NumCpus",             UINT,     NumCpus,              "1"),
197
  VAR("NumEntryGuards",      UINT,     NumEntryGuards,       "3"),
198
  VAR("ORListenAddress",     LINELIST, ORListenAddress,      NULL),
Nick Mathewson's avatar
Nick Mathewson committed
199
  VAR("ORPort",              UINT,     ORPort,               "0"),
200
201
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
Nick Mathewson's avatar
Nick Mathewson committed
202
  VAR("PidFile",             STRING,   PidFile,              NULL),
203
  VAR("ProtocolWarnings",    BOOL,     ProtocolWarnings,     "0"),
204
205
  VAR("PublishServerDescriptor",BOOL,  PublishServerDescriptor,"1"),
  VAR("PublishHidServDescriptors",BOOL,PublishHidServDescriptors, "1"),
206
  VAR("ReachableAddresses",  LINELIST, ReachableAddresses,   NULL),
207
208
  VAR("ReachableDirAddresses",LINELIST,ReachableDirAddresses,NULL),
  VAR("ReachableORAddresses",LINELIST, ReachableORAddresses, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
209
  VAR("RecommendedVersions", LINELIST, RecommendedVersions,  NULL),
210
211
  VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions,  NULL),
  VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions,  NULL),
212
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
Nick Mathewson's avatar
Nick Mathewson committed
213
214
  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes,     NULL),
  VAR("RendNodes",           STRING,   RendNodes,            NULL),
215
  VAR("RendPostPeriod",      INTERVAL, RendPostPeriod,       "1 hour"),
216
  VAR("RephistTrackTime",    INTERVAL, RephistTrackTime,     "24 hours"),
217
  OBSOLETE("RouterFile"),
218
219
  VAR("RunAsDaemon",         BOOL,     RunAsDaemon,          "0"),
  VAR("RunTesting",          BOOL,     RunTesting,           "0"),
220
  VAR("SafeLogging",         BOOL,     SafeLogging,          "1"),
221
  VAR("SafeSocks",           BOOL,     SafeSocks,            "0"),
222
  VAR("ShutdownWaitLength",  INTERVAL, ShutdownWaitLength,   "30 seconds"),
223
  VAR("SocksListenAddress",  LINELIST, SocksListenAddress,   NULL),
224
  VAR("SocksPolicy",         LINELIST, SocksPolicy,          NULL),
Nick Mathewson's avatar
Nick Mathewson committed
225
  VAR("SocksPort",           UINT,     SocksPort,            "9050"),
226
227
  /* if StatusFetchPeriod is 0, see get_status_fetch_period() in main.c */
  VAR("StatusFetchPeriod",   INTERVAL, StatusFetchPeriod,    "0 seconds"),
Nick Mathewson's avatar
Nick Mathewson committed
228
229
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("StrictExitNodes",     BOOL,     StrictExitNodes,      "0"),
230
  VAR("SysLog",              LINELIST_S, OldLogOptions,      NULL),
231
  VAR("TestSocks",           BOOL,     TestSocks,            "0"),
Nick Mathewson's avatar
Nick Mathewson committed
232
233
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
234
  OBSOLETE("TrafficShaping"),
235
  VAR("UseEntryGuards",      BOOL,     UseEntryGuards,       "1"),
Nick Mathewson's avatar
Nick Mathewson committed
236
  VAR("User",                STRING,   User,                 NULL),
237
  VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "0"),
238
  VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
239
  VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
240
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
241
};
242
243
#undef VAR

244
245
#define VAR(name,conftype,member,initvalue)                             \
  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member),  \
246
      initvalue }
247
static config_var_t _state_vars[] = {
248
  VAR("AccountingBytesReadInInterval", MEMUNIT,
249
      AccountingBytesReadInInterval, NULL),
250
251
252
  VAR("AccountingBytesWrittenInInterval", MEMUNIT,
      AccountingBytesWrittenInInterval, NULL),
  VAR("AccountingExpectedUsage", MEMUNIT,     AccountingExpectedUsage, NULL),
253
  VAR("AccountingIntervalStart", ISOTIME,     AccountingIntervalStart, NULL),
Nick Mathewson's avatar
Nick Mathewson committed
254
  VAR("AccountingSecondsActive", INTERVAL,    AccountingSecondsActive, NULL),
255
256
257
258
  VAR("EntryGuard",              LINELIST_S,  EntryGuards,             NULL),
  VAR("EntryGuardDownSince",     LINELIST_S,  EntryGuards,             NULL),
  VAR("EntryGuardUnlistedSince", LINELIST_S,  EntryGuards,             NULL),
  VAR("EntryGuards",             LINELIST_V,  EntryGuards,             NULL),
Nick Mathewson's avatar
Nick Mathewson committed
259

260
261
262
263
264
265
266
  VAR("BWHistoryReadEnds",       ISOTIME,     BWHistoryReadEnds,      NULL),
  VAR("BWHistoryReadInterval",   UINT,        BWHistoryReadInterval,  NULL),
  VAR("BWHistoryReadValues",     CSV,         BWHistoryReadValues,    NULL),
  VAR("BWHistoryWriteEnds",      ISOTIME,     BWHistoryWriteEnds,     NULL),
  VAR("BWHistoryWriteInterval",  UINT,        BWHistoryWriteInterval, NULL),
  VAR("BWHistoryWriteValues",    CSV,         BWHistoryWriteValues,   NULL),

267
268
  VAR("TorVersion",              STRING,      TorVersion,             NULL),

269
270
  VAR("LastWritten",             ISOTIME,     LastWritten,            NULL),

271
  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
272
273
};

274
275
276
#undef VAR
#undef OBSOLETE

277
278
/** Represents an English description of a configuration variable; used when
 * generating configuration file comments. */
279
280
281
282
283
284
typedef struct config_var_description_t {
  const char *name;
  const char *description;
} config_var_description_t;

static config_var_description_t options_description[] = {
285
  { "Address", "The advertised (external) address we should use." },
286
287
288
289
290
  // { "AccountingStart", ""},
  { NULL, NULL },
};

static config_var_description_t state_description[] = {
291
  { "AccountingBytesReadInInterval",
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
    "How many bytes have we read in this accounting period?" },
  { "AccountingBytesWrittenInInterval",
    "How many bytes have we written in this accounting period?" },
  { "AccountingExpectedUsage",
    "How many bytes did we expect to use per minute? (0 for no estimate.)" },
  { "AccountingIntervalStart", "When did this accounting period begin?" },
  { "AccountingSecondsActive", "How long have we been awake in this period?" },

  { "BWHistoryReadEnds", "When does the last-recorded read-interval end?" },
  { "BWHistoryReadInterval", "How long is each read-interval (in seconds)?" },
  { "BWHistoryReadValues", "Number of bytes read in each interval." },
  { "BWHistoryWriteEnds", "When does the last-recorded write-interval end?" },
  { "BWHistoryWriteInterval", "How long is each write-interval (in seconds)?"},
  { "BWHistoryWriteValues", "Number of bytes written in each interval." },

307
308
309
310
311
  { "EntryGuard", "One of the nodes we have chosen as a fixed entry" },
  { "EntryGuardDownSince",
    "The last entry guard has been down since this time." },
  { "EntryGuardUnlistedSince",
    "The last entry guard has been unlisted since this time." },
312
313
314
  { "LastWritten", "When was this state file last regenerated?" },

  { "TorVersion", "Which version of Tor generated this state file?" },
315
316
317
  { NULL, NULL },
};

Roger Dingledine's avatar
Roger Dingledine committed
318
typedef int (*validate_fn_t)(void*,void*,int);
319

320
321
322
/** Information on the keys, value types, key-to-struct-member mappings,
 * variable descriptions, validation functions, and abbreviations for a
 * configuration or storage format. */
323
324
325
326
327
328
329
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;
330
  config_var_description_t *descriptions;
Roger Dingledine's avatar
Roger Dingledine committed
331
332
333
  /** If present, extra is a LINELIST variable for unrecognized
   * lines.  Otherwise, unrecognized lines are an error. */
  config_var_t *extra;
334
335
336
337
} config_format_t;

#define CHECK(fmt, cfg) do {                                            \
    tor_assert(fmt && cfg);                                             \
338
    tor_assert((fmt)->magic ==                                          \
339
               *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset));        \
340
341
  } while (0)

342
static void config_line_append(config_line_t **lst,
343
                               const char *key, const char *val);
344
345
static void option_clear(config_format_t *fmt, or_options_t *options,
                         config_var_t *var);
346
static void option_reset(config_format_t *fmt, or_options_t *options,
347
                         config_var_t *var, int use_defaults);
348
static void config_free(config_format_t *fmt, void *options);
349
static int option_is_same(config_format_t *fmt,
350
351
                          or_options_t *o1, or_options_t *o2,
                          const char *name);
352
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
353
static int options_validate(or_options_t *old_options,
Roger Dingledine's avatar
Roger Dingledine committed
354
                            or_options_t *options, int from_setconf);
355
static int options_act_reversible(or_options_t *old_options);
356
static int options_act(or_options_t *old_options);
357
static int options_transition_allowed(or_options_t *old, or_options_t *new);
358
359
360
361
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);
362
static int check_nickname_list(const char *lst, const char *name);
363
static void config_register_addressmaps(or_options_t *options);
364

365
static int parse_dir_server_line(const char *line, int validate_only);
366
static int config_cmp_single_addr_policy(addr_policy_t *a, addr_policy_t *b);
367
static int config_addr_policy_covers(addr_policy_t *a, addr_policy_t *b);
368
static int config_addr_policy_intersects(addr_policy_t *a, addr_policy_t *b);
369
static int parse_redirect_line(smartlist_t *result,
370
                               config_line_t *line);
371
372
373
static int parse_log_severity_range(const char *range, int *min_out,
                                    int *max_out);
static int convert_log_option(or_options_t *options,
374
375
                              config_line_t *level_opt,
                              config_line_t *file_opt, int isDaemon);
376
377
378
379
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);
380
static int validate_data_directory(or_options_t *options);
381
static int write_configuration_file(const char *fname, or_options_t *options);
382
static config_line_t *get_assigned_option(config_format_t *fmt,
383
                                     or_options_t *options, const char *key);
384
static void config_init(config_format_t *fmt, void *options);
385
386
static int or_state_validate(or_state_t *old_options, or_state_t *options,
                             int from_setconf);
387

388
389
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
390
static void print_cvs_version(void);
391
static void parse_reachable_addresses(void);
392
static int init_libevent(void);
393
static int opt_streq(const char *s1, const char *s2);
394
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
395
static void check_libevent_version(const char *m, const char *v, int server);
396
#endif
397

398
399
/*static*/ or_options_t *options_new(void);

400
401
#define OR_OPTIONS_MAGIC 9090909

402
static config_format_t options_format = {
403
404
405
  sizeof(or_options_t),
  OR_OPTIONS_MAGIC,
  STRUCT_OFFSET(or_options_t, _magic),
406
407
408
  _option_abbrevs,
  _option_vars,
  (validate_fn_t)options_validate,
409
410
  options_description,
  NULL
411
412
413
414
};

#define OR_STATE_MAGIC 0x57A73f57

415
416
417
418
static config_var_t state_extra_var = {
  "__extra", CONFIG_TYPE_LINELIST, STRUCT_OFFSET(or_state_t, ExtraLines), NULL
};

419
420
421
422
static config_format_t state_format = {
  sizeof(or_state_t),
  OR_STATE_MAGIC,
  STRUCT_OFFSET(or_state_t, _magic),
423
  _state_abbrevs,
424
425
  _state_vars,
  (validate_fn_t)or_state_validate,
426
427
  state_description,
  &state_extra_var,
428
429
};

430
431
432
433
434
/*
 * Functions to read and write the global options pointer.
 */

/** Command-line and config-file options. */
435
static or_options_t *global_options = NULL;
Roger Dingledine's avatar
Roger Dingledine committed
436
/** Name of most recently read torrc file. */
437
static char *torrc_fname = NULL;
438
/** Persistent serialized state. */
439
static or_state_t *global_state = NULL;
440
441
/** Parsed addr_policy_t describing which addresses we believe we can start
 * circuits at. */
442
static addr_policy_t *reachable_or_addr_policy = NULL;
443
444
/** Parsed addr_policy_t describing which addresses we believe we can connect
 * to directories at. */
445
static addr_policy_t *reachable_dir_addr_policy = NULL;
446

447
/** Allocate an empty configuration object of a given format type. */
448
449
450
451
static void *
config_alloc(config_format_t *fmt)
{
  void *opts = opts = tor_malloc_zero(fmt->size);
452
  *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
453
454
455
456
  CHECK(fmt, opts);
  return opts;
}

457
458
/** Return the currently configured options. */
or_options_t *
459
460
get_options(void)
{
461
462
463
  tor_assert(global_options);
  return global_options;
}
464

465
466
467
/** 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.
468
 */
469
int
470
471
set_options(or_options_t *new_val)
{
472
  or_options_t *old_options = global_options;
473
  global_options = new_val;
474
475
  /* Note that we pass the *old* options below, for comparison. It
   * pulls the new options directly out of global_options. */
476
477
478
479
  if (options_act_reversible(old_options)<0) {
    global_options = old_options;
    return -1;
  }
480
  if (options_act(old_options) < 0) { /* acting on the options failed. die. */
Roger Dingledine's avatar
Roger Dingledine committed
481
482
    log_err(LD_CONFIG,
            "Acting on config options left us in a broken state. Dying.");
483
484
485
    exit(1);
  }
  if (old_options)
486
    config_free(&options_format, old_options);
487
488

  return 0;
489
490
}

491
492
/** Release all memory and resources held by global configuration structures.
 */
493
494
495
void
config_free_all(void)
{
496
497
498
499
500
501
502
503
  if (global_options) {
    config_free(&options_format, global_options);
    global_options = NULL;
  }
  if (global_state) {
    config_free(&state_format, global_state);
    global_state = NULL;
  }
504
  tor_free(torrc_fname);
505
506
507
508
509
510
511
  if (reachable_or_addr_policy) {
    addr_policy_free(reachable_or_addr_policy);
    reachable_or_addr_policy = NULL;
  }
  if (reachable_dir_addr_policy) {
    addr_policy_free(reachable_dir_addr_policy);
    reachable_dir_addr_policy = NULL;
512
  }
513
514
}

515
516
517
518
/** If options->SafeLogging is on, return a not very useful string,
 * else return address.
 */
const char *
519
520
safe_str(const char *address)
{
521
522
523
524
525
526
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return address;
}

527
/** Equivalent to escaped(safe_str(address)) */
528
529
530
531
532
533
534
535
536
const char *
escaped_safe_str(const char *address)
{
  if (get_options()->SafeLogging)
    return "[scrubbed]";
  else
    return escaped(address);
}

537
538
539
540
/** Add the default directory servers directly into the trusted dir list. */
static void
add_default_trusted_dirservers(void)
{
541
  int i;
542
  const char *dirservers[] = {
543
544
545
546
547
548
549
    "moria1 v1 18.244.0.188:9031 "
      "FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441",
    "moria2 v1 18.244.0.114:80 "
      "719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF",
    "tor26 v1 86.59.21.38:80 "
      "847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
    NULL
550
  };
551
552
  for (i=0; dirservers[i]; i++)
    parse_dir_server_line(dirservers[i], 0);
553
554
}

555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
/** 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;
571
  int logs_marked = 0;
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594

  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) {
Roger Dingledine's avatar
Roger Dingledine committed
595
596
    log_err(LD_FS, "Couldn't access/create private data directory \"%s\"",
            options->DataDirectory);
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
    /* 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) {
Roger Dingledine's avatar
Roger Dingledine committed
613
    log_err(LD_CONFIG, "Failed to bind one of the listener ports.");
614
615
616
    goto rollback;
  }

617
618
619
620
621
  mark_logs_temp(); /* Close current logs once new logs are open. */
  logs_marked = 1;
  if (options_init_logs(options, 0)<0) /* Configure the log(s) */
    goto rollback;

622
623
 commit:
  r = 0;
624
625
626
627
628
  if (logs_marked) {
    close_temp_logs();
    add_callback_log(LOG_ERR, LOG_ERR, control_event_logmsg);
    control_adjust_event_log_severity();
  }
629
630
  SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn,
  {
Roger Dingledine's avatar
Roger Dingledine committed
631
632
    log_notice(LD_NET, "Closing old %s on %s:%d",
               conn_type_to_string(conn->type), conn->address, conn->port);
633
634
635
636
637
638
639
640
    connection_close_immediate(conn);
    connection_mark_for_close(conn);
  });
  goto done;

 rollback:
  r = -1;

641
642
643
644
645
  if (logs_marked) {
    rollback_log_changes();
    control_adjust_event_log_severity();
  }

646
647
648
649
650
  if (set_conn_limit && old_options)
    set_max_file_descriptors((unsigned)old_options->ConnLimit,MAXCONNECTIONS);

  SMARTLIST_FOREACH(new_listeners, connection_t *, conn,
  {
Roger Dingledine's avatar
Roger Dingledine committed
651
652
    log_notice(LD_NET, "Closing %s on %s:%d",
               conn_type_to_string(conn->type), conn->address, conn->port);
653
654
655
656
657
658
659
660
661
662
    connection_close_immediate(conn);
    connection_mark_for_close(conn);
  });

 done:
  smartlist_free(new_listeners);
  smartlist_free(replaced_listeners);
  return r;
}

663
664
665
/** 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.
666
 *
667
 * Return 0 if all goes well, return -1 if it's time to die.
668
669
670
 *
 * Note 2: We haven't moved all the "act on new configuration" logic
 * here yet.  Some is still in do_hup() and other places.
671
 */
672
673
static int
options_act(or_options_t *old_options)
674
{
675
  config_line_t *cl;
676
677
  char *fn;
  size_t len;
678
  or_options_t *options = get_options();
679
  int running_tor = options->command == CMD_RUN_TOR;
680
681

  clear_trusted_dir_servers();
682
683
684
  if (options->DirServers) {
    for (cl = options->DirServers; cl; cl = cl->next) {
      if (parse_dir_server_line(cl->value, 0)<0) {
Roger Dingledine's avatar
Roger Dingledine committed
685
        log_err(LD_BUG,
686
687
688
            "Bug: Previously validated DirServer line could not be added!");
        return -1;
      }
689
    }
690
691
  } else {
    add_default_trusted_dirservers();
692
693
  }

694
  if (running_tor && rend_config_services(options, 0)<0) {
Roger Dingledine's avatar
Roger Dingledine committed
695
696
    log_err(LD_BUG,
       "Bug: Previously validated hidden services line could not be added!");
697
    return -1;
698
  }
699

700
701
702
703
704
  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) {
Roger Dingledine's avatar
Roger Dingledine committed
705
706
      log_err(LD_CONFIG,
              "Couldn't access/create private data directory \"%s\"", fn);
707
708
709
      tor_free(fn);
      return -1;
    }
710
711
    tor_free(fn);
  }
712

713
714
  /* 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. */
715
716
717
  if (options->command != CMD_RUN_TOR)
    return 0;

718
719
720
721
722
  /* Load state */
  if (! global_state)
    if (or_state_load())
      return -1;

723
724
725
726
727
728
729
730
731
  {
    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);
  }

732
  /* Finish backgrounding the process */
733
  if (running_tor && options->RunAsDaemon) {
734
    /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */
735
    finish_daemon(options->DataDirectory);
736
737
738
739
  }

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

743
744
745
  /* Register addressmap directives */
  config_register_addressmaps(options);

746
747
748
  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
749
  parse_authdir_policy();
750
  parse_reachable_addresses();
751

752
753
  init_cookie_authentication(options->CookieAuthentication);

754
755
  /* reload keys as needed for rendezvous services. */
  if (rend_service_load_keys()<0) {
Roger Dingledine's avatar
Roger Dingledine committed
756
    log_err(LD_GENERAL,"Error loading rendezvous service keys");
757
758
759
    return -1;
  }

760
  /* Set up accounting */
761
  if (accounting_parse_options(options, 0)<0) {
Roger Dingledine's avatar
Roger Dingledine committed
762
    log_err(LD_CONFIG,"Error in accounting options");
763
764
    return -1;
  }
765
  if (accounting_is_enabled(options))
766
767
    configure_accounting(time(NULL));

768
769
770
  if (!running_tor)
    return 0;

771
772
  /* Check for transitions that need action. */
  if (old_options) {
773
    if (options->UseEntryGuards && !old_options->UseEntryGuards) {
Roger Dingledine's avatar
Roger Dingledine committed
774
775
      log_info(LD_CIRC,
               "Switching to entry guards; abandoning previous circuits");
776
777
778
779
      circuit_mark_all_unused_circs();
      circuit_expire_all_dirty_circs();
    }

780
    if (options_transition_affects_workers(old_options, options)) {
Roger Dingledine's avatar
Roger Dingledine committed
781
782
      log_info(LD_GENERAL,
               "Worker-related options changed. Rotating workers.");
783
784
785
      if (server_mode(options) && !server_mode(old_options)) {
        extern int has_completed_circuit;
        if (init_keys() < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
786
          log_err(LD_GENERAL,"Error initializing keys; exiting");
787
788
789
790
791
792
          return -1;
        }
        server_has_changed_ip();
        if (has_completed_circuit)
          inform_testing_reachability();
      }
793
794
795
796
797
      cpuworkers_rotate();
      dnsworkers_rotate();
    }
  }

798
  /* Check if we need to parse and add the EntryNodes config option. */
799
800
801
  if (options->EntryNodes &&
      (!old_options ||
       !opt_streq(old_options->EntryNodes, options->EntryNodes)))
802
803
    entry_nodes_should_be_added();

804
  /* Since our options changed, we might need to regenerate and upload our
805
   * server descriptor.
806
   */
807
808
  if (!old_options ||
      options_transition_affects_descriptor(old_options, options))
809
    mark_my_descriptor_dirty();
810

811
  return 0;
812
813
814
815
816
817
}

/*
 * Functions to parse config options
 */

Nick Mathewson's avatar
Nick Mathewson committed
818
/** If <b>option</b> is an official abbreviation for a longer option,
819
820
 * return the longer option.  Otherwise return <b>option</b>.
 * If <b>command_line</b> is set, apply all abbreviations.  Otherwise, only
821
822
 * apply abbreviations that work for the config file and the command line.
 * If <b>warn_obsolete</b> is set, warn about deprecated names. */
823
static const char *
824
825
expand_abbrev(config_format_t *fmt, const char *option, int command_line,
              int warn_obsolete)
826
827
{
  int i;
828
829
830
  if (! fmt->abbrevs)
    return option;
  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
831
    /* Abbreviations are casei. */
832
833
    if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
        (command_line || !fmt->abbrevs[i].commandline_only)) {
834
      if (warn_obsolete && fmt->abbrevs[i].warn) {
Roger Dingledine's avatar
Roger Dingledine committed
835
836
837
838
839
        log_warn(LD_CONFIG,
                 "The configuration option '%s' is deprecated; "
                 "use '%s' instead.",
                 fmt->abbrevs[i].abbreviated,
                 fmt->abbrevs[i].full);
840
      }
841
      return fmt->abbrevs[i].full;
842
    }
843
844
845
  }
  return option;
}
Nick Mathewson's avatar
Nick Mathewson committed
846

847
848
849
850
851
/** 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)
852
{
853
854
  config_line_t *front = NULL;
  config_line_t **new = &front;
855
856
857
  char *s;
  int i = 1;

858
  while (i < argc) {
859
860
861
    if (!strcmp(argv[i],"-f") ||
        !strcmp(argv[i],"--hash-password")) {
      i += 2; /* command-line option with argument. ignore them. */
862
      continue;
863
864
    } else if (!strcmp(argv[i],"--list-fingerprint") ||
               !strcmp(argv[i],"--verify-config")) {
865
      i += 1; /* command-line option. ignore it. */
866
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
867
868
869
    } else if (!strcmp(argv[i],"--nt-service")) {
      i += 1;
      continue;
870
    }
871
    if (i == argc-1) {
Roger Dingledine's avatar
Roger Dingledine committed
872
873
      log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
               argv[i]);
874
875
876
      config_free_lines(front);
      return -1;
    }
877

878
    *new = tor_malloc_zero(sizeof(config_line_t));
879
    s = argv[i];
880

881
    while (*s == '-')
882
      s++;
883

884
    (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1, 1));
885
886
    (*new)->value = tor_strdup(argv[i+1]);
    (*new)->next = NULL;
887
    log(LOG_DEBUG, LD_CONFIG, "Commandline: parsed keyword '%s', value '%s'",
888
889
890
        (*new)->key, (*new)->value);

    new = &((*new)->next);
891
892
    i += 2;
  }
893
894
  *result = front;
  return 0;
895
896
}

Nick Mathewson's avatar
Nick Mathewson committed
897
/** Helper: allocate a new configuration option mapping 'key' to 'val',
898
899
 * append it to *<b>lst</b>. */
static void
900
config_line_append(config_line_t **lst,
901
902
                   const char *key,
                   const char *val)
Nick Mathewson's avatar