dirserv.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. static int the_directory_is_dirty = 1;
  6. static char *the_directory = NULL;
  7. static int the_directory_len = -1;
  8. /*
  9. * Fingerprint handling code.
  10. */
  11. typedef struct fingerprint_entry_t {
  12. char *nickname;
  13. char *fingerprint;
  14. } fingerprint_entry_t;
  15. static fingerprint_entry_t fingerprint_list[MAX_ROUTERS_IN_DIR];
  16. static int n_fingerprints = 0;
  17. /* return 0 on success, -1 on failure */
  18. int
  19. dirserv_parse_fingerprint_file(const char *fname)
  20. {
  21. FILE *file;
  22. #define BUF_LEN (FINGERPRINT_LEN+MAX_NICKNAME_LEN+20)
  23. char buf[BUF_LEN+1];
  24. char *cp, *nickname, *fingerprint;
  25. fingerprint_entry_t fingerprint_list_tmp[MAX_ROUTERS_IN_DIR];
  26. int n_fingerprints_tmp = 0;
  27. int lineno=0;
  28. int i;
  29. if (!(file = fopen(fname, "r"))) {
  30. log(LOG_WARNING, "Cannot open fingerprint file %s", fname);
  31. goto err;
  32. }
  33. while (1) {
  34. cp = fgets(buf, BUF_LEN, file);
  35. ++lineno;
  36. if (!cp) {
  37. if (feof(file))
  38. break;
  39. else {
  40. log(LOG_WARNING, "Error reading from fingerprint file");
  41. goto err;
  42. }
  43. }
  44. buf[BUF_LEN]='\0';
  45. cp = buf;
  46. while (isspace(*cp))
  47. ++cp;
  48. if (*cp == '#' || *cp == '\0')
  49. continue;
  50. nickname = cp;
  51. cp = strchr(cp, ' ');
  52. if (!cp) {
  53. log(LOG_WARNING, "Bad line %d of fingerprint file", lineno);
  54. goto err;
  55. }
  56. *cp++ = '\0';
  57. while (isspace(*cp))
  58. ++cp;
  59. if (strlen(cp) < FINGERPRINT_LEN) {
  60. log(LOG_WARNING, "Bad line %d of fingerprint file", lineno);
  61. goto err;
  62. }
  63. fingerprint = cp;
  64. cp[FINGERPRINT_LEN] = '\0';
  65. if (strlen(nickname) > MAX_NICKNAME_LEN) {
  66. log(LOG_WARNING, "Nickname too long on line %d of fingerprint file",
  67. lineno);
  68. goto err;
  69. }
  70. if (!crypto_pk_check_fingerprint_syntax(fingerprint)) {
  71. log(LOG_WARNING, "Invalid fingerprint on line %d of fingerprint file",
  72. lineno);
  73. goto err;
  74. }
  75. for (i = 0; i < n_fingerprints_tmp; ++i) {
  76. if (0==strcasecmp(fingerprint_list_tmp[i].nickname, nickname)) {
  77. log(LOG_WARNING, "Duplicate nickname on line %d of fingerprint file", lineno);
  78. goto err;
  79. }
  80. }
  81. fingerprint_list_tmp[n_fingerprints_tmp].nickname = strdup(nickname);
  82. fingerprint_list_tmp[n_fingerprints_tmp].fingerprint = strdup(fingerprint);
  83. ++n_fingerprints_tmp;
  84. }
  85. /* replace the global fingerprints list. */
  86. dirserv_free_fingerprint_list();
  87. memcpy(fingerprint_list, fingerprint_list_tmp,
  88. sizeof(fingerprint_entry_t)*n_fingerprints_tmp);
  89. n_fingerprints = n_fingerprints_tmp;
  90. return 0;
  91. err:
  92. for (i = 0; i < n_fingerprints_tmp; ++i) {
  93. free(fingerprint_list_tmp[i].nickname);
  94. free(fingerprint_list_tmp[i].fingerprint);
  95. }
  96. return -1;
  97. #undef BUF_LEN
  98. }
  99. /* return 1 if router's identity and nickname match. */
  100. int
  101. dirserv_router_fingerprint_is_known(const routerinfo_t *router)
  102. {
  103. int i;
  104. fingerprint_entry_t *ent =NULL;
  105. char fp[FINGERPRINT_LEN+1];
  106. for (i=0;i<n_fingerprints;++i) {
  107. if (!strcasecmp(router->nickname,fingerprint_list[i].nickname)) {
  108. ent = &fingerprint_list[i];
  109. break;
  110. }
  111. }
  112. if (!ent) {
  113. /* No such server known */
  114. return 0;
  115. }
  116. if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) {
  117. /* XXX Error computing fingerprint: log */
  118. return 0;
  119. }
  120. if (0==strcasecmp(ent->fingerprint, fp)) {
  121. /* Right fingerprint. */
  122. return 1;
  123. } else {
  124. /* Wrong fingerprint. */
  125. return 0;
  126. }
  127. }
  128. void
  129. dirserv_free_fingerprint_list()
  130. {
  131. int i;
  132. for (i = 0; i < n_fingerprints; ++i) {
  133. free(fingerprint_list[i].nickname);
  134. free(fingerprint_list[i].fingerprint);
  135. }
  136. n_fingerprints = 0;
  137. }
  138. /*
  139. * Descriptor list
  140. */
  141. typedef struct descriptor_entry_t {
  142. char *nickname;
  143. time_t published;
  144. size_t desc_len;
  145. char *descriptor;
  146. } descriptor_entry_t;
  147. static descriptor_entry_t *descriptor_list[MAX_ROUTERS_IN_DIR];
  148. static int n_descriptors = 0;
  149. static void free_descriptor_entry(descriptor_entry_t *desc)
  150. {
  151. if (desc->descriptor)
  152. free(desc->descriptor);
  153. if (desc->nickname)
  154. free(desc->nickname);
  155. free(desc);
  156. }
  157. void
  158. dirserv_free_descriptors()
  159. {
  160. int i;
  161. for (i = 0; i < n_descriptors; ++i) {
  162. free_descriptor_entry(descriptor_list[i]);
  163. }
  164. n_descriptors = 0;
  165. }
  166. /* Return 0 if descriptor added; -1 if descriptor rejected. Updates *desc
  167. * to point after the descriptor if the descriptor is OK.
  168. */
  169. int
  170. dirserv_add_descriptor(const char **desc)
  171. {
  172. descriptor_entry_t **desc_ent_ptr;
  173. routerinfo_t *ri = NULL;
  174. int i;
  175. char *start, *end;
  176. char *desc_tmp = NULL;
  177. size_t desc_len;
  178. start = strstr(*desc, "router ");
  179. if (!start) {
  180. log(LOG_WARNING, "no descriptor found.");
  181. goto err;
  182. }
  183. end = strstr(start+6, "\nrouter ");
  184. if (end) {
  185. ++end; /* Include NL. */
  186. } else {
  187. end = start+strlen(start);
  188. }
  189. desc_len = end-start;
  190. desc_tmp = tor_malloc(desc_len+1);
  191. strncpy(desc_tmp, start, desc_len);
  192. desc_tmp[desc_len]='\0';
  193. /* Check: is the descriptor syntactically valid? */
  194. ri = router_get_entry_from_string(&desc_tmp);
  195. if (!ri) {
  196. log(LOG_WARNING, "Couldn't parse descriptor");
  197. goto err;
  198. }
  199. free(desc_tmp); desc_tmp = NULL;
  200. /* Okay. Now check whether the fingerprint is recognized. */
  201. if (!dirserv_router_fingerprint_is_known(ri)) {
  202. log(LOG_WARNING, "Identity is unrecognized for descriptor");
  203. goto err;
  204. }
  205. /* Do we already have an entry for this router? */
  206. desc_ent_ptr = NULL;
  207. for (i = 0; i < n_descriptors; ++i) {
  208. if (!strcasecmp(ri->nickname, descriptor_list[i]->nickname)) {
  209. desc_ent_ptr = &descriptor_list[i];
  210. break;
  211. }
  212. }
  213. if (desc_ent_ptr) {
  214. /* if so, decide whether to update it. */
  215. if ((*desc_ent_ptr)->published > ri->published_on) {
  216. /* We already have a newer descriptor */
  217. goto err;
  218. }
  219. /* We don't have a newer one; we'll update this one. */
  220. free_descriptor_entry(*desc_ent_ptr);
  221. } else {
  222. /* Add this at the end. */
  223. desc_ent_ptr = &descriptor_list[n_descriptors++];
  224. }
  225. (*desc_ent_ptr) = tor_malloc(sizeof(descriptor_entry_t));
  226. (*desc_ent_ptr)->nickname = ri->nickname;
  227. (*desc_ent_ptr)->published = ri->published_on;
  228. (*desc_ent_ptr)->desc_len = desc_len;
  229. (*desc_ent_ptr)->descriptor = tor_malloc(desc_len+1);
  230. strncpy((*desc_ent_ptr)->descriptor, start, desc_len);
  231. (*desc_ent_ptr)->descriptor[desc_len] = '\0';
  232. *desc = end;
  233. the_directory_is_dirty = 1;
  234. routerinfo_free(ri);
  235. return 0;
  236. err:
  237. if (desc_tmp)
  238. free(desc_tmp);
  239. if (ri)
  240. routerinfo_free(ri);
  241. return -1;
  242. }
  243. void
  244. directory_set_dirty()
  245. {
  246. the_directory_is_dirty = 1;
  247. }
  248. int
  249. dirserv_init_from_directory_string(const char *dir)
  250. {
  251. const char *cp = dir;
  252. while(1) {
  253. cp = strstr(cp, "\nrouter ");
  254. if (!cp) break;
  255. ++cp;
  256. if (dirserv_add_descriptor(&cp)) {
  257. return -1;
  258. }
  259. --cp; /*Back up to newline.*/
  260. }
  261. return 0;
  262. }
  263. int
  264. dirserv_dump_directory_to_string(char *s, int maxlen,
  265. crypto_pk_env_t *private_key)
  266. {
  267. char *cp, *eos;
  268. char digest[20];
  269. char signature[128];
  270. char published[33];
  271. time_t published_on;
  272. int i;
  273. eos = s+maxlen;
  274. if (list_running_servers(&cp))
  275. return -1;
  276. published_on = time(NULL);
  277. strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
  278. snprintf(s, maxlen,
  279. "signed-directory\n"
  280. "published %s\n"
  281. "recommended-software "RECOMMENDED_SOFTWARE_VERSIONS"\n"
  282. "running-routers %s\n", published, cp);
  283. free(cp);
  284. i = strlen(s);
  285. cp = s+i;
  286. for (i = 0; i < n_descriptors; ++i) {
  287. strncat(cp, descriptor_list[i]->descriptor, descriptor_list[i]->desc_len);
  288. cp += descriptor_list[i]->desc_len;
  289. assert(!cp);
  290. }
  291. /* These multiple strlen calls are inefficient, but dwarfed by the RSA
  292. signature.
  293. */
  294. i = strlen(s);
  295. strncat(s, "directory-signature\n", maxlen-i);
  296. i = strlen(s);
  297. cp = s + i;
  298. if (crypto_SHA_digest(s, i, digest)) {
  299. log_fn(LOG_WARNING,"couldn't compute digest");
  300. return -1;
  301. }
  302. if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
  303. log_fn(LOG_WARNING,"couldn't sign digest");
  304. return -1;
  305. }
  306. strncpy(cp,
  307. "-----BEGIN SIGNATURE-----\n", maxlen-i);
  308. i = strlen(s);
  309. cp = s+i;
  310. if (base64_encode(cp, maxlen-i, signature, 128) < 0) {
  311. log_fn(LOG_WARNING," couldn't base64-encode signature");
  312. return -1;
  313. }
  314. i = strlen(s);
  315. cp = s+i;
  316. strncat(cp, "-----END SIGNATURE-----\n", maxlen-i);
  317. i = strlen(s);
  318. if (i == maxlen) {
  319. log_fn(LOG_WARNING,"tried to exceed string length.");
  320. return -1;
  321. }
  322. return 0;
  323. }
  324. size_t dirserv_get_directory(const char **directory)
  325. {
  326. char *new_directory;
  327. if (the_directory_is_dirty) {
  328. new_directory = tor_malloc(MAX_DIR_SIZE);
  329. if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE,
  330. get_identity_key())) {
  331. log(LOG_WARNING, "Error creating directory.");
  332. free(new_directory);
  333. return 0;
  334. }
  335. if (the_directory)
  336. free(the_directory);
  337. the_directory = new_directory;
  338. the_directory_len = strlen(the_directory);
  339. log_fn(LOG_INFO,"New directory (size %d):\n%s",the_directory_len,
  340. the_directory);
  341. the_directory_is_dirty = 0;
  342. /* Now read the directory we just made in order to update our own
  343. * router lists. This does more signature checking than is strictly
  344. * necessary, but safe is better than sorry. */
  345. new_directory = strdup(*directory);
  346. if (router_get_dir_from_string(new_directory, get_identity_key())) {
  347. log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying.");
  348. exit(0);
  349. }
  350. free(new_directory);
  351. } else {
  352. log(LOG_INFO,"Directory still clean, reusing.");
  353. }
  354. *directory = the_directory;
  355. return the_directory_len;
  356. }