dirserv.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. /**
  6. * \file dirserv.c
  7. * \brief Directory server core implementation.
  8. **/
  9. /** How old do we allow a router to get before removing it? (seconds) */
  10. #define ROUTER_MAX_AGE (60*60*24)
  11. /** How far in the future do we allow a router to get? (seconds) */
  12. #define ROUTER_ALLOW_SKEW (30*60)
  13. extern or_options_t options; /**< command-line and config-file options */
  14. /** Do we need to regenerate the directory when someone asks for it? */
  15. static int the_directory_is_dirty = 1;
  16. static int list_running_servers(char **nicknames_out);
  17. static void directory_remove_unrecognized(void);
  18. /************** Fingerprint handling code ************/
  19. typedef struct fingerprint_entry_t {
  20. char *nickname;
  21. char *fingerprint;
  22. } fingerprint_entry_t;
  23. /** List of nickname-\>identity fingerprint mappings for all the routers
  24. * that we recognize. Used to prevent Sybil attacks. */
  25. static smartlist_t *fingerprint_list = NULL;
  26. /** Add the fingerprint <b>fp</b> for the nickname <b>nickname</b> to
  27. * the global list of recognized identity key fingerprints.
  28. */
  29. void /* Should be static; exposed for testing */
  30. add_fingerprint_to_dir(const char *nickname, const char *fp)
  31. {
  32. int i;
  33. fingerprint_entry_t *ent;
  34. if (!fingerprint_list)
  35. fingerprint_list = smartlist_create();
  36. for (i = 0; i < smartlist_len(fingerprint_list); ++i) {
  37. ent = smartlist_get(fingerprint_list, i);
  38. if (!strcasecmp(ent->nickname,nickname)) {
  39. tor_free(ent->fingerprint);
  40. ent->fingerprint = tor_strdup(fp);
  41. return;
  42. }
  43. }
  44. ent = tor_malloc(sizeof(fingerprint_entry_t));
  45. ent->nickname = tor_strdup(nickname);
  46. ent->fingerprint = tor_strdup(fp);
  47. smartlist_add(fingerprint_list, ent);
  48. }
  49. /** Add the nickname and fingerprint for this OR to the recognized list.
  50. */
  51. int
  52. dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk)
  53. {
  54. char fp[FINGERPRINT_LEN+1];
  55. if (crypto_pk_get_fingerprint(pk, fp)<0) {
  56. log_fn(LOG_ERR, "Error computing fingerprint");
  57. return -1;
  58. }
  59. add_fingerprint_to_dir(nickname, fp);
  60. return 0;
  61. }
  62. /** Parse the nickname-\>fingerprint mappings stored in the file named
  63. * <b>fname</b>. The file format is line-based, with each non-blank
  64. * holding one nickname, some space, and a fingerprint for that
  65. * nickname. On success, replace the current fingerprint list with
  66. * the contents of <b>fname</b> and return 0. On failure, leave the
  67. * current fingerprint list untouched, and return -1. */
  68. int
  69. dirserv_parse_fingerprint_file(const char *fname)
  70. {
  71. FILE *file;
  72. char line[FINGERPRINT_LEN+MAX_NICKNAME_LEN+20+1];
  73. char *nickname, *fingerprint;
  74. smartlist_t *fingerprint_list_new;
  75. int i, result;
  76. fingerprint_entry_t *ent;
  77. if(!(file = fopen(fname, "r"))) {
  78. log_fn(LOG_WARN, "Cannot open fingerprint file %s", fname);
  79. return -1;
  80. }
  81. fingerprint_list_new = smartlist_create();
  82. while( (result=parse_line_from_file(line, sizeof(line),file,&nickname,&fingerprint)) > 0) {
  83. if (strlen(nickname) > MAX_NICKNAME_LEN) {
  84. log(LOG_WARN, "Nickname %s too long in fingerprint file. Skipping.", nickname);
  85. continue;
  86. }
  87. if(strlen(fingerprint) != FINGERPRINT_LEN ||
  88. !crypto_pk_check_fingerprint_syntax(fingerprint)) {
  89. log_fn(LOG_WARN, "Invalid fingerprint (nickname %s, fingerprint %s). Skipping.",
  90. nickname, fingerprint);
  91. continue;
  92. }
  93. for (i = 0; i < smartlist_len(fingerprint_list_new); ++i) {
  94. ent = smartlist_get(fingerprint_list_new, i);
  95. if (0==strcasecmp(ent->nickname, nickname)) {
  96. log(LOG_WARN, "Duplicate nickname %s. Skipping.",nickname);
  97. break; /* out of the for. the 'if' below means skip to the next line. */
  98. }
  99. }
  100. if(i == smartlist_len(fingerprint_list_new)) { /* not a duplicate */
  101. ent = tor_malloc(sizeof(fingerprint_entry_t));
  102. ent->nickname = tor_strdup(nickname);
  103. ent->fingerprint = tor_strdup(fingerprint);
  104. smartlist_add(fingerprint_list_new, ent);
  105. }
  106. }
  107. fclose(file);
  108. if(result == 0) { /* eof; replace the global fingerprints list. */
  109. dirserv_free_fingerprint_list();
  110. fingerprint_list = fingerprint_list_new;
  111. /* Delete any routers whose fingerprints we no longer recognize */
  112. directory_remove_unrecognized();
  113. return 0;
  114. }
  115. /* error */
  116. log_fn(LOG_WARN, "Error reading from fingerprint file");
  117. for (i = 0; i < smartlist_len(fingerprint_list_new); ++i) {
  118. ent = smartlist_get(fingerprint_list_new, i);
  119. tor_free(ent->nickname);
  120. tor_free(ent->fingerprint);
  121. tor_free(ent);
  122. }
  123. smartlist_free(fingerprint_list_new);
  124. return -1;
  125. }
  126. /** Check whether <b>router</b> has a nickname/identity key combination that
  127. * we recognize from the fingerprint list. Return 1 if router's
  128. * identity and nickname match, -1 if we recognize the nickname but
  129. * the identity key is wrong, and 0 if the nickname is not known. */
  130. int
  131. dirserv_router_fingerprint_is_known(const routerinfo_t *router)
  132. {
  133. int i, found=0;
  134. fingerprint_entry_t *ent =NULL;
  135. char fp[FINGERPRINT_LEN+1];
  136. if (!fingerprint_list)
  137. fingerprint_list = smartlist_create();
  138. log_fn(LOG_DEBUG, "%d fingerprints known.", smartlist_len(fingerprint_list));
  139. for (i=0;i<smartlist_len(fingerprint_list);++i) {
  140. ent = smartlist_get(fingerprint_list, i);
  141. log_fn(LOG_DEBUG,"%s vs %s", router->nickname, ent->nickname);
  142. if (!strcasecmp(router->nickname,ent->nickname)) {
  143. found = 1;
  144. break;
  145. }
  146. }
  147. if (!found) { /* No such server known */
  148. log_fn(LOG_INFO,"no fingerprint found for %s",router->nickname);
  149. return 0;
  150. }
  151. if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) {
  152. log_fn(LOG_WARN,"error computing fingerprint");
  153. return -1;
  154. }
  155. if (0==strcasecmp(ent->fingerprint, fp)) {
  156. log_fn(LOG_DEBUG,"good fingerprint for %s",router->nickname);
  157. return 1; /* Right fingerprint. */
  158. } else {
  159. log_fn(LOG_WARN,"mismatched fingerprint for %s",router->nickname);
  160. return -1; /* Wrong fingerprint. */
  161. }
  162. }
  163. /** Return true iff any router named <b>nickname</b> is in the fingerprint
  164. * list. */
  165. static int
  166. router_nickname_is_approved(const char *nickname)
  167. {
  168. int i;
  169. fingerprint_entry_t *ent;
  170. if (!fingerprint_list)
  171. return 0;
  172. for (i=0;i<smartlist_len(fingerprint_list);++i) {
  173. ent = smartlist_get(fingerprint_list, i);
  174. if (!strcasecmp(nickname,ent->nickname)) {
  175. return 1;
  176. }
  177. }
  178. return 0;
  179. }
  180. /** Clear the current fingerprint list. */
  181. void
  182. dirserv_free_fingerprint_list()
  183. {
  184. int i;
  185. fingerprint_entry_t *ent;
  186. if (!fingerprint_list)
  187. return;
  188. for (i = 0; i < smartlist_len(fingerprint_list); ++i) {
  189. ent = smartlist_get(fingerprint_list, i);
  190. tor_free(ent->nickname);
  191. tor_free(ent->fingerprint);
  192. tor_free(ent);
  193. }
  194. smartlist_free(fingerprint_list);
  195. fingerprint_list = NULL;
  196. }
  197. /*
  198. * Descriptor list
  199. */
  200. /** A directory server's view of a server descriptor. Contains both
  201. * parsed and unparsed versions. */
  202. typedef struct descriptor_entry_t {
  203. char *nickname;
  204. time_t published;
  205. size_t desc_len;
  206. char *descriptor;
  207. routerinfo_t *router;
  208. } descriptor_entry_t;
  209. /** List of all server descriptors that this dirserv is holding. */
  210. static smartlist_t *descriptor_list = NULL;
  211. /** Release the storage held by <b>desc</b> */
  212. static void free_descriptor_entry(descriptor_entry_t *desc)
  213. {
  214. tor_free(desc->descriptor);
  215. tor_free(desc->nickname);
  216. routerinfo_free(desc->router);
  217. free(desc);
  218. }
  219. /** Release all storage that the dirserv is holding for server
  220. * descriptors. */
  221. void
  222. dirserv_free_descriptors()
  223. {
  224. if (!descriptor_list)
  225. return;
  226. SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
  227. free_descriptor_entry(d));
  228. smartlist_clear(descriptor_list);
  229. }
  230. /** Parse the server descriptor at *desc and maybe insert it into the
  231. * list of service descriptors, and (if the descriptor is well-formed)
  232. * advance *desc immediately past the descriptor's end.
  233. *
  234. * Return 1 if descriptor is well-formed and accepted;
  235. * 0 if well-formed and server is unapproved;
  236. * -1 if not well-formed or other error.
  237. */
  238. int
  239. dirserv_add_descriptor(const char **desc)
  240. {
  241. descriptor_entry_t *ent = NULL;
  242. routerinfo_t *ri = NULL;
  243. int i, r, found=-1;
  244. char *start, *end;
  245. char *desc_tmp = NULL;
  246. const char *cp;
  247. size_t desc_len;
  248. time_t now;
  249. if (!descriptor_list)
  250. descriptor_list = smartlist_create();
  251. start = strstr(*desc, "router ");
  252. if (!start) {
  253. log_fn(LOG_WARN, "no 'router' line found. This is not a descriptor.");
  254. return -1;
  255. }
  256. if ((end = strstr(start+6, "\nrouter "))) {
  257. ++end; /* Include NL. */
  258. } else if ((end = strstr(start+6, "\ndirectory-signature"))) {
  259. ++end;
  260. } else {
  261. end = start+strlen(start);
  262. }
  263. desc_len = end-start;
  264. cp = desc_tmp = tor_strndup(start, desc_len);
  265. /* Check: is the descriptor syntactically valid? */
  266. ri = router_parse_entry_from_string(cp, NULL);
  267. tor_free(desc_tmp);
  268. if (!ri) {
  269. log(LOG_WARN, "Couldn't parse descriptor");
  270. return -1;
  271. }
  272. /* Okay. Now check whether the fingerprint is recognized. */
  273. r = dirserv_router_fingerprint_is_known(ri);
  274. if(r<1) {
  275. if(r==0) {
  276. char fp[FINGERPRINT_LEN+1];
  277. log_fn(LOG_WARN, "Unknown nickname %s (%s:%d). Not adding.",
  278. ri->nickname, ri->address, ri->or_port);
  279. if (crypto_pk_get_fingerprint(ri->identity_pkey, fp) < 0) {
  280. log_fn(LOG_WARN, "Error computing fingerprint for %s", ri->nickname);
  281. } else {
  282. log_fn(LOG_WARN, "Fingerprint line: %s %s", ri->nickname, fp);
  283. }
  284. } else {
  285. log_fn(LOG_WARN, "Known nickname %s, wrong fingerprint. Not adding.", ri->nickname);
  286. }
  287. routerinfo_free(ri);
  288. *desc = end;
  289. return 0;
  290. }
  291. /* Is there too much clock skew? */
  292. now = time(NULL);
  293. if (ri->published_on > now+ROUTER_ALLOW_SKEW) {
  294. log_fn(LOG_WARN, "Publication time for nickname %s is too far in the future; possible clock skew. Not adding.", ri->nickname);
  295. routerinfo_free(ri);
  296. *desc = end;
  297. return 0;
  298. }
  299. if (ri->published_on < now-ROUTER_MAX_AGE) {
  300. log_fn(LOG_WARN, "Publication time for router with nickname %s is too far in the past. Not adding.", ri->nickname);
  301. routerinfo_free(ri);
  302. *desc = end;
  303. return 0;
  304. }
  305. /* Do we already have an entry for this router? */
  306. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  307. ent = smartlist_get(descriptor_list, i);
  308. if (!strcasecmp(ri->nickname, ent->nickname)) {
  309. found = i;
  310. break;
  311. }
  312. }
  313. if (found >= 0) {
  314. /* if so, decide whether to update it. */
  315. if (ent->published > ri->published_on) {
  316. /* We already have a newer descriptor */
  317. log_fn(LOG_INFO,"We already have a newer desc for nickname %s. Not adding.",ri->nickname);
  318. /* This isn't really an error; return success. */
  319. routerinfo_free(ri);
  320. *desc = end;
  321. return 1;
  322. }
  323. /* We don't have a newer one; we'll update this one. */
  324. log_fn(LOG_INFO,"Dirserv updating desc for nickname %s",ri->nickname);
  325. free_descriptor_entry(ent);
  326. smartlist_del_keeporder(descriptor_list, found);
  327. } else {
  328. /* Add at the end. */
  329. log_fn(LOG_INFO,"Dirserv adding desc for nickname %s",ri->nickname);
  330. }
  331. ent = tor_malloc(sizeof(descriptor_entry_t));
  332. ent->nickname = tor_strdup(ri->nickname);
  333. ent->published = ri->published_on;
  334. ent->desc_len = desc_len;
  335. ent->descriptor = tor_malloc(desc_len+1);
  336. strncpy(ent->descriptor, start, desc_len);
  337. ent->descriptor[desc_len] = '\0';
  338. ent->router = ri;
  339. smartlist_add(descriptor_list, ent);
  340. *desc = end;
  341. directory_set_dirty();
  342. return 1;
  343. }
  344. /** Remove all descriptors whose nicknames or fingerprints we don't
  345. * recognize. (Descriptors that used to be good can become
  346. * unrecognized when we reload the fingerprint list.)
  347. */
  348. static void
  349. directory_remove_unrecognized(void)
  350. {
  351. int i;
  352. descriptor_entry_t *ent;
  353. if (!descriptor_list)
  354. descriptor_list = smartlist_create();
  355. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  356. ent = smartlist_get(descriptor_list, i);
  357. if (dirserv_router_fingerprint_is_known(ent->router)<=0) {
  358. log(LOG_INFO, "Router %s is no longer recognized",
  359. ent->nickname);
  360. free_descriptor_entry(ent);
  361. smartlist_del(descriptor_list, i--);
  362. }
  363. }
  364. }
  365. /** Mark the directory as <b>dirty</b> -- when we're next asked for a
  366. * directory, we will rebuild it instead of reusing the most recently
  367. * generated one.
  368. */
  369. void
  370. directory_set_dirty()
  371. {
  372. the_directory_is_dirty = 1;
  373. }
  374. /** Load all descriptors from an earlier directory stored in the string
  375. * <b>dir</b>.
  376. */
  377. int
  378. dirserv_init_from_directory_string(const char *dir)
  379. {
  380. const char *cp = dir;
  381. while(1) {
  382. cp = strstr(cp, "\nrouter ");
  383. if (!cp) break;
  384. ++cp;
  385. if (dirserv_add_descriptor(&cp) < 0) {
  386. return -1;
  387. }
  388. --cp; /*Back up to newline.*/
  389. }
  390. return 0;
  391. }
  392. /** Set *<b>nicknames_out</b> to a comma-separated list of all the ORs that we
  393. * believe are currently running (because we have open connections to
  394. * them). Return 0 on success; -1 on error.
  395. */
  396. static int
  397. list_running_servers(char **nicknames_out)
  398. {
  399. connection_t **connection_array;
  400. int n_conns;
  401. connection_t *conn;
  402. char *cp;
  403. int i;
  404. int length;
  405. smartlist_t *nicknames;
  406. *nicknames_out = NULL;
  407. nicknames = smartlist_create();
  408. smartlist_add(nicknames, options.Nickname);
  409. get_connection_array(&connection_array, &n_conns);
  410. for (i = 0; i<n_conns; ++i) {
  411. conn = connection_array[i];
  412. if (conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN)
  413. continue; /* only list successfully handshaked OR's. */
  414. if(!conn->nickname) /* it's an OP, don't list it */
  415. continue;
  416. if (!router_nickname_is_approved(conn->nickname))
  417. continue; /* If we removed them from the approved list, don't list it.*/
  418. smartlist_add(nicknames, conn->nickname);
  419. }
  420. length = smartlist_len(nicknames) + 1; /* spaces + EOS + 1. */
  421. SMARTLIST_FOREACH(nicknames, char *, c, length += strlen(c));
  422. *nicknames_out = tor_malloc_zero(length);
  423. cp = *nicknames_out;
  424. for (i = 0; i<smartlist_len(nicknames); ++i) {
  425. if (i)
  426. strcat(cp, " ");
  427. strcat(cp, (char*)smartlist_get(nicknames,i)); /* can't overflow */
  428. while (*cp)
  429. ++cp;
  430. }
  431. smartlist_free(nicknames);
  432. return 0;
  433. }
  434. /** Remove any descriptors from the directory that are more than ROUTER_MAX_AGE
  435. * seconds old.
  436. */
  437. void
  438. dirserv_remove_old_servers(void)
  439. {
  440. int i;
  441. time_t cutoff;
  442. descriptor_entry_t *ent;
  443. if (!descriptor_list)
  444. descriptor_list = smartlist_create();
  445. cutoff = time(NULL) - ROUTER_MAX_AGE;
  446. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  447. ent = smartlist_get(descriptor_list, i);
  448. if (ent->published < cutoff) {
  449. /* descriptor_list[i] is too old. Remove it. */
  450. free_descriptor_entry(ent);
  451. smartlist_del(descriptor_list, i--);
  452. directory_set_dirty();
  453. }
  454. }
  455. }
  456. /** Dump all routers currently in the directory into the string
  457. * <b>s</b>, using at most <b>maxlen</b> characters, and signing the
  458. * directory with <b>private_key</b>. Return 0 on success, -1 on
  459. * failure.
  460. */
  461. int
  462. dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
  463. crypto_pk_env_t *private_key)
  464. {
  465. char *cp, *eos;
  466. char digest[20];
  467. char signature[128];
  468. char published[33];
  469. time_t published_on;
  470. int i;
  471. eos = s+maxlen;
  472. if (!descriptor_list)
  473. descriptor_list = smartlist_create();
  474. if (list_running_servers(&cp))
  475. return -1;
  476. dirserv_remove_old_servers();
  477. published_on = time(NULL);
  478. strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
  479. snprintf(s, maxlen,
  480. "signed-directory\n"
  481. "published %s\n"
  482. "recommended-software %s\n"
  483. "running-routers %s\n\n", published, options.RecommendedVersions, cp);
  484. free(cp);
  485. i = strlen(s);
  486. cp = s+i;
  487. SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
  488. if (strlcat(s, d->descriptor, maxlen) >= maxlen)
  489. goto truncated);
  490. /* These multiple strlcat calls are inefficient, but dwarfed by the RSA
  491. signature.
  492. */
  493. if (strlcat(s, "directory-signature ", maxlen) >= maxlen)
  494. goto truncated;
  495. if (strlcat(s, options.Nickname, maxlen) >= maxlen)
  496. goto truncated;
  497. if (strlcat(s, "\n", maxlen) >= maxlen)
  498. goto truncated;
  499. if (router_get_dir_hash(s,digest)) {
  500. log_fn(LOG_WARN,"couldn't compute digest");
  501. return -1;
  502. }
  503. if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
  504. log_fn(LOG_WARN,"couldn't sign digest");
  505. return -1;
  506. }
  507. log(LOG_DEBUG,"generated directory digest begins with %s",hex_str(digest,4));
  508. if (strlcat(cp, "-----BEGIN SIGNATURE-----\n", maxlen) >= maxlen)
  509. goto truncated;
  510. i = strlen(s);
  511. cp = s+i;
  512. if (base64_encode(cp, maxlen-i, signature, 128) < 0) {
  513. log_fn(LOG_WARN,"couldn't base64-encode signature");
  514. return -1;
  515. }
  516. if (strlcat(s, "-----END SIGNATURE-----\n", maxlen) >= maxlen)
  517. goto truncated;
  518. return 0;
  519. truncated:
  520. log_fn(LOG_WARN,"tried to exceed string length.");
  521. return -1;
  522. }
  523. /** Most recently generated encoded signed directory. */
  524. static char *the_directory = NULL;
  525. static int the_directory_len = -1;
  526. /** Set *<b>directory</b> to the most recently generated encoded signed
  527. * directory, generating a new one as necessary. */
  528. size_t dirserv_get_directory(const char **directory)
  529. {
  530. char *new_directory;
  531. char filename[512];
  532. if (the_directory_is_dirty) {
  533. new_directory = tor_malloc(MAX_DIR_SIZE);
  534. if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE,
  535. get_identity_key())) {
  536. log(LOG_WARN, "Error creating directory.");
  537. free(new_directory);
  538. return 0;
  539. }
  540. tor_free(the_directory);
  541. the_directory = new_directory;
  542. the_directory_len = strlen(the_directory);
  543. log_fn(LOG_INFO,"New directory (size %d):\n%s",the_directory_len,
  544. the_directory);
  545. the_directory_is_dirty = 0;
  546. /* Now read the directory we just made in order to update our own
  547. * router lists. This does more signature checking than is strictly
  548. * necessary, but safe is better than sorry. */
  549. new_directory = tor_strdup(the_directory);
  550. /* use a new copy of the dir, since get_dir_from_string scribbles on it */
  551. if (router_load_routerlist_from_directory(new_directory, get_identity_key())) {
  552. log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying.");
  553. exit(0);
  554. }
  555. free(new_directory);
  556. sprintf(filename,"%s/cached-directory", options.DataDirectory);
  557. if(write_str_to_file(filename,the_directory) < 0) {
  558. log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
  559. }
  560. } else {
  561. log(LOG_INFO,"Directory still clean, reusing.");
  562. }
  563. *directory = the_directory;
  564. return the_directory_len;
  565. }
  566. /*
  567. Local Variables:
  568. mode:c
  569. indent-tabs-mode:nil
  570. c-basic-offset:2
  571. End:
  572. */