config.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. /**
  5. * /file config.c
  6. *
  7. * /brief Code to parse and interpret configuration files.
  8. *
  9. **/
  10. #include "or.h"
  11. #ifdef MS_WINDOWS
  12. #include <shlobj.h>
  13. #endif
  14. /** Enumeration of types which option values can take */
  15. typedef enum config_type_t {
  16. CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
  17. CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */
  18. CONFIG_TYPE_DOUBLE, /**< A floating-point value */
  19. CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */
  20. CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and optional
  21. * whitespace. */
  22. CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
  23. CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
  24. } config_type_t;
  25. /** Largest allowed config line */
  26. #define CONFIG_LINE_T_MAXLEN 4096
  27. static struct config_line_t *config_get_commandlines(int argc, char **argv);
  28. static int config_get_lines(FILE *f, struct config_line_t **result);
  29. static void config_free_lines(struct config_line_t *front);
  30. static int config_compare(struct config_line_t *c, const char *key, config_type_t type, void *arg);
  31. static int config_assign(or_options_t *options, struct config_line_t *list);
  32. static int parse_dir_server_line(const char *line);
  33. static int parse_redirect_line(or_options_t *options,
  34. struct config_line_t *line);
  35. /** Helper: Read a list of configuration options from the command line. */
  36. static struct config_line_t *
  37. config_get_commandlines(int argc, char **argv)
  38. {
  39. struct config_line_t *new;
  40. struct config_line_t *front = NULL;
  41. char *s;
  42. int i = 1;
  43. while (i < argc-1) {
  44. if (!strcmp(argv[i],"-f")) {
  45. // log(LOG_DEBUG,"Commandline: skipping over -f.");
  46. i += 2; /* this is the config file option. ignore it. */
  47. continue;
  48. }
  49. new = tor_malloc(sizeof(struct config_line_t));
  50. s = argv[i];
  51. while(*s == '-')
  52. s++;
  53. new->key = tor_strdup(s);
  54. new->value = tor_strdup(argv[i+1]);
  55. log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
  56. new->key, new->value);
  57. new->next = front;
  58. front = new;
  59. i += 2;
  60. }
  61. return front;
  62. }
  63. /** Helper: allocate a new configuration option mapping 'key' to 'val',
  64. * prepend it to 'front', and return the newly allocated config_line_t */
  65. static struct config_line_t *
  66. config_line_prepend(struct config_line_t *front,
  67. const char *key,
  68. const char *val)
  69. {
  70. struct config_line_t *newline;
  71. newline = tor_malloc(sizeof(struct config_line_t));
  72. newline->key = tor_strdup(key);
  73. newline->value = tor_strdup(val);
  74. newline->next = front;
  75. return newline;
  76. }
  77. /** Helper: parse the config file and strdup into key/value
  78. * strings. Set *result to the list, or NULL if parsing the file
  79. * failed. Return 0 on success, -1 on failure. Warn and ignore any
  80. * misformatted lines. */
  81. static int
  82. config_get_lines(FILE *f, struct config_line_t **result)
  83. {
  84. struct config_line_t *front = NULL;
  85. char line[CONFIG_LINE_T_MAXLEN];
  86. int r;
  87. char *key, *value;
  88. while ((r = parse_line_from_file(line, sizeof(line), f, &key, &value)) > 0) {
  89. front = config_line_prepend(front, key, value);
  90. }
  91. if (r < 0) {
  92. *result = NULL;
  93. return -1;
  94. } else {
  95. *result = front;
  96. return 0;
  97. }
  98. }
  99. /**
  100. * Free all the configuration lines on the linked list <b>front</b>.
  101. */
  102. static void
  103. config_free_lines(struct config_line_t *front)
  104. {
  105. struct config_line_t *tmp;
  106. while (front) {
  107. tmp = front;
  108. front = tmp->next;
  109. tor_free(tmp->key);
  110. tor_free(tmp->value);
  111. tor_free(tmp);
  112. }
  113. }
  114. /** Search the linked list <b>c</b> for any option whose key is <b>key</b>.
  115. * If such an option is found, interpret it as of type <b>type</b>, and store
  116. * the result in <b>arg</b>. If the option is misformatted, log a warning and
  117. * skip it.
  118. */
  119. static int
  120. config_compare(struct config_line_t *c, const char *key,
  121. config_type_t type, void *arg)
  122. {
  123. int i, ok;
  124. if (strncasecmp(c->key, key, strlen(c->key)))
  125. return 0;
  126. if (strcasecmp(c->key, key)) {
  127. tor_free(c->key);
  128. c->key = tor_strdup(key);
  129. }
  130. /* it's a match. cast and assign. */
  131. log_fn(LOG_DEBUG, "Recognized keyword '%s' as %s, using value '%s'.",
  132. c->key, key, c->value);
  133. switch(type) {
  134. case CONFIG_TYPE_UINT:
  135. i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
  136. if (!ok) {
  137. log(LOG_WARN, "Int keyword '%s %s' is malformed or out of bounds. Skipping.",
  138. c->key,c->value);
  139. return 0;
  140. }
  141. *(int *)arg = i;
  142. break;
  143. case CONFIG_TYPE_BOOL:
  144. i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
  145. if (!ok) {
  146. log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1. Skipping.", c->key);
  147. return 0;
  148. }
  149. *(int *)arg = i;
  150. break;
  151. case CONFIG_TYPE_STRING:
  152. tor_free(*(char **)arg);
  153. *(char **)arg = tor_strdup(c->value);
  154. break;
  155. case CONFIG_TYPE_DOUBLE:
  156. *(double *)arg = atof(c->value);
  157. break;
  158. case CONFIG_TYPE_CSV:
  159. if (*(smartlist_t**)arg == NULL)
  160. *(smartlist_t**)arg = smartlist_create();
  161. smartlist_split_string(*(smartlist_t**)arg, c->value, ",",
  162. SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  163. break;
  164. case CONFIG_TYPE_LINELIST:
  165. /* Note: this reverses the order that the lines appear in. That's
  166. * just fine, since we build up the list of lines reversed in the
  167. * first place. */
  168. *(struct config_line_t**)arg =
  169. config_line_prepend(*(struct config_line_t**)arg, c->key, c->value);
  170. break;
  171. case CONFIG_TYPE_OBSOLETE:
  172. log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
  173. break;
  174. }
  175. return 1;
  176. }
  177. /** Iterate through the linked list of options <b>list</b>.
  178. * For each item, convert as appropriate and assign to <b>options</b>.
  179. * If an item is unrecognized, return -1 immediately,
  180. * else return 0 for success. */
  181. static int
  182. config_assign(or_options_t *options, struct config_line_t *list)
  183. {
  184. while (list) {
  185. if (
  186. /* order matters here! abbreviated arguments use the first match. */
  187. /* string options */
  188. config_compare(list, "Address", CONFIG_TYPE_STRING, &options->Address) ||
  189. config_compare(list, "AllowUnverifiedNodes", CONFIG_TYPE_CSV, &options->AllowUnverifiedNodes) ||
  190. config_compare(list, "AuthoritativeDirectory",CONFIG_TYPE_BOOL, &options->AuthoritativeDir) ||
  191. config_compare(list, "BandwidthRate", CONFIG_TYPE_UINT, &options->BandwidthRate) ||
  192. config_compare(list, "BandwidthBurst", CONFIG_TYPE_UINT, &options->BandwidthBurst) ||
  193. config_compare(list, "ClientOnly", CONFIG_TYPE_BOOL, &options->ClientOnly) ||
  194. config_compare(list, "ContactInfo", CONFIG_TYPE_STRING, &options->ContactInfo) ||
  195. config_compare(list, "DebugLogFile", CONFIG_TYPE_STRING, &options->DebugLogFile) ||
  196. config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) ||
  197. config_compare(list, "DirPort", CONFIG_TYPE_UINT, &options->DirPort) ||
  198. config_compare(list, "DirBindAddress", CONFIG_TYPE_LINELIST, &options->DirBindAddress) ||
  199. config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_UINT, &options->DirFetchPostPeriod) ||
  200. config_compare(list, "DirServer", CONFIG_TYPE_LINELIST, &options->DirServers) ||
  201. config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) ||
  202. config_compare(list, "EntryNodes", CONFIG_TYPE_STRING, &options->EntryNodes) ||
  203. config_compare(list, "StrictExitNodes", CONFIG_TYPE_BOOL, &options->StrictExitNodes) ||
  204. config_compare(list, "StrictEntryNodes", CONFIG_TYPE_BOOL, &options->StrictEntryNodes) ||
  205. config_compare(list, "ExitPolicy", CONFIG_TYPE_LINELIST, &options->ExitPolicy) ||
  206. config_compare(list, "ExcludeNodes", CONFIG_TYPE_STRING, &options->ExcludeNodes) ||
  207. config_compare(list, "FascistFirewall",CONFIG_TYPE_BOOL, &options->FascistFirewall) ||
  208. config_compare(list, "FirewallPorts",CONFIG_TYPE_CSV, &options->FirewallPorts) ||
  209. config_compare(list, "MyFamily", CONFIG_TYPE_STRING, &options->MyFamily) ||
  210. config_compare(list, "NodeFamily", CONFIG_TYPE_LINELIST, &options->NodeFamilies) ||
  211. config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) ||
  212. config_compare(list, "HttpProxy", CONFIG_TYPE_STRING, &options->HttpProxy) ||
  213. config_compare(list, "HiddenServiceDir", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
  214. config_compare(list, "HiddenServicePort", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
  215. config_compare(list, "HiddenServiceNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
  216. config_compare(list, "HiddenServiceExcludeNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
  217. config_compare(list, "IgnoreVersion", CONFIG_TYPE_BOOL, &options->IgnoreVersion) ||
  218. config_compare(list, "KeepalivePeriod",CONFIG_TYPE_UINT, &options->KeepalivePeriod) ||
  219. config_compare(list, "LogLevel", CONFIG_TYPE_LINELIST, &options->LogOptions) ||
  220. config_compare(list, "LogFile", CONFIG_TYPE_LINELIST, &options->LogOptions) ||
  221. config_compare(list, "LinkPadding", CONFIG_TYPE_OBSOLETE, NULL) ||
  222. config_compare(list, "MaxConn", CONFIG_TYPE_UINT, &options->MaxConn) ||
  223. config_compare(list, "MaxOnionsPending",CONFIG_TYPE_UINT, &options->MaxOnionsPending) ||
  224. config_compare(list, "Nickname", CONFIG_TYPE_STRING, &options->Nickname) ||
  225. config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_UINT, &options->NewCircuitPeriod) ||
  226. config_compare(list, "NumCpus", CONFIG_TYPE_UINT, &options->NumCpus) ||
  227. config_compare(list, "ORPort", CONFIG_TYPE_UINT, &options->ORPort) ||
  228. config_compare(list, "ORBindAddress", CONFIG_TYPE_LINELIST, &options->ORBindAddress) ||
  229. config_compare(list, "OutboundBindAddress",CONFIG_TYPE_STRING, &options->OutboundBindAddress) ||
  230. config_compare(list, "PidFile", CONFIG_TYPE_STRING, &options->PidFile) ||
  231. config_compare(list, "PathlenCoinWeight",CONFIG_TYPE_DOUBLE, &options->PathlenCoinWeight) ||
  232. config_compare(list, "RedirectExit", CONFIG_TYPE_LINELIST, &options->RedirectExit) ||
  233. config_compare(list, "RouterFile", CONFIG_TYPE_OBSOLETE, NULL) ||
  234. config_compare(list, "RunAsDaemon", CONFIG_TYPE_BOOL, &options->RunAsDaemon) ||
  235. config_compare(list, "RunTesting", CONFIG_TYPE_BOOL, &options->RunTesting) ||
  236. config_compare(list, "RecommendedVersions",CONFIG_TYPE_LINELIST, &options->RecommendedVersions) ||
  237. config_compare(list, "RendNodes", CONFIG_TYPE_STRING, &options->RendNodes) ||
  238. config_compare(list, "RendExcludeNodes",CONFIG_TYPE_STRING, &options->RendExcludeNodes) ||
  239. config_compare(list, "SocksPort", CONFIG_TYPE_UINT, &options->SocksPort) ||
  240. config_compare(list, "SocksBindAddress",CONFIG_TYPE_LINELIST,&options->SocksBindAddress) ||
  241. config_compare(list, "SocksPolicy", CONFIG_TYPE_LINELIST,&options->SocksPolicy) ||
  242. config_compare(list, "TrafficShaping", CONFIG_TYPE_OBSOLETE, NULL) ||
  243. config_compare(list, "User", CONFIG_TYPE_STRING, &options->User)
  244. ) {
  245. /* then we're ok. it matched something. */
  246. } else {
  247. log_fn(LOG_WARN,"Unknown keyword '%s'. Failing.",list->key);
  248. return -1;
  249. }
  250. list = list->next;
  251. }
  252. return 0;
  253. }
  254. static void
  255. add_default_trusted_dirservers(void)
  256. {
  257. /* moria1 */
  258. parse_dir_server_line("18.244.0.188:9031 "
  259. "FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441");
  260. /* moria2 */
  261. parse_dir_server_line("18.244.0.114:80 "
  262. "719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF");
  263. /* tor26 */
  264. parse_dir_server_line("62.116.124.106:9030 "
  265. "847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D");
  266. }
  267. /** Set <b>options</b> to a reasonable default.
  268. *
  269. * Call this function before we parse the torrc file.
  270. */
  271. static int
  272. config_assign_defaults(or_options_t *options)
  273. {
  274. /* set them up as a client only */
  275. options->SocksPort = 9050;
  276. options->AllowUnverifiedNodes = smartlist_create();
  277. smartlist_add(options->AllowUnverifiedNodes, "middle");
  278. smartlist_add(options->AllowUnverifiedNodes, "rendezvous");
  279. config_free_lines(options->ExitPolicy);
  280. options->ExitPolicy = NULL;
  281. return 0;
  282. }
  283. /** Print a usage message for tor. */
  284. static void
  285. print_usage(void)
  286. {
  287. printf("tor -f <torrc> [args]\n"
  288. "See man page for more options. This -h is probably obsolete.\n\n"
  289. "-b <bandwidth>\t\tbytes/second rate limiting\n"
  290. "-d <file>\t\tDebug file\n"
  291. // "-m <max>\t\tMax number of connections\n"
  292. "-l <level>\t\tLog level\n"
  293. "-r <file>\t\tList of known routers\n");
  294. printf("\nClient options:\n"
  295. "-e \"nick1 nick2 ...\"\t\tExit nodes\n"
  296. "-s <IP>\t\t\tPort to bind to for Socks\n");
  297. printf("\nServer options:\n"
  298. "-n <nick>\t\tNickname of router\n"
  299. "-o <port>\t\tOR port to bind to\n"
  300. "-p <file>\t\tPID file\n");
  301. }
  302. /**
  303. * Based on <b>address</b>, guess our public IP address and put it
  304. * in <b>addr</b>.
  305. */
  306. int
  307. resolve_my_address(const char *address, uint32_t *addr)
  308. {
  309. struct in_addr in;
  310. struct hostent *rent;
  311. char hostname[256];
  312. int explicit_ip=1;
  313. tor_assert(addr);
  314. if (address) {
  315. strlcpy(hostname, address, sizeof(hostname));
  316. } else { /* then we need to guess our address */
  317. explicit_ip = 0; /* it's implicit */
  318. if (gethostname(hostname, sizeof(hostname)) < 0) {
  319. log_fn(LOG_WARN,"Error obtaining local hostname");
  320. return -1;
  321. }
  322. log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname);
  323. }
  324. /* now we know hostname. resolve it and keep only the IP */
  325. if (tor_inet_aton(hostname, &in) == 0) {
  326. /* then we have to resolve it */
  327. explicit_ip = 0;
  328. rent = (struct hostent *)gethostbyname(hostname);
  329. if (!rent) {
  330. log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname);
  331. return -1;
  332. }
  333. tor_assert(rent->h_length == 4);
  334. memcpy(&in.s_addr, rent->h_addr, rent->h_length);
  335. }
  336. if (!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
  337. log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
  338. "Please set the Address config option to be the IP you want to use.",
  339. hostname, inet_ntoa(in));
  340. return -1;
  341. }
  342. log_fn(LOG_DEBUG, "Resolved Address to %s.", inet_ntoa(in));
  343. *addr = ntohl(in.s_addr);
  344. return 0;
  345. }
  346. static char *
  347. get_default_nickname(void)
  348. {
  349. char localhostname[256];
  350. char *cp, *out, *outp;
  351. if (gethostname(localhostname, sizeof(localhostname)) < 0) {
  352. log_fn(LOG_WARN,"Error obtaining local hostname");
  353. return NULL;
  354. }
  355. /* Put it in lowercase; stop at the first dot. */
  356. for (cp = localhostname; *cp; ++cp) {
  357. if (*cp == '.') {
  358. *cp = '\0';
  359. break;
  360. }
  361. *cp = tolower(*cp);
  362. }
  363. /* Strip invalid characters. */
  364. cp = localhostname;
  365. out = outp = tor_malloc(strlen(localhostname) + 1);
  366. while (*cp) {
  367. if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
  368. *outp++ = *cp++;
  369. else
  370. cp++;
  371. }
  372. *outp = '\0';
  373. /* Enforce length. */
  374. if (strlen(out) > MAX_NICKNAME_LEN)
  375. out[MAX_NICKNAME_LEN]='\0';
  376. return out;
  377. }
  378. /** Release storage held by <b>options</b> */
  379. static void
  380. free_options(or_options_t *options)
  381. {
  382. config_free_lines(options->LogOptions);
  383. tor_free(options->ContactInfo);
  384. tor_free(options->DebugLogFile);
  385. tor_free(options->DataDirectory);
  386. tor_free(options->Nickname);
  387. tor_free(options->Address);
  388. tor_free(options->PidFile);
  389. tor_free(options->ExitNodes);
  390. tor_free(options->EntryNodes);
  391. tor_free(options->ExcludeNodes);
  392. tor_free(options->RendNodes);
  393. tor_free(options->RendExcludeNodes);
  394. tor_free(options->OutboundBindAddress);
  395. tor_free(options->User);
  396. tor_free(options->Group);
  397. tor_free(options->HttpProxy);
  398. config_free_lines(options->RendConfigLines);
  399. config_free_lines(options->SocksBindAddress);
  400. config_free_lines(options->ORBindAddress);
  401. config_free_lines(options->DirBindAddress);
  402. config_free_lines(options->ExitPolicy);
  403. config_free_lines(options->SocksPolicy);
  404. config_free_lines(options->DirServers);
  405. config_free_lines(options->RecommendedVersions);
  406. config_free_lines(options->NodeFamilies);
  407. config_free_lines(options->RedirectExit);
  408. if (options->RedirectExitList) {
  409. SMARTLIST_FOREACH(options->RedirectExitList,
  410. exit_redirect_t *, p, tor_free(p));
  411. smartlist_free(options->RedirectExitList);
  412. options->RedirectExitList = NULL;
  413. }
  414. if (options->FirewallPorts) {
  415. SMARTLIST_FOREACH(options->FirewallPorts, char *, cp, tor_free(cp));
  416. smartlist_free(options->FirewallPorts);
  417. options->FirewallPorts = NULL;
  418. }
  419. }
  420. /** Set <b>options</b> to hold reasonable defaults for most options.
  421. * Each option defaults to zero. */
  422. static void
  423. init_options(or_options_t *options)
  424. {
  425. memset(options,0,sizeof(or_options_t));
  426. options->ExitNodes = tor_strdup("");
  427. options->EntryNodes = tor_strdup("");
  428. options->StrictEntryNodes = options->StrictExitNodes = 0;
  429. options->ExcludeNodes = tor_strdup("");
  430. options->RendNodes = tor_strdup("");
  431. options->RendExcludeNodes = tor_strdup("");
  432. /* options->PidFile = tor_strdup("tor.pid"); */
  433. options->PathlenCoinWeight = 0.3;
  434. options->MaxConn = 900;
  435. options->DirFetchPostPeriod = 600;
  436. options->KeepalivePeriod = 300;
  437. options->MaxOnionsPending = 100;
  438. options->NewCircuitPeriod = 30; /* twice a minute */
  439. options->BandwidthRate = 800000; /* at most 800kB/s total sustained incoming */
  440. options->BandwidthBurst = 10000000; /* max burst on the token bucket */
  441. options->NumCpus = 1;
  442. }
  443. #ifdef MS_WINDOWS
  444. static char *get_windows_conf_root(void)
  445. {
  446. static int is_set = 0;
  447. static char path[MAX_PATH+1];
  448. LPITEMIDLIST idl;
  449. IMalloc *m;
  450. HRESULT result;
  451. if (is_set)
  452. return path;
  453. /* Find X:\documents and settings\username\applicatation data\ .
  454. * We would use SHGetSpecialFolder path, but that wasn't added until IE4.
  455. */
  456. if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA,
  457. &idl))) {
  458. GetCurrentDirectory(MAX_PATH, path);
  459. is_set = 1;
  460. log_fn(LOG_WARN, "I couldn't find your application data folder: are you running an ancient version of Windows 95? Defaulting to '%s'", path);
  461. return path;
  462. }
  463. /* Convert the path from an "ID List" (whatever that is!) to a path. */
  464. result = SHGetPathFromIDList(idl, path);
  465. /* Now we need to free the */
  466. SHGetMalloc(&m);
  467. if (m) {
  468. m->lpVtbl->Free(m, idl);
  469. m->lpVtbl->Release(m);
  470. }
  471. if (!SUCCEEDED(result)) {
  472. return NULL;
  473. }
  474. strlcat(path,"\\tor",MAX_PATH);
  475. is_set = 1;
  476. return path;
  477. }
  478. #endif
  479. static char *
  480. get_default_conf_file(void)
  481. {
  482. #ifdef MS_WINDOWS
  483. char *path = tor_malloc(MAX_PATH);
  484. strlcpy(path, get_windows_conf_root(), MAX_PATH);
  485. strlcat(path,"\\torrc",MAX_PATH);
  486. return path;
  487. #else
  488. return tor_strdup(CONFDIR "/torrc");
  489. #endif
  490. }
  491. /** Verify whether lst is a string containing valid-looking space-separated
  492. * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure.
  493. */
  494. static int check_nickname_list(const char *lst, const char *name)
  495. {
  496. int r = 0;
  497. smartlist_t *sl;
  498. if (!lst)
  499. return 0;
  500. sl = smartlist_create();
  501. smartlist_split_string(sl, lst, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  502. SMARTLIST_FOREACH(sl, const char *, s,
  503. {
  504. if (!is_legal_nickname_or_hexdigest(s)) {
  505. log_fn(LOG_WARN, "Invalid nickname '%s' in %s line", s, name);
  506. r = -1;
  507. }
  508. });
  509. SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
  510. smartlist_free(sl);
  511. return r;
  512. }
  513. /** Read a configuration file into <b>options</b>, finding the configuration
  514. * file location based on the command line. After loading the options,
  515. * validate them for consistency. Return 0 if success, <0 if failure. */
  516. int
  517. getconfig(int argc, char **argv, or_options_t *options)
  518. {
  519. struct config_line_t *cl;
  520. FILE *cf;
  521. char *fname;
  522. int i;
  523. int result = 0;
  524. static int first_load = 1;
  525. static char **backup_argv;
  526. static int backup_argc;
  527. char *previous_pidfile = NULL;
  528. int previous_runasdaemon = 0;
  529. int previous_orport = -1;
  530. int using_default_torrc;
  531. if (first_load) { /* first time we're called. save commandline args */
  532. backup_argv = argv;
  533. backup_argc = argc;
  534. first_load = 0;
  535. } else { /* we're reloading. need to clean up old ones first. */
  536. argv = backup_argv;
  537. argc = backup_argc;
  538. /* record some previous values, so we can fail if they change */
  539. if (options->PidFile)
  540. previous_pidfile = tor_strdup(options->PidFile);
  541. previous_runasdaemon = options->RunAsDaemon;
  542. previous_orport = options->ORPort;
  543. free_options(options);
  544. }
  545. init_options(options);
  546. if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) {
  547. print_usage();
  548. exit(0);
  549. }
  550. if (argc > 1 && (!strcmp(argv[1],"--version"))) {
  551. printf("Tor version %s.\n",VERSION);
  552. exit(0);
  553. }
  554. /* learn config file name, get config lines, assign them */
  555. i = 1;
  556. while (i < argc-1 && strcmp(argv[i],"-f")) {
  557. i++;
  558. }
  559. if (i < argc-1) { /* we found one */
  560. fname = tor_strdup(argv[i+1]);
  561. using_default_torrc = 0;
  562. } else {
  563. /* didn't find one, try CONFDIR */
  564. char *fn;
  565. using_default_torrc = 1;
  566. fn = get_default_conf_file();
  567. if (fn && file_status(fn) == FN_FILE) {
  568. fname = fn;
  569. } else {
  570. tor_free(fn);
  571. fn = expand_filename("~/.torrc");
  572. if (fn && file_status(fn) == FN_FILE) {
  573. fname = fn;
  574. } else {
  575. tor_free(fn);
  576. fname = get_default_conf_file();
  577. }
  578. }
  579. }
  580. tor_assert(fname);
  581. log(LOG_DEBUG, "Opening config file '%s'", fname);
  582. if (config_assign_defaults(options) < 0) {
  583. return -1;
  584. }
  585. cf = fopen(fname, "r");
  586. if (!cf) {
  587. if (using_default_torrc == 1) {
  588. log(LOG_NOTICE, "Configuration file '%s' not present, "
  589. "using reasonable defaults.", fname);
  590. tor_free(fname);
  591. } else {
  592. log(LOG_WARN, "Unable to open configuration file '%s'.", fname);
  593. tor_free(fname);
  594. return -1;
  595. }
  596. } else { /* it opened successfully. use it. */
  597. tor_free(fname);
  598. if (config_get_lines(cf, &cl)<0)
  599. return -1;
  600. if (config_assign(options,cl) < 0)
  601. return -1;
  602. config_free_lines(cl);
  603. fclose(cf);
  604. }
  605. /* go through command-line variables too */
  606. cl = config_get_commandlines(argc,argv);
  607. if (config_assign(options,cl) < 0)
  608. return -1;
  609. config_free_lines(cl);
  610. /* Validate options */
  611. /* first check if any of the previous options have changed but aren't allowed to */
  612. if (previous_pidfile && strcmp(previous_pidfile,options->PidFile)) {
  613. log_fn(LOG_WARN,"During reload, PidFile changed from %s to %s. Failing.",
  614. previous_pidfile, options->PidFile);
  615. return -1;
  616. }
  617. tor_free(previous_pidfile);
  618. if (previous_runasdaemon && !options->RunAsDaemon) {
  619. log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing.");
  620. return -1;
  621. }
  622. if (previous_orport == 0 && options->ORPort > 0) {
  623. log_fn(LOG_WARN,"During reload, change from ORPort=0 to >0 not allowed. Failing.");
  624. return -1;
  625. }
  626. if (options->ORPort < 0 || options->ORPort > 65535) {
  627. log(LOG_WARN, "ORPort option out of bounds.");
  628. result = -1;
  629. }
  630. if (options->Nickname == NULL) {
  631. if (server_mode()) {
  632. if (!(options->Nickname = get_default_nickname()))
  633. return -1;
  634. log_fn(LOG_NOTICE, "Choosing default nickname %s", options->Nickname);
  635. }
  636. } else {
  637. if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
  638. strlen(options->Nickname)) {
  639. log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
  640. result = -1;
  641. }
  642. if (strlen(options->Nickname) == 0) {
  643. log_fn(LOG_WARN, "Nickname must have at least one character");
  644. result = -1;
  645. }
  646. if (strlen(options->Nickname) > MAX_NICKNAME_LEN) {
  647. log_fn(LOG_WARN, "Nickname '%s' has more than %d characters.",
  648. options->Nickname, MAX_NICKNAME_LEN);
  649. result = -1;
  650. }
  651. }
  652. if (server_mode()) {
  653. /* confirm that our address isn't broken, so we can complain now */
  654. uint32_t tmp;
  655. if (resolve_my_address(options->Address, &tmp) < 0)
  656. result = -1;
  657. }
  658. if (options->SocksPort < 0 || options->SocksPort > 65535) {
  659. log(LOG_WARN, "SocksPort option out of bounds.");
  660. result = -1;
  661. }
  662. if (options->SocksPort == 0 && options->ORPort == 0) {
  663. log(LOG_WARN, "SocksPort and ORPort are both undefined? Quitting.");
  664. result = -1;
  665. }
  666. if (options->DirPort < 0 || options->DirPort > 65535) {
  667. log(LOG_WARN, "DirPort option out of bounds.");
  668. result = -1;
  669. }
  670. if (options->StrictExitNodes && !strlen(options->ExitNodes)) {
  671. log(LOG_WARN, "StrictExitNodes set, but no ExitNodes listed.");
  672. }
  673. if (options->StrictEntryNodes && !strlen(options->EntryNodes)) {
  674. log(LOG_WARN, "StrictEntryNodes set, but no EntryNodes listed.");
  675. }
  676. if (options->AuthoritativeDir && options->RecommendedVersions == NULL) {
  677. log(LOG_WARN, "Directory servers must configure RecommendedVersions.");
  678. result = -1;
  679. }
  680. if (options->AuthoritativeDir && !options->DirPort) {
  681. log(LOG_WARN, "Running as authoritative directory, but no DirPort set.");
  682. result = -1;
  683. }
  684. if (options->AuthoritativeDir && !options->ORPort) {
  685. log(LOG_WARN, "Running as authoritative directory, but no ORPort set.");
  686. result = -1;
  687. }
  688. if (options->AuthoritativeDir && options->ClientOnly) {
  689. log(LOG_WARN, "Running as authoritative directory, but ClientOnly also set.");
  690. result = -1;
  691. }
  692. if (options->FascistFirewall && !options->FirewallPorts) {
  693. options->FirewallPorts = smartlist_create();
  694. smartlist_add(options->FirewallPorts, tor_strdup("80"));
  695. smartlist_add(options->FirewallPorts, tor_strdup("443"));
  696. }
  697. if (options->FirewallPorts) {
  698. SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp,
  699. {
  700. i = atoi(cp);
  701. if (i < 1 || i > 65535) {
  702. log(LOG_WARN, "Port '%s' out of range in FirewallPorts", cp);
  703. result=-1;
  704. }
  705. });
  706. }
  707. options->_AllowUnverified = 0;
  708. if (options->AllowUnverifiedNodes) {
  709. SMARTLIST_FOREACH(options->AllowUnverifiedNodes, const char *, cp, {
  710. if (!strcasecmp(cp, "entry"))
  711. options->_AllowUnverified |= ALLOW_UNVERIFIED_ENTRY;
  712. else if (!strcasecmp(cp, "exit"))
  713. options->_AllowUnverified |= ALLOW_UNVERIFIED_EXIT;
  714. else if (!strcasecmp(cp, "middle"))
  715. options->_AllowUnverified |= ALLOW_UNVERIFIED_MIDDLE;
  716. else if (!strcasecmp(cp, "introduction"))
  717. options->_AllowUnverified |= ALLOW_UNVERIFIED_INTRODUCTION;
  718. else if (!strcasecmp(cp, "rendezvous"))
  719. options->_AllowUnverified |= ALLOW_UNVERIFIED_RENDEZVOUS;
  720. else {
  721. log(LOG_WARN, "Unrecognized value '%s' in AllowUnverifiedNodes",
  722. cp);
  723. result=-1;
  724. }
  725. });
  726. }
  727. if (options->SocksPort >= 1 &&
  728. (options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0)) {
  729. log(LOG_WARN, "PathlenCoinWeight option must be >=0.0 and <1.0.");
  730. result = -1;
  731. }
  732. if (options->MaxConn < 1) {
  733. log(LOG_WARN, "MaxConn option must be a non-zero positive integer.");
  734. result = -1;
  735. }
  736. if (options->MaxConn >= MAXCONNECTIONS) {
  737. log(LOG_WARN, "MaxConn option must be less than %d.", MAXCONNECTIONS);
  738. result = -1;
  739. }
  740. #define MIN_DIRFETCHPOSTPERIOD 60
  741. if (options->DirFetchPostPeriod < MIN_DIRFETCHPOSTPERIOD) {
  742. log(LOG_WARN, "DirFetchPostPeriod option must be at least %d.", MIN_DIRFETCHPOSTPERIOD);
  743. result = -1;
  744. }
  745. if (options->DirFetchPostPeriod > MIN_ONION_KEY_LIFETIME / 2) {
  746. log(LOG_WARN, "DirFetchPostPeriod is too large; clipping.");
  747. options->DirFetchPostPeriod = MIN_ONION_KEY_LIFETIME / 2;
  748. }
  749. if (options->KeepalivePeriod < 1) {
  750. log(LOG_WARN,"KeepalivePeriod option must be positive.");
  751. result = -1;
  752. }
  753. if (options->HttpProxy) { /* parse it now */
  754. if (parse_addr_port(options->HttpProxy, NULL,
  755. &options->HttpProxyAddr, &options->HttpProxyPort) < 0) {
  756. log(LOG_WARN,"HttpProxy failed to parse or resolve. Please fix.");
  757. result = -1;
  758. }
  759. if (options->HttpProxyPort == 0) { /* give it a default */
  760. options->HttpProxyPort = 80;
  761. }
  762. }
  763. if (check_nickname_list(options->ExitNodes, "ExitNodes"))
  764. return -1;
  765. if (check_nickname_list(options->EntryNodes, "EntryNodes"))
  766. return -1;
  767. if (check_nickname_list(options->ExcludeNodes, "ExcludeNodes"))
  768. return -1;
  769. if (check_nickname_list(options->RendNodes, "RendNodes"))
  770. return -1;
  771. if (check_nickname_list(options->RendNodes, "RendExcludeNodes"))
  772. return -1;
  773. if (check_nickname_list(options->MyFamily, "MyFamily"))
  774. return -1;
  775. for (cl = options->NodeFamilies; cl; cl = cl->next) {
  776. if (check_nickname_list(cl->value, "NodeFamily"))
  777. return -1;
  778. }
  779. if (!options->RedirectExitList)
  780. options->RedirectExitList = smartlist_create();
  781. for (cl = options->RedirectExit; cl; cl = cl->next) {
  782. if (parse_redirect_line(options, cl)<0)
  783. return -1;
  784. }
  785. clear_trusted_dir_servers();
  786. if (!options->DirServers) {
  787. add_default_trusted_dirservers();
  788. } else {
  789. for (cl = options->DirServers; cl; cl = cl->next) {
  790. if (parse_dir_server_line(cl->value)<0)
  791. return -1;
  792. }
  793. }
  794. if (rend_config_services(options) < 0) {
  795. result = -1;
  796. }
  797. return result;
  798. }
  799. static int
  800. add_single_log(struct config_line_t *level_opt,
  801. struct config_line_t *file_opt, int isDaemon)
  802. {
  803. int levelMin = -1, levelMax = -1;
  804. char *cp, *tmp_sev;
  805. if (level_opt) {
  806. cp = strchr(level_opt->value, '-');
  807. if (cp) {
  808. tmp_sev = tor_strndup(level_opt->value, cp - level_opt->value);
  809. levelMin = parse_log_level(tmp_sev);
  810. if (levelMin < 0) {
  811. log_fn(LOG_WARN, "Unrecognized log severity '%s': must be one of "
  812. "err|warn|notice|info|debug", tmp_sev);
  813. return -1;
  814. }
  815. tor_free(tmp_sev);
  816. levelMax = parse_log_level(cp+1);
  817. if (levelMax < 0) {
  818. log_fn(LOG_WARN, "Unrecognized log severity '%s': must be one of "
  819. "err|warn|notice|info|debug", cp+1);
  820. return -1;
  821. }
  822. } else {
  823. levelMin = parse_log_level(level_opt->value);
  824. if (levelMin < 0) {
  825. log_fn(LOG_WARN, "Unrecognized log severity '%s': must be one of "
  826. "err|warn|notice|info|debug", level_opt->value);
  827. return -1;
  828. }
  829. }
  830. }
  831. if (levelMin < 0 && levelMax < 0) {
  832. levelMin = LOG_NOTICE;
  833. levelMax = LOG_ERR;
  834. } else if (levelMin < 0) {
  835. levelMin = levelMax;
  836. } else {
  837. levelMax = LOG_ERR;
  838. }
  839. if (file_opt) {
  840. if (add_file_log(levelMin, levelMax, file_opt->value) < 0) {
  841. log_fn(LOG_WARN, "Cannot write to LogFile '%s': %s.", file_opt->value,
  842. strerror(errno));
  843. return -1;
  844. }
  845. log_fn(LOG_NOTICE, "Successfully opened LogFile '%s', redirecting output.",
  846. file_opt->value);
  847. } else if (!isDaemon) {
  848. add_stream_log(levelMin, levelMax, "<stdout>", stdout);
  849. close_temp_logs();
  850. }
  851. return 0;
  852. }
  853. /**
  854. * Initialize the logs based on the configuration file.
  855. */
  856. int
  857. config_init_logs(or_options_t *options)
  858. {
  859. /* The order of options is: Level? (File Level?)+
  860. */
  861. struct config_line_t *opt = options->LogOptions;
  862. /* Special case if no options are given. */
  863. if (!opt) {
  864. add_stream_log(LOG_NOTICE, LOG_ERR, "<stdout>", stdout);
  865. close_temp_logs();
  866. /* don't return yet, in case we want to do a debuglogfile below */
  867. }
  868. /* Special case for if first option is LogLevel. */
  869. if (opt && !strcasecmp(opt->key, "LogLevel")) {
  870. if (opt->next && !strcasecmp(opt->next->key, "LogFile")) {
  871. if (add_single_log(opt, opt->next, options->RunAsDaemon) < 0)
  872. return -1;
  873. opt = opt->next->next;
  874. } else if (!opt->next) {
  875. if (add_single_log(opt, NULL, options->RunAsDaemon) < 0)
  876. return -1;
  877. opt = opt->next;
  878. } else {
  879. ; /* give warning below */
  880. }
  881. }
  882. while (opt) {
  883. if (!strcasecmp(opt->key, "LogLevel")) {
  884. log_fn(LOG_WARN, "Two LogLevel options in a row without intervening LogFile");
  885. opt = opt->next;
  886. } else {
  887. tor_assert(!strcasecmp(opt->key, "LogFile"));
  888. if (opt->next && !strcasecmp(opt->next->key, "LogLevel")) {
  889. /* LogFile followed by LogLevel */
  890. if (add_single_log(opt->next, opt, options->RunAsDaemon) < 0)
  891. return -1;
  892. opt = opt->next->next;
  893. } else {
  894. /* LogFile followed by LogFile or end of list. */
  895. if (add_single_log(NULL, opt, options->RunAsDaemon) < 0)
  896. return -1;
  897. opt = opt->next;
  898. }
  899. }
  900. }
  901. if (options->DebugLogFile) {
  902. log_fn(LOG_WARN, "DebugLogFile is deprecated; use LogFile and LogLevel instead");
  903. if (add_file_log(LOG_DEBUG, LOG_ERR, options->DebugLogFile) < 0)
  904. return -1;
  905. }
  906. return 0;
  907. }
  908. /**
  909. * Given a linked list of config lines containing "allow" and "deny" tokens,
  910. * parse them and place the result in <b>dest</b>. Skip malformed lines.
  911. */
  912. void
  913. config_parse_exit_policy(struct config_line_t *cfg,
  914. struct exit_policy_t **dest)
  915. {
  916. struct exit_policy_t **nextp;
  917. smartlist_t *entries;
  918. if (!cfg)
  919. return;
  920. nextp = dest;
  921. while (*nextp)
  922. nextp = &((*nextp)->next);
  923. entries = smartlist_create();
  924. for (; cfg; cfg = cfg->next) {
  925. smartlist_split_string(entries, cfg->value, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  926. SMARTLIST_FOREACH(entries, const char *, ent,
  927. {
  928. log_fn(LOG_DEBUG,"Adding new entry '%s'",ent);
  929. *nextp = router_parse_exit_policy_from_string(ent);
  930. if (*nextp) {
  931. nextp = &((*nextp)->next);
  932. } else {
  933. log_fn(LOG_WARN,"Malformed exit policy %s; skipping.", ent);
  934. }
  935. });
  936. SMARTLIST_FOREACH(entries, char *, ent, tor_free(ent));
  937. smartlist_clear(entries);
  938. }
  939. smartlist_free(entries);
  940. }
  941. void exit_policy_free(struct exit_policy_t *p) {
  942. struct exit_policy_t *e;
  943. while (p) {
  944. e = p;
  945. p = p->next;
  946. tor_free(e->string);
  947. tor_free(e);
  948. }
  949. }
  950. static int parse_redirect_line(or_options_t *options,
  951. struct config_line_t *line)
  952. {
  953. smartlist_t *elements = NULL;
  954. exit_redirect_t *r;
  955. tor_assert(options);
  956. tor_assert(options->RedirectExitList);
  957. tor_assert(line);
  958. r = tor_malloc_zero(sizeof(exit_redirect_t));
  959. elements = smartlist_create();
  960. smartlist_split_string(elements, line->value, " ",
  961. SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  962. if (smartlist_len(elements) != 2) {
  963. log_fn(LOG_WARN, "Wrong number of elements in RedirectExit line");
  964. goto err;
  965. }
  966. if (parse_addr_and_port_range(smartlist_get(elements,0),&r->addr,&r->mask,
  967. &r->port_min,&r->port_max)) {
  968. log_fn(LOG_WARN, "Error parsing source address in RedirectExit line");
  969. goto err;
  970. }
  971. if (0==strcasecmp(smartlist_get(elements,1), "pass")) {
  972. r->is_redirect = 0;
  973. } else {
  974. if (parse_addr_port(smartlist_get(elements,1),NULL,&r->addr_dest,
  975. &r->port_dest)) {
  976. log_fn(LOG_WARN, "Error parseing dest address in RedirectExit line");
  977. goto err;
  978. }
  979. r->is_redirect = 1;
  980. }
  981. goto done;
  982. err:
  983. tor_free(r);
  984. done:
  985. SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
  986. smartlist_free(elements);
  987. if (r) {
  988. smartlist_add(options->RedirectExitList, r);
  989. return 0;
  990. } else {
  991. return -1;
  992. }
  993. }
  994. static int parse_dir_server_line(const char *line)
  995. {
  996. smartlist_t *items = NULL;
  997. int r;
  998. char *addrport, *address=NULL;
  999. uint16_t port;
  1000. char digest[DIGEST_LEN];
  1001. items = smartlist_create();
  1002. smartlist_split_string(items, line, " ",
  1003. SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
  1004. if (smartlist_len(items) < 2) {
  1005. log_fn(LOG_WARN, "Too few arguments to DirServer line.");
  1006. goto err;
  1007. }
  1008. addrport = smartlist_get(items, 0);
  1009. if (parse_addr_port(addrport, &address, NULL, &port)<0) {
  1010. log_fn(LOG_WARN, "Error parsing DirServer address '%s'", addrport);
  1011. goto err;
  1012. }
  1013. if (!port) {
  1014. log_fn(LOG_WARN, "Missing port in DirServe address '%s'",addrport);
  1015. goto err;
  1016. }
  1017. tor_strstrip(smartlist_get(items, 1), " ");
  1018. if (strlen(smartlist_get(items, 1)) != HEX_DIGEST_LEN) {
  1019. log_fn(LOG_WARN, "Key digest for DirServer is wrong length.");
  1020. goto err;
  1021. }
  1022. if (base16_decode(digest, DIGEST_LEN,
  1023. smartlist_get(items,1), HEX_DIGEST_LEN)<0) {
  1024. log_fn(LOG_WARN, "Unable to decode DirServer key digest.");
  1025. goto err;
  1026. }
  1027. log_fn(LOG_DEBUG, "Trusted dirserver at %s:%d (%s)", address, (int)port,
  1028. (char*)smartlist_get(items,1));
  1029. add_trusted_dir_server(address, port, digest);
  1030. r = 0;
  1031. goto done;
  1032. err:
  1033. r = -1;
  1034. done:
  1035. SMARTLIST_FOREACH(items, char*, s, tor_free(s));
  1036. smartlist_free(items);
  1037. if (address)
  1038. tor_free(address);
  1039. return r;
  1040. }
  1041. const char *
  1042. get_data_directory(or_options_t *options)
  1043. {
  1044. const char *d;
  1045. if (options->DataDirectory) {
  1046. d = options->DataDirectory;
  1047. } else {
  1048. #ifdef MS_WINDOWS
  1049. char *p;
  1050. p = tor_malloc(MAX_PATH);
  1051. strlcpy(p,get_windows_conf_root(),MAX_PATH);
  1052. options->DataDirectory = p;
  1053. return p;
  1054. #else
  1055. d = "~/.tor";
  1056. #endif
  1057. }
  1058. if (d && strncmp(d,"~/",2) == 0) {
  1059. char *fn = expand_filename(d);
  1060. if (!fn) {
  1061. log_fn(LOG_ERR,"Failed to expand filename '%s'. Exiting.", d);
  1062. exit(1);
  1063. }
  1064. tor_free(options->DataDirectory);
  1065. options->DataDirectory = fn;
  1066. }
  1067. return options->DataDirectory;
  1068. }
  1069. /*
  1070. Local Variables:
  1071. mode:c
  1072. indent-tabs-mode:nil
  1073. c-basic-offset:2
  1074. End:
  1075. */