Unify windows special-dir handling
[tor.git] / src / or / config.c
blob9ea398783a774d49504b6b3a9a389d15cfe9261d
1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
3 /* $Id$ */
5 /**
6 * /file config.c
8 * /brief Code to parse and interpret configuration files.
10 **/
12 #include "or.h"
13 #ifdef MS_WINDOWS
14 #include <shlobj.h>
15 #endif
17 /** Enumeration of types which option values can take */
18 typedef enum config_type_t {
19 CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
20 CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */
21 CONFIG_TYPE_DOUBLE, /**< A floating-point value */
22 CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */
23 CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and optional
24 * whitespace. */
25 CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
26 CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
27 } config_type_t;
29 /** Largest allowed config line */
30 #define CONFIG_LINE_T_MAXLEN 4096
32 static struct config_line_t *config_get_commandlines(int argc, char **argv);
33 static int config_get_lines(FILE *f, struct config_line_t **result);
34 static void config_free_lines(struct config_line_t *front);
35 static int config_compare(struct config_line_t *c, const char *key, config_type_t type, void *arg);
36 static int config_assign(or_options_t *options, struct config_line_t *list);
37 static int parse_dir_server_line(const char *line);
38 static int parse_redirect_line(or_options_t *options,
39 struct config_line_t *line);
42 /** Helper: Read a list of configuration options from the command line. */
43 static struct config_line_t *
44 config_get_commandlines(int argc, char **argv)
46 struct config_line_t *new;
47 struct config_line_t *front = NULL;
48 char *s;
49 int i = 1;
51 while (i < argc-1) {
52 if (!strcmp(argv[i],"-f")) {
53 // log(LOG_DEBUG,"Commandline: skipping over -f.");
54 i += 2; /* this is the config file option. ignore it. */
55 continue;
58 new = tor_malloc(sizeof(struct config_line_t));
59 s = argv[i];
61 while(*s == '-')
62 s++;
64 new->key = tor_strdup(s);
65 new->value = tor_strdup(argv[i+1]);
67 log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
68 new->key, new->value);
69 new->next = front;
70 front = new;
71 i += 2;
73 return front;
76 /** Helper: allocate a new configuration option mapping 'key' to 'val',
77 * prepend it to 'front', and return the newly allocated config_line_t */
78 static struct config_line_t *
79 config_line_prepend(struct config_line_t *front,
80 const char *key,
81 const char *val)
83 struct config_line_t *newline;
85 newline = tor_malloc(sizeof(struct config_line_t));
86 newline->key = tor_strdup(key);
87 newline->value = tor_strdup(val);
88 newline->next = front;
89 return newline;
92 /** Helper: parse the config file and strdup into key/value
93 * strings. Set *result to the list, or NULL if parsing the file
94 * failed. Return 0 on success, -1 on failure. Warn and ignore any
95 * misformatted lines. */
96 static int
97 config_get_lines(FILE *f, struct config_line_t **result)
99 struct config_line_t *front = NULL;
100 char line[CONFIG_LINE_T_MAXLEN];
101 int r;
102 char *key, *value;
104 while ((r = parse_line_from_file(line, sizeof(line), f, &key, &value)) > 0) {
105 front = config_line_prepend(front, key, value);
108 if (r < 0) {
109 *result = NULL;
110 return -1;
111 } else {
112 *result = front;
113 return 0;
118 * Free all the configuration lines on the linked list <b>front</b>.
120 static void
121 config_free_lines(struct config_line_t *front)
123 struct config_line_t *tmp;
125 while (front) {
126 tmp = front;
127 front = tmp->next;
129 tor_free(tmp->key);
130 tor_free(tmp->value);
131 tor_free(tmp);
135 /** Search the linked list <b>c</b> for any option whose key is <b>key</b>.
136 * If such an option is found, interpret it as of type <b>type</b>, and store
137 * the result in <b>arg</b>. If the option is misformatted, log a warning and
138 * skip it.
140 static int
141 config_compare(struct config_line_t *c, const char *key,
142 config_type_t type, void *arg)
144 int i, ok;
146 if (strncasecmp(c->key, key, strlen(c->key)))
147 return 0;
149 if (strcasecmp(c->key, key)) {
150 tor_free(c->key);
151 c->key = tor_strdup(key);
154 /* it's a match. cast and assign. */
155 log_fn(LOG_DEBUG, "Recognized keyword '%s' as %s, using value '%s'.",
156 c->key, key, c->value);
158 switch(type) {
159 case CONFIG_TYPE_UINT:
160 i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
161 if (!ok) {
162 log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds. Skipping.",
163 c->key,c->value);
164 return 0;
166 *(int *)arg = i;
167 break;
169 case CONFIG_TYPE_BOOL:
170 i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
171 if (!ok) {
172 log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1. Skipping.", c->key);
173 return 0;
175 *(int *)arg = i;
176 break;
178 case CONFIG_TYPE_STRING:
179 tor_free(*(char **)arg);
180 *(char **)arg = tor_strdup(c->value);
181 break;
183 case CONFIG_TYPE_DOUBLE:
184 *(double *)arg = atof(c->value);
185 break;
187 case CONFIG_TYPE_CSV:
188 if (*(smartlist_t**)arg == NULL)
189 *(smartlist_t**)arg = smartlist_create();
191 smartlist_split_string(*(smartlist_t**)arg, c->value, ",",
192 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
193 break;
195 case CONFIG_TYPE_LINELIST:
196 /* Note: this reverses the order that the lines appear in. That's
197 * just fine, since we build up the list of lines reversed in the
198 * first place. */
199 *(struct config_line_t**)arg =
200 config_line_prepend(*(struct config_line_t**)arg, c->key, c->value);
201 break;
203 case CONFIG_TYPE_OBSOLETE:
204 log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
205 break;
208 return 1;
211 /** Iterate through the linked list of options <b>list</b>.
212 * For each item, convert as appropriate and assign to <b>options</b>.
213 * If an item is unrecognized, return -1 immediately,
214 * else return 0 for success. */
215 static int
216 config_assign(or_options_t *options, struct config_line_t *list)
218 while (list) {
219 if (
221 /* order matters here! abbreviated arguments use the first match. */
223 /* string options */
224 config_compare(list, "Address", CONFIG_TYPE_STRING, &options->Address) ||
225 config_compare(list, "AllowUnverifiedNodes", CONFIG_TYPE_CSV, &options->AllowUnverifiedNodes) ||
226 config_compare(list, "AuthoritativeDirectory",CONFIG_TYPE_BOOL, &options->AuthoritativeDir) ||
228 config_compare(list, "BandwidthRate", CONFIG_TYPE_UINT, &options->BandwidthRate) ||
229 config_compare(list, "BandwidthBurst", CONFIG_TYPE_UINT, &options->BandwidthBurst) ||
231 config_compare(list, "ClientOnly", CONFIG_TYPE_BOOL, &options->ClientOnly) ||
232 config_compare(list, "ContactInfo", CONFIG_TYPE_STRING, &options->ContactInfo) ||
234 config_compare(list, "DebugLogFile", CONFIG_TYPE_STRING, &options->DebugLogFile) ||
235 config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) ||
236 config_compare(list, "DirPort", CONFIG_TYPE_UINT, &options->DirPort) ||
237 config_compare(list, "DirBindAddress", CONFIG_TYPE_LINELIST, &options->DirBindAddress) ||
238 config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_UINT, &options->DirFetchPostPeriod) ||
239 config_compare(list, "DirServer", CONFIG_TYPE_LINELIST, &options->DirServers) ||
241 config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) ||
242 config_compare(list, "EntryNodes", CONFIG_TYPE_STRING, &options->EntryNodes) ||
243 config_compare(list, "StrictExitNodes", CONFIG_TYPE_BOOL, &options->StrictExitNodes) ||
244 config_compare(list, "StrictEntryNodes", CONFIG_TYPE_BOOL, &options->StrictEntryNodes) ||
245 config_compare(list, "ExitPolicy", CONFIG_TYPE_LINELIST, &options->ExitPolicy) ||
246 config_compare(list, "ExcludeNodes", CONFIG_TYPE_STRING, &options->ExcludeNodes) ||
248 config_compare(list, "FascistFirewall",CONFIG_TYPE_BOOL, &options->FascistFirewall) ||
249 config_compare(list, "FirewallPorts",CONFIG_TYPE_CSV, &options->FirewallPorts) ||
250 config_compare(list, "MyFamily", CONFIG_TYPE_STRING, &options->MyFamily) ||
251 config_compare(list, "NodeFamily", CONFIG_TYPE_LINELIST, &options->NodeFamilies) ||
253 config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) ||
255 config_compare(list, "HttpProxy", CONFIG_TYPE_STRING, &options->HttpProxy) ||
256 config_compare(list, "HiddenServiceDir", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
257 config_compare(list, "HiddenServicePort", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
258 config_compare(list, "HiddenServiceNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
259 config_compare(list, "HiddenServiceExcludeNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
261 config_compare(list, "IgnoreVersion", CONFIG_TYPE_BOOL, &options->IgnoreVersion) ||
263 config_compare(list, "KeepalivePeriod",CONFIG_TYPE_UINT, &options->KeepalivePeriod) ||
265 config_compare(list, "LogLevel", CONFIG_TYPE_LINELIST, &options->LogOptions) ||
266 config_compare(list, "LogFile", CONFIG_TYPE_LINELIST, &options->LogOptions) ||
267 config_compare(list, "LinkPadding", CONFIG_TYPE_OBSOLETE, NULL) ||
269 config_compare(list, "MaxConn", CONFIG_TYPE_UINT, &options->MaxConn) ||
270 config_compare(list, "MaxOnionsPending",CONFIG_TYPE_UINT, &options->MaxOnionsPending) ||
272 config_compare(list, "Nickname", CONFIG_TYPE_STRING, &options->Nickname) ||
273 config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_UINT, &options->NewCircuitPeriod) ||
274 config_compare(list, "NumCpus", CONFIG_TYPE_UINT, &options->NumCpus) ||
276 config_compare(list, "ORPort", CONFIG_TYPE_UINT, &options->ORPort) ||
277 config_compare(list, "ORBindAddress", CONFIG_TYPE_LINELIST, &options->ORBindAddress) ||
278 config_compare(list, "OutboundBindAddress",CONFIG_TYPE_STRING, &options->OutboundBindAddress) ||
280 config_compare(list, "PidFile", CONFIG_TYPE_STRING, &options->PidFile) ||
281 config_compare(list, "PathlenCoinWeight",CONFIG_TYPE_DOUBLE, &options->PathlenCoinWeight) ||
283 config_compare(list, "RedirectExit", CONFIG_TYPE_LINELIST, &options->RedirectExit) ||
284 config_compare(list, "RouterFile", CONFIG_TYPE_OBSOLETE, NULL) ||
285 config_compare(list, "RunAsDaemon", CONFIG_TYPE_BOOL, &options->RunAsDaemon) ||
286 config_compare(list, "RunTesting", CONFIG_TYPE_BOOL, &options->RunTesting) ||
287 config_compare(list, "RecommendedVersions",CONFIG_TYPE_LINELIST, &options->RecommendedVersions) ||
288 config_compare(list, "RendNodes", CONFIG_TYPE_STRING, &options->RendNodes) ||
289 config_compare(list, "RendExcludeNodes",CONFIG_TYPE_STRING, &options->RendExcludeNodes) ||
291 config_compare(list, "SocksPort", CONFIG_TYPE_UINT, &options->SocksPort) ||
292 config_compare(list, "SocksBindAddress",CONFIG_TYPE_LINELIST,&options->SocksBindAddress) ||
293 config_compare(list, "SocksPolicy", CONFIG_TYPE_LINELIST,&options->SocksPolicy) ||
295 config_compare(list, "TrafficShaping", CONFIG_TYPE_OBSOLETE, NULL) ||
297 config_compare(list, "User", CONFIG_TYPE_STRING, &options->User)
300 /* then we're ok. it matched something. */
301 } else {
302 log_fn(LOG_WARN,"Unknown keyword '%s'. Failing.",list->key);
303 return -1;
306 list = list->next;
309 return 0;
312 static void
313 add_default_trusted_dirservers(void)
315 /* moria1 */
316 parse_dir_server_line("18.244.0.188:9031 "
317 "FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
318 /* moria2 */
319 parse_dir_server_line("18.244.0.114:80 "
320 "719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
321 /* tor26 */
322 parse_dir_server_line("62.116.124.106:9030 "
323 "847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
326 /** Set <b>options</b> to a reasonable default.
328 * Call this function before we parse the torrc file.
330 static int
331 config_assign_defaults(or_options_t *options)
333 /* set them up as a client only */
334 options->SocksPort = 9050;
336 options->AllowUnverifiedNodes = smartlist_create();
337 smartlist_add(options->AllowUnverifiedNodes, "middle");
338 smartlist_add(options->AllowUnverifiedNodes, "rendezvous");
340 config_free_lines(options->ExitPolicy);
341 options->ExitPolicy = NULL;
343 return 0;
346 /** Print a usage message for tor. */
347 static void
348 print_usage(void)
350 printf("tor -f <torrc> [args]\n"
351 "See man page for more options. This -h is probably obsolete.\n\n"
352 "-b <bandwidth>\t\tbytes/second rate limiting\n"
353 "-d <file>\t\tDebug file\n"
354 // "-m <max>\t\tMax number of connections\n"
355 "-l <level>\t\tLog level\n"
356 "-r <file>\t\tList of known routers\n");
357 printf("\nClient options:\n"
358 "-e \"nick1 nick2 ...\"\t\tExit nodes\n"
359 "-s <IP>\t\t\tPort to bind to for Socks\n");
360 printf("\nServer options:\n"
361 "-n <nick>\t\tNickname of router\n"
362 "-o <port>\t\tOR port to bind to\n"
363 "-p <file>\t\tPID file\n");
367 * Based on <b>address</b>, guess our public IP address and put it
368 * in <b>addr</b>.
371 resolve_my_address(const char *address, uint32_t *addr)
373 struct in_addr in;
374 struct hostent *rent;
375 char hostname[256];
376 int explicit_ip=1;
378 tor_assert(addr);
380 if (address) {
381 strlcpy(hostname, address, sizeof(hostname));
382 } else { /* then we need to guess our address */
383 explicit_ip = 0; /* it's implicit */
385 if (gethostname(hostname, sizeof(hostname)) < 0) {
386 log_fn(LOG_WARN,"Error obtaining local hostname");
387 return -1;
389 log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
392 /* now we know hostname. resolve it and keep only the IP */
394 if (tor_inet_aton(hostname, &in) == 0) {
395 /* then we have to resolve it */
396 explicit_ip = 0;
397 rent = (struct hostent *)gethostbyname(hostname);
398 if (!rent) {
399 log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
400 return -1;
402 tor_assert(rent->h_length == 4);
403 memcpy(&in.s_addr, rent->h_addr, rent->h_length);
406 if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
407 log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
408 "Please set the Address config option to be the IP you want to use.",
409 hostname, inet_ntoa(in));
410 return -1;
413 log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
414 *addr = ntohl(in.s_addr);
415 return 0;
418 static char *
419 get_default_nickname(void)
421 char localhostname[256];
422 char *cp, *out, *outp;
424 if (gethostname(localhostname, sizeof(localhostname)) < 0) {
425 log_fn(LOG_WARN,"Error obtaining local hostname");
426 return NULL;
429 /* Put it in lowercase; stop at the first dot. */
430 for (cp = localhostname; *cp; ++cp) {
431 if (*cp == '.') {
432 *cp = '\0';
433 break;
435 *cp = tolower(*cp);
438 /* Strip invalid characters. */
439 cp = localhostname;
440 out = outp = tor_malloc(strlen(localhostname) + 1);
441 while (*cp) {
442 if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
443 *outp++ = *cp++;
444 else
445 cp++;
447 *outp = '\0';
449 /* Enforce length. */
450 if (strlen(out) > MAX_NICKNAME_LEN)
451 out[MAX_NICKNAME_LEN]='\0';
453 return out;
456 /** Release storage held by <b>options</b> */
457 static void
458 free_options(or_options_t *options)
460 config_free_lines(options->LogOptions);
461 tor_free(options->ContactInfo);
462 tor_free(options->DebugLogFile);
463 tor_free(options->DataDirectory);
464 tor_free(options->Nickname);
465 tor_free(options->Address);
466 tor_free(options->PidFile);
467 tor_free(options->ExitNodes);
468 tor_free(options->EntryNodes);
469 tor_free(options->ExcludeNodes);
470 tor_free(options->RendNodes);
471 tor_free(options->RendExcludeNodes);
472 tor_free(options->OutboundBindAddress);
473 tor_free(options->User);
474 tor_free(options->Group);
475 tor_free(options->HttpProxy);
476 config_free_lines(options->RendConfigLines);
477 config_free_lines(options->SocksBindAddress);
478 config_free_lines(options->ORBindAddress);
479 config_free_lines(options->DirBindAddress);
480 config_free_lines(options->ExitPolicy);
481 config_free_lines(options->SocksPolicy);
482 config_free_lines(options->DirServers);
483 config_free_lines(options->RecommendedVersions);
484 config_free_lines(options->NodeFamilies);
485 config_free_lines(options->RedirectExit);
486 if (options->RedirectExitList) {
487 SMARTLIST_FOREACH(options->RedirectExitList,
488 exit_redirect_t *, p, tor_free(p));
489 smartlist_free(options->RedirectExitList);
490 options->RedirectExitList = NULL;
492 if (options->FirewallPorts) {
493 SMARTLIST_FOREACH(options->FirewallPorts, char *, cp, tor_free(cp));
494 smartlist_free(options->FirewallPorts);
495 options->FirewallPorts = NULL;
499 /** Set <b>options</b> to hold reasonable defaults for most options.
500 * Each option defaults to zero. */
501 static void
502 init_options(or_options_t *options)
504 memset(options,0,sizeof(or_options_t));
505 options->ExitNodes = tor_strdup("");
506 options->EntryNodes = tor_strdup("");
507 options->StrictEntryNodes = options->StrictExitNodes = 0;
508 options->ExcludeNodes = tor_strdup("");
509 options->RendNodes = tor_strdup("");
510 options->RendExcludeNodes = tor_strdup("");
511 /* options->PidFile = tor_strdup("tor.pid"); */
512 options->PathlenCoinWeight = 0.3;
513 options->MaxConn = 900;
514 options->DirFetchPostPeriod = 600;
515 options->KeepalivePeriod = 300;
516 options->MaxOnionsPending = 100;
517 options->NewCircuitPeriod = 30; /* twice a minute */
518 options->BandwidthRate = 800000; /* at most 800kB/s total sustained incoming */
519 options->BandwidthBurst = 10000000; /* max burst on the token bucket */
520 options->NumCpus = 1;
523 #ifdef MS_WINDOWS
524 static char *get_windows_conf_root(void)
526 static int is_set = 0;
527 static char path[MAX_PATH+1];
529 LPITEMIDLIST idl;
530 IMalloc *m;
531 HRESULT result;
533 if (is_set)
534 return path;
536 /* Find X:\documents and settings\username\applicatation data\ .
537 * We would use SHGetSpecialFolder path, but that wasn't added until IE4.
539 if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA,
540 &idl))) {
541 return NULL;
543 /* Convert the path from an "ID List" (whatever that is!) to a path. */
544 result = SHGetPathFromIDList(idl, path);
545 /* Now we need to free the */
546 SHGetMalloc(&m);
547 if (m) {
548 m->lpVtbl->Free(m, idl);
549 m->lpVtbl->Release(m);
551 if (!SUCCEEDED(result)) {
552 return NULL;
554 is_set = 1;
555 return path;
557 #endif
559 static char *
560 get_default_conf_file(void)
562 #ifdef MS_WINDOWS
563 char *path = tor_malloc(MAX_PATH);
564 strlcpy(path, get_windows_conf_root(), MAX_PATH);
565 strlcat(path,"\\tor\\torrc",MAX_PATH);
566 return path;
567 #else
568 return tor_strdup(CONFDIR "/torrc");
569 #endif
572 /** Verify whether lst is a string containing valid-looking space-separated
573 * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure.
575 static int check_nickname_list(const char *lst, const char *name)
577 int r = 0;
578 smartlist_t *sl;
580 if (!lst)
581 return 0;
582 sl = smartlist_create();
583 smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
584 SMARTLIST_FOREACH(sl, const char *, s,
586 if (!is_legal_nickname_or_hexdigest(s)) {
587 log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name);
588 r = -1;
591 SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
592 smartlist_free(sl);
593 return r;
596 /** Read a configuration file into <b>options</b>, finding the configuration
597 * file location based on the command line. After loading the options,
598 * validate them for consistency. Return 0 if success, <0 if failure. */
600 getconfig(int argc, char **argv, or_options_t *options)
602 struct config_line_t *cl;
603 FILE *cf;
604 char *fname;
605 int i;
606 int result = 0;
607 static int first_load = 1;
608 static char **backup_argv;
609 static int backup_argc;
610 char *previous_pidfile = NULL;
611 int previous_runasdaemon = 0;
612 int previous_orport = -1;
613 int using_default_torrc;
615 if (first_load) { /* first time we're called. save commandline args */
616 backup_argv = argv;
617 backup_argc = argc;
618 first_load = 0;
619 } else { /* we're reloading. need to clean up old ones first. */
620 argv = backup_argv;
621 argc = backup_argc;
623 /* record some previous values, so we can fail if they change */
624 if (options->PidFile)
625 previous_pidfile = tor_strdup(options->PidFile);
626 previous_runasdaemon = options->RunAsDaemon;
627 previous_orport = options->ORPort;
628 free_options(options);
630 init_options(options);
632 if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) {
633 print_usage();
634 exit(0);
637 if (argc > 1 && (!strcmp(argv[1],"--version"))) {
638 printf("Tor version %s.\n",VERSION);
639 exit(0);
642 /* learn config file name, get config lines, assign them */
643 i = 1;
644 while (i < argc-1 && strcmp(argv[i],"-f")) {
645 i++;
648 if (i < argc-1) { /* we found one */
649 fname = tor_strdup(argv[i+1]);
650 using_default_torrc = 0;
651 } else {
652 /* didn't find one, try CONFDIR */
653 char *fn;
654 using_default_torrc = 1;
655 fn = get_default_conf_file();
656 if (fn && file_status(fn) == FN_FILE) {
657 fname = fn;
658 } else {
659 tor_free(fn);
660 fn = expand_filename("~/.torrc");
661 if (fn && file_status(fn) == FN_FILE) {
662 fname = fn;
663 } else {
664 tor_free(fn);
665 fname = get_default_conf_file();
669 tor_assert(fname);
670 log(LOG_DEBUG, "Opening config file '%s'", fname);
672 if (config_assign_defaults(options) < 0) {
673 return -1;
676 cf = fopen(fname, "r");
677 if (!cf) {
678 if (using_default_torrc == 1) {
679 log(LOG_NOTICE, "Configuration file '%s' not present, "
680 "using reasonable defaults.", fname);
681 tor_free(fname);
682 } else {
683 log(LOG_WARN, "Unable to open configuration file '%s'.", fname);
684 tor_free(fname);
685 return -1;
687 } else { /* it opened successfully. use it. */
688 tor_free(fname);
689 if (config_get_lines(cf, &cl)<0)
690 return -1;
691 if (config_assign(options,cl) < 0)
692 return -1;
693 config_free_lines(cl);
694 fclose(cf);
697 /* go through command-line variables too */
698 cl = config_get_commandlines(argc,argv);
699 if (config_assign(options,cl) < 0)
700 return -1;
701 config_free_lines(cl);
703 /* Validate options */
705 /* first check if any of the previous options have changed but aren't allowed to */
706 if (previous_pidfile && strcmp(previous_pidfile,options->PidFile)) {
707 log_fn(LOG_WARN,"During reload, PidFile changed from %s to %s. Failing.",
708 previous_pidfile, options->PidFile);
709 return -1;
711 tor_free(previous_pidfile);
713 if (previous_runasdaemon && !options->RunAsDaemon) {
714 log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing.");
715 return -1;
718 if (previous_orport == 0 && options->ORPort > 0) {
719 log_fn(LOG_WARN,"During reload, change from ORPort=0 to >0 not allowed. Failing.");
720 return -1;
723 if (options->ORPort < 0 || options->ORPort > 65535) {
724 log(LOG_WARN, "ORPort option out of bounds.");
725 result = -1;
728 if (options->Nickname == NULL) {
729 if (server_mode()) {
730 if (!(options->Nickname = get_default_nickname()))
731 return -1;
732 log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
734 } else {
735 if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
736 strlen(options->Nickname)) {
737 log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
738 result = -1;
740 if (strlen(options->Nickname) == 0) {
741 log_fn(LOG_WARN, "Nickname must have at least one character");
742 result = -1;
744 if (strlen(options->Nickname) > MAX_NICKNAME_LEN) {
745 log_fn(LOG_WARN, "Nickname '%s' has more than %d characters.",
746 options->Nickname, MAX_NICKNAME_LEN);
747 result = -1;
751 if (server_mode()) {
752 /* confirm that our address isn't broken, so we can complain now */
753 uint32_t tmp;
754 if (resolve_my_address(options->Address, &tmp) < 0)
755 result = -1;
758 if (options->SocksPort < 0 || options->SocksPort > 65535) {
759 log(LOG_WARN, "SocksPort option out of bounds.");
760 result = -1;
763 if (options->SocksPort == 0 && options->ORPort == 0) {
764 log(LOG_WARN, "SocksPort and ORPort are both undefined? Quitting.");
765 result = -1;
768 if (options->DirPort < 0 || options->DirPort > 65535) {
769 log(LOG_WARN, "DirPort option out of bounds.");
770 result = -1;
773 if (options->StrictExitNodes && !strlen(options->ExitNodes)) {
774 log(LOG_WARN, "StrictExitNodes set, but no ExitNodes listed.");
777 if (options->StrictEntryNodes && !strlen(options->EntryNodes)) {
778 log(LOG_WARN, "StrictEntryNodes set, but no EntryNodes listed.");
781 if (options->AuthoritativeDir && options->RecommendedVersions == NULL) {
782 log(LOG_WARN, "Directory servers must configure RecommendedVersions.");
783 result = -1;
786 if (options->AuthoritativeDir && !options->DirPort) {
787 log(LOG_WARN, "Running as authoritative directory, but no DirPort set.");
788 result = -1;
791 if (options->AuthoritativeDir && !options->ORPort) {
792 log(LOG_WARN, "Running as authoritative directory, but no ORPort set.");
793 result = -1;
796 if (options->AuthoritativeDir && options->ClientOnly) {
797 log(LOG_WARN, "Running as authoritative directory, but ClientOnly also set.");
798 result = -1;
801 if (options->FascistFirewall && !options->FirewallPorts) {
802 options->FirewallPorts = smartlist_create();
803 smartlist_add(options->FirewallPorts, tor_strdup("80"));
804 smartlist_add(options->FirewallPorts, tor_strdup("443"));
806 if (options->FirewallPorts) {
807 SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp,
809 i = atoi(cp);
810 if (i < 1 || i > 65535) {
811 log(LOG_WARN, "Port '%s' out of range in FirewallPorts", cp);
812 result=-1;
816 options->_AllowUnverified = 0;
817 if (options->AllowUnverifiedNodes) {
818 SMARTLIST_FOREACH(options->AllowUnverifiedNodes, const char *, cp, {
819 if (!strcasecmp(cp, "entry"))
820 options->_AllowUnverified |= ALLOW_UNVERIFIED_ENTRY;
821 else if (!strcasecmp(cp, "exit"))
822 options->_AllowUnverified |= ALLOW_UNVERIFIED_EXIT;
823 else if (!strcasecmp(cp, "middle"))
824 options->_AllowUnverified |= ALLOW_UNVERIFIED_MIDDLE;
825 else if (!strcasecmp(cp, "introduction"))
826 options->_AllowUnverified |= ALLOW_UNVERIFIED_INTRODUCTION;
827 else if (!strcasecmp(cp, "rendezvous"))
828 options->_AllowUnverified |= ALLOW_UNVERIFIED_RENDEZVOUS;
829 else {
830 log(LOG_WARN, "Unrecognized value '%s' in AllowUnverifiedNodes",
831 cp);
832 result=-1;
837 if (options->SocksPort >= 1 &&
838 (options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0)) {
839 log(LOG_WARN, "PathlenCoinWeight option must be >=0.0 and <1.0.");
840 result = -1;
843 if (options->MaxConn < 1) {
844 log(LOG_WARN, "MaxConn option must be a non-zero positive integer.");
845 result = -1;
848 if (options->MaxConn >= MAXCONNECTIONS) {
849 log(LOG_WARN, "MaxConn option must be less than %d.", MAXCONNECTIONS);
850 result = -1;
853 #define MIN_DIRFETCHPOSTPERIOD 60
854 if (options->DirFetchPostPeriod < MIN_DIRFETCHPOSTPERIOD) {
855 log(LOG_WARN, "DirFetchPostPeriod option must be at least %d.", MIN_DIRFETCHPOSTPERIOD);
856 result = -1;
858 if (options->DirFetchPostPeriod > MIN_ONION_KEY_LIFETIME / 2) {
859 log(LOG_WARN, "DirFetchPostPeriod is too large; clipping.");
860 options->DirFetchPostPeriod = MIN_ONION_KEY_LIFETIME / 2;
863 if (options->KeepalivePeriod < 1) {
864 log(LOG_WARN,"KeepalivePeriod option must be positive.");
865 result = -1;
868 if (options->HttpProxy) { /* parse it now */
869 if (parse_addr_port(options->HttpProxy, NULL,
870 &options->HttpProxyAddr, &options->HttpProxyPort) < 0) {
871 log(LOG_WARN,"HttpProxy failed to parse or resolve. Please fix.");
872 result = -1;
874 if (options->HttpProxyPort == 0) { /* give it a default */
875 options->HttpProxyPort = 80;
879 if (check_nickname_list(options->ExitNodes, "ExitNodes"))
880 return -1;
881 if (check_nickname_list(options->EntryNodes, "EntryNodes"))
882 return -1;
883 if (check_nickname_list(options->ExcludeNodes, "ExcludeNodes"))
884 return -1;
885 if (check_nickname_list(options->RendNodes, "RendNodes"))
886 return -1;
887 if (check_nickname_list(options->RendNodes, "RendExcludeNodes"))
888 return -1;
889 if (check_nickname_list(options->MyFamily, "MyFamily"))
890 return -1;
891 for (cl = options->NodeFamilies; cl; cl = cl->next) {
892 if (check_nickname_list(cl->value, "NodeFamily"))
893 return -1;
896 if (!options->RedirectExitList)
897 options->RedirectExitList = smartlist_create();
898 for (cl = options->RedirectExit; cl; cl = cl->next) {
899 if (parse_redirect_line(options, cl)<0)
900 return -1;
903 clear_trusted_dir_servers();
904 if (!options->DirServers) {
905 add_default_trusted_dirservers();
906 } else {
907 for (cl = options->DirServers; cl; cl = cl->next) {
908 if (parse_dir_server_line(cl->value)<0)
909 return -1;
913 if (rend_config_services(options) < 0) {
914 result = -1;
916 return result;
919 static int
920 add_single_log(struct config_line_t *level_opt,
921 struct config_line_t *file_opt, int isDaemon)
923 int levelMin = -1, levelMax = -1;
924 char *cp, *tmp_sev;
926 if (level_opt) {
927 cp = strchr(level_opt->value, '-');
928 if (cp) {
929 tmp_sev = tor_strndup(level_opt->value, cp - level_opt->value);
930 levelMin = parse_log_level(tmp_sev);
931 if (levelMin < 0) {
932 log_fn(LOG_WARN, "Unrecognized log severity '%s': must be one of "
933 "err|warn|notice|info|debug", tmp_sev);
934 return -1;
936 tor_free(tmp_sev);
937 levelMax = parse_log_level(cp+1);
938 if (levelMax < 0) {
939 log_fn(LOG_WARN, "Unrecognized log severity '%s': must be one of "
940 "err|warn|notice|info|debug", cp+1);
941 return -1;
943 } else {
944 levelMin = parse_log_level(level_opt->value);
945 if (levelMin < 0) {
946 log_fn(LOG_WARN, "Unrecognized log severity '%s': must be one of "
947 "err|warn|notice|info|debug", level_opt->value);
948 return -1;
953 if (levelMin < 0 && levelMax < 0) {
954 levelMin = LOG_NOTICE;
955 levelMax = LOG_ERR;
956 } else if (levelMin < 0) {
957 levelMin = levelMax;
958 } else {
959 levelMax = LOG_ERR;
961 if (file_opt) {
962 if (add_file_log(levelMin, levelMax, file_opt->value) < 0) {
963 log_fn(LOG_WARN, "Cannot write to LogFile '%s': %s.", file_opt->value,
964 strerror(errno));
965 return -1;
967 log_fn(LOG_NOTICE, "Successfully opened LogFile '%s', redirecting output.",
968 file_opt->value);
969 } else if (!isDaemon) {
970 add_stream_log(levelMin, levelMax, "<stdout>", stdout);
971 close_temp_logs();
973 return 0;
977 * Initialize the logs based on the configuration file.
980 config_init_logs(or_options_t *options)
982 /* The order of options is: Level? (File Level?)+
984 struct config_line_t *opt = options->LogOptions;
986 /* Special case if no options are given. */
987 if (!opt) {
988 add_stream_log(LOG_NOTICE, LOG_ERR, "<stdout>", stdout);
989 close_temp_logs();
990 /* don't return yet, in case we want to do a debuglogfile below */
993 /* Special case for if first option is LogLevel. */
994 if (opt && !strcasecmp(opt->key, "LogLevel")) {
995 if (opt->next && !strcasecmp(opt->next->key, "LogFile")) {
996 if (add_single_log(opt, opt->next, options->RunAsDaemon) < 0)
997 return -1;
998 opt = opt->next->next;
999 } else if (!opt->next) {
1000 if (add_single_log(opt, NULL, options->RunAsDaemon) < 0)
1001 return -1;
1002 opt = opt->next;
1003 } else {
1004 ; /* give warning below */
1008 while (opt) {
1009 if (!strcasecmp(opt->key, "LogLevel")) {
1010 log_fn(LOG_WARN, "Two LogLevel options in a row without intervening LogFile");
1011 opt = opt->next;
1012 } else {
1013 tor_assert(!strcasecmp(opt->key, "LogFile"));
1014 if (opt->next && !strcasecmp(opt->next->key, "LogLevel")) {
1015 /* LogFile followed by LogLevel */
1016 if (add_single_log(opt->next, opt, options->RunAsDaemon) < 0)
1017 return -1;
1018 opt = opt->next->next;
1019 } else {
1020 /* LogFile followed by LogFile or end of list. */
1021 if (add_single_log(NULL, opt, options->RunAsDaemon) < 0)
1022 return -1;
1023 opt = opt->next;
1028 if (options->DebugLogFile) {
1029 log_fn(LOG_WARN, "DebugLogFile is deprecated; use LogFile and LogLevel instead");
1030 if (add_file_log(LOG_DEBUG, LOG_ERR, options->DebugLogFile) < 0)
1031 return -1;
1034 return 0;
1038 * Given a linked list of config lines containing "allow" and "deny" tokens,
1039 * parse them and place the result in <b>dest</b>. Skip malformed lines.
1041 void
1042 config_parse_exit_policy(struct config_line_t *cfg,
1043 struct exit_policy_t **dest)
1045 struct exit_policy_t **nextp;
1046 smartlist_t *entries;
1048 if (!cfg)
1049 return;
1051 nextp = dest;
1053 while (*nextp)
1054 nextp = &((*nextp)->next);
1056 entries = smartlist_create();
1057 for (; cfg; cfg = cfg->next) {
1058 smartlist_split_string(entries, cfg->value, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
1059 SMARTLIST_FOREACH(entries, const char *, ent,
1061 log_fn(LOG_DEBUG,"Adding new entry '%s'",ent);
1062 *nextp = router_parse_exit_policy_from_string(ent);
1063 if (*nextp) {
1064 nextp = &((*nextp)->next);
1065 } else {
1066 log_fn(LOG_WARN,"Malformed exit policy %s; skipping.", ent);
1069 SMARTLIST_FOREACH(entries, char *, ent, tor_free(ent));
1070 smartlist_clear(entries);
1072 smartlist_free(entries);
1075 void exit_policy_free(struct exit_policy_t *p) {
1076 struct exit_policy_t *e;
1078 while (p) {
1079 e = p;
1080 p = p->next;
1081 tor_free(e->string);
1082 tor_free(e);
1086 static int parse_redirect_line(or_options_t *options,
1087 struct config_line_t *line)
1089 smartlist_t *elements = NULL;
1090 exit_redirect_t *r;
1092 tor_assert(options);
1093 tor_assert(options->RedirectExitList);
1094 tor_assert(line);
1096 r = tor_malloc_zero(sizeof(exit_redirect_t));
1097 smartlist_split_string(elements, line->value, " ",
1098 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
1099 if (smartlist_len(elements) != 2) {
1100 log_fn(LOG_WARN, "Wrong number of elements in RedirectExit line");
1101 goto err;
1103 if (parse_addr_and_port_range(smartlist_get(elements,0),&r->addr,&r->mask,
1104 &r->port_min,&r->port_max)) {
1105 log_fn(LOG_WARN, "Error parsing source address in RedirectExit line");
1106 goto err;
1108 if (parse_addr_port(smartlist_get(elements,1),NULL,&r->addr_dest,
1109 &r->port_dest)) {
1110 log_fn(LOG_WARN, "Error parseing dest address in RedirectExit line");
1111 goto err;
1114 goto done;
1115 err:
1116 tor_free(r);
1117 done:
1118 SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
1119 smartlist_free(elements);
1120 if (r) {
1121 smartlist_add(options->RedirectExitList, r);
1122 return 0;
1123 } else {
1124 return -1;
1128 static int parse_dir_server_line(const char *line)
1130 smartlist_t *items = NULL;
1131 int r;
1132 char *addrport, *address=NULL;
1133 uint16_t port;
1134 char digest[DIGEST_LEN];
1136 items = smartlist_create();
1137 smartlist_split_string(items, line, " ",
1138 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
1139 if (smartlist_len(items) < 2) {
1140 log_fn(LOG_WARN, "Too few arguments to DirServer line.");
1141 goto err;
1143 addrport = smartlist_get(items, 0);
1144 if (parse_addr_port(addrport, &address, NULL, &port)<0) {
1145 log_fn(LOG_WARN, "Error parsing DirServer address '%s'", addrport);
1146 goto err;
1148 if (!port) {
1149 log_fn(LOG_WARN, "Missing port in DirServe address '%s'",addrport);
1150 goto err;
1153 tor_strstrip(smartlist_get(items, 1), " ");
1154 if (strlen(smartlist_get(items, 1)) != HEX_DIGEST_LEN) {
1155 log_fn(LOG_WARN, "Key digest for DirServer is wrong length.");
1156 goto err;
1158 if (base16_decode(digest, DIGEST_LEN,
1159 smartlist_get(items,1), HEX_DIGEST_LEN)<0) {
1160 log_fn(LOG_WARN, "Unable to decode DirServer key digest.");
1161 goto err;
1164 log_fn(LOG_DEBUG, "Trusted dirserver at %s:%d (%s)", address, (int)port,
1165 (char*)smartlist_get(items,1));
1166 add_trusted_dir_server(address, port, digest);
1168 r = 0;
1169 goto done;
1171 err:
1172 r = -1;
1174 done:
1175 SMARTLIST_FOREACH(items, char*, s, tor_free(s));
1176 smartlist_free(items);
1178 if (address)
1179 tor_free(address);
1181 return r;
1184 const char *
1185 get_data_directory(or_options_t *options)
1187 const char *d;
1189 if (options->DataDirectory) {
1190 d = options->DataDirectory;
1191 } else {
1192 #ifdef MS_WINDOWS
1193 char *p;
1194 p = tor_malloc(MAX_PATH);
1195 strlcpy(p,get_windows_conf_root(),MAX_PATH);
1196 strlcat(p,"\\tor",MAX_PATH);
1197 options->DataDirectory = p;
1198 return p;
1199 #else
1200 d = "~/.tor";
1201 #endif
1204 if (d && strncmp(d,"~/",2) == 0) {
1205 char *fn = expand_filename(d);
1206 if (!fn) {
1207 log_fn(LOG_ERR,"Failed to expand filename '%s'. Exiting.", d);
1208 exit(1);
1210 tor_free(options->DataDirectory);
1211 options->DataDirectory = fn;
1213 return options->DataDirectory;
1217 Local Variables:
1218 mode:c
1219 indent-tabs-mode:nil
1220 c-basic-offset:2
1221 End: