Verify bittorrent .torrent metainfo files.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
11KB

  1. #include "metainfo.h"
  2. #include <errno.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdint.h>
  7. #include "sha1.h"
  8. #include "metainfo_http.h"
  9. /*
  10. * Read the file in memory, and return the pointer to it (which needs to be
  11. * freed) in out_contents and the size in out_size. If the file is too big,
  12. * fail. Returns 0 on success and an errno on fail.
  13. */
  14. static int metainfo_read_file(const char* path, char** out_contents, int* out_size) {
  15. int ret = 0;
  16. FILE* f = NULL;
  17. long size = 0;
  18. char* contents = NULL, *curr_contents = NULL;
  19. size_t read;
  20. f = fopen(path, "rb");
  21. if (!f) {
  22. ret = errno;
  23. goto end;
  24. }
  25. /* Get the file size, and bail if it's too large */
  26. if (fseek(f, 0, SEEK_END) == -1) {
  27. ret = errno;
  28. goto end;
  29. }
  30. size = ftell(f);
  31. if (size > MAX_TORRENT_SIZE) {
  32. ret = EFBIG;
  33. goto end;
  34. }
  35. rewind(f);
  36. contents = curr_contents = malloc(size);
  37. if (!contents) {
  38. ret = ENOMEM;
  39. goto end;
  40. }
  41. /* Read it in */
  42. while ((read = fread(curr_contents, 1, \
  43. size - (curr_contents - contents), f)) > 0) {
  44. curr_contents += read;
  45. }
  46. if (ferror(f)) {
  47. ret = errno;
  48. free(curr_contents);
  49. curr_contents = NULL;
  50. goto end;
  51. }
  52. end:
  53. if (f)
  54. fclose(f);
  55. *out_size = size;
  56. *out_contents = contents;
  57. return ret;
  58. }
  59. /*
  60. * Read/download the file in memory, and return the pointer to it (which needs to be
  61. * freed) in out_contents and the size in out_size. If the file is too big,
  62. * fail. Returns 0 on success and an errno on fail.
  63. */
  64. static int metainfo_read(const char* path, char** out_contents, int* out_size) {
  65. if (strncmp(path, "http", 4) == 0) {
  66. #ifndef HTTP_TORRENT
  67. return ENOPROTOOPT;
  68. #else
  69. return metainfo_read_http(path, out_contents, out_size);
  70. #endif
  71. }
  72. return metainfo_read_file(path, out_contents, out_size);
  73. }
  74. static int len_strcmp(const char* s1, int s1_len, const char* s2, int s2_len) {
  75. return (s1_len == s2_len) && (strncmp(s1, s2, s1_len) == 0);
  76. }
  77. static int read_benc_int_into(bencode_t* benc, long int* val, int def) {
  78. if (!bencode_int_value(benc, val)) {
  79. *val = def;
  80. return -1;
  81. }
  82. return 0;
  83. }
  84. #define tkey(s) len_strcmp(key, klen, s, strlen(s))
  85. #define ttype(t) bencode_is_##t(&item)
  86. static int metainfo_hash_info(metainfo_t* metai, bencode_t* info) {
  87. const char* info_start;
  88. int info_len;
  89. /* Almost as if this function was made for this, lol */
  90. bencode_dict_get_start_and_len(info, &info_start, &info_len);
  91. SHA1_CTX ctx;
  92. SHA1Init(&ctx);
  93. SHA1Update(&ctx, (const unsigned char*)info_start, info_len);
  94. SHA1Final((unsigned char*)&metai->info_hash, &ctx);
  95. return 0;
  96. }
  97. static int metainfo_parse_info(metainfo_t* metai, bencode_t* benc) {
  98. metainfo_hash_info(metai, benc);
  99. while (bencode_dict_has_next(benc)) {
  100. const char* key;
  101. int klen;
  102. bencode_t item;
  103. bencode_dict_get_next(benc, &item, &key, &klen);
  104. if (tkey("name") && ttype(string)) {
  105. metai->name = item;
  106. } else if (tkey("piece length") && ttype(int)) {
  107. read_benc_int_into(&item, &metai->piece_length, -1);
  108. } else if (tkey("pieces") && ttype(string)) {
  109. int plen = -1;
  110. bencode_string_value(&item, (const char**)&metai->pieces, &plen);
  111. /* A piece hash is always 20 bytes */
  112. if (plen % sizeof(sha1sum_t) != 0) {
  113. fprintf(stderr, "A piece hash is not 20 bytes somewhere\n" \
  114. "\tHash string length is: %d\n", plen);
  115. /* This should never happen tho */
  116. plen -= plen % sizeof(sha1sum_t);
  117. }
  118. metai->piece_count = plen / sizeof(sha1sum_t);
  119. } else if (tkey("length") && ttype(int)) { /* If single file */
  120. metai->is_multi_file = 0;
  121. read_benc_int_into(&item, &metai->file_size, -1);
  122. } else if (tkey("files") && ttype(list)) { /* If multiple files */
  123. metai->is_multi_file = 1;
  124. metai->files = item;
  125. } else if (tkey("private") && ttype(int)) {
  126. read_benc_int_into(&item, &metai->is_private, 0);
  127. } else if (tkey("source") && ttype(string)) {
  128. metai->source = item;
  129. } else {
  130. fprintf(stderr, "Unknown key in info dict: %.*s\n", klen, key);
  131. }
  132. }
  133. return 0;
  134. }
  135. static int metainfo_parse(metainfo_t* metai, bencode_t* benc) {
  136. int ret = 0;
  137. /* All .torrent files are dictionaries, so this is an error */
  138. if (!bencode_is_dict(benc)) {
  139. metainfo_destroy(metai);
  140. fprintf(stderr, "File is not a valid .torrent file\n");
  141. return -1;
  142. }
  143. while (bencode_dict_has_next(benc)) {
  144. const char* key;
  145. int klen;
  146. bencode_t item;
  147. bencode_dict_get_next(benc, &item, &key, &klen);
  148. if (tkey("announce")) {
  149. metai->announce = item;
  150. } else if (tkey("created by") && ttype(string)) {
  151. metai->created_by = item;
  152. } else if (tkey("creation date") && ttype(int)) {
  153. read_benc_int_into(&item, &metai->creation_date, -1);
  154. } else if (tkey("info") && ttype(dict)) {
  155. metainfo_parse_info(metai, &item);
  156. } else if (tkey("comment") && ttype(string)) {
  157. metai->comment = item;
  158. } else {
  159. fprintf(stderr, "Unknown dict key: %.*s\n", klen, key);
  160. }
  161. }
  162. return ret;
  163. }
  164. int metainfo_create(metainfo_t* metai, const char* path) {
  165. char* bytes = NULL;
  166. int size = 0;
  167. int ret = metainfo_read(path, &bytes, &size);
  168. if (ret) {
  169. fprintf(stderr, "Metafile reading failed: %s\n", \
  170. strerror(ret));
  171. return -1;
  172. }
  173. memset(metai, 0, sizeof(metainfo_t));
  174. metai->bytes = bytes;
  175. metai->bytes_size = size;
  176. bencode_t benc;
  177. bencode_init(&benc, bytes, size);
  178. if (metainfo_parse(metai, &benc) == -1) {
  179. metainfo_destroy(metai);
  180. fprintf(stderr, "Can't parse metainfo file\n");
  181. return -1;
  182. }
  183. return 0;
  184. }
  185. void metainfo_destroy(metainfo_t* metai) {
  186. if (metai->bytes) {
  187. free(metai->bytes);
  188. metai->bytes = NULL;
  189. }
  190. }
  191. const sha1sum_t* metainfo_infohash(metainfo_t* metai) {
  192. return &metai->info_hash;
  193. }
  194. static int metainfo_get_string(bencode_t* benc, const char** str, int* len) {
  195. if (!benc->start)
  196. return -1;
  197. return bencode_string_value(benc, str, len) - 1;
  198. }
  199. int metainfo_announce(metainfo_t* metai, const char** str, int* len) {
  200. return metainfo_get_string(&metai->announce, str, len);
  201. }
  202. int metainfo_created_by(metainfo_t* metai, const char** str, int* len) {
  203. return metainfo_get_string(&metai->created_by, str, len);
  204. }
  205. int metainfo_creation_date(metainfo_t* metai) {
  206. return metai->creation_date;
  207. }
  208. int metainfo_source(metainfo_t* metai, const char** str, int* len) {
  209. return metainfo_get_string(&metai->source, str, len);
  210. }
  211. int metainfo_is_private(metainfo_t* metai) {
  212. return metai->is_private;
  213. }
  214. int metainfo_name(metainfo_t* metai, const char** str, int* len) {
  215. return metainfo_get_string(&metai->name, str, len);
  216. }
  217. int metainfo_comment(metainfo_t* metai, const char** str, int* len) {
  218. return metainfo_get_string(&metai->comment, str, len);
  219. }
  220. int metainfo_pieces(metainfo_t* metai, const sha1sum_t** piece_hash) {
  221. if (!metai->pieces)
  222. return -1;
  223. *piece_hash = metai->pieces;
  224. return 0;
  225. }
  226. int metainfo_piece_index(metainfo_t* metai, int index, \
  227. const sha1sum_t** piece_hash) {
  228. if (!metai->pieces || index >= metai->piece_count)
  229. return -1;
  230. *piece_hash = metai->pieces + index;
  231. return 0;
  232. }
  233. int metainfo_piece_size(metainfo_t* metai) {
  234. return metai->piece_length;
  235. }
  236. long int metainfo_piece_count(metainfo_t* metai) {
  237. return metai->piece_count;
  238. }
  239. int metainfo_is_multi_file(metainfo_t* metai) {
  240. return metai->is_multi_file;
  241. }
  242. long int metainfo_file_count(metainfo_t* metai) {
  243. if (!(metai->is_multi_file && bencode_is_list(&metai->files)))
  244. return 0;
  245. long int count = 0;
  246. bencode_t iterb = metai->files;
  247. while (bencode_list_get_next(&iterb, NULL) != 0)
  248. count++;
  249. return count;
  250. }
  251. static int metainfo_file_dict2fileinfo(bencode_t* f_dict, fileinfo_t* finfo) {
  252. int has_path = 0, has_size = 0;
  253. while (bencode_dict_has_next(f_dict) && (!has_path || !has_size)) {
  254. const char* key;
  255. int klen;
  256. bencode_t item;
  257. bencode_dict_get_next(f_dict, &item, &key, &klen);
  258. if (tkey("length") && ttype(int)) {
  259. has_size = 1;
  260. bencode_int_value(&item, &finfo->size);
  261. } else if (tkey("path") && ttype(list)) {
  262. has_path = 1;
  263. finfo->path = item;
  264. } else {
  265. fprintf(stderr, "Unknown key in files dict: %*.s\n", klen, key);
  266. }
  267. }
  268. return (has_path && has_size) ? 0 : -1;
  269. }
  270. int metainfo_file_index(metainfo_t* metai, int index, fileinfo_t* finfo) {
  271. if (!(metai->is_multi_file && bencode_is_list(&metai->files)))
  272. return -1;
  273. bencode_t iterb = metai->files;
  274. while (index-- && bencode_list_get_next(&iterb, NULL) != 0);
  275. if (!bencode_is_dict(&iterb))
  276. return -1;
  277. return metainfo_file_dict2fileinfo(&iterb, finfo);
  278. }
  279. int metainfo_fileiter_create(const metainfo_t* metai, fileiter_t* fileiter) {
  280. if (!metai->is_multi_file || !bencode_is_list(&metai->files))
  281. return -1;
  282. fileiter->filelist = metai->files;
  283. return 0;
  284. }
  285. int metainfo_file_next(fileiter_t* iter, fileinfo_t* finfo) {
  286. if (!bencode_list_has_next(&iter->filelist))
  287. return -1;
  288. bencode_t f_dict;
  289. bencode_list_get_next(&iter->filelist, &f_dict);
  290. return metainfo_file_dict2fileinfo(&f_dict, finfo);
  291. }
  292. int metainfo_fileinfo(metainfo_t* metai, fileinfo_t* finfo) {
  293. if (metai->is_multi_file)
  294. return -1;
  295. finfo->size = metai->file_size;
  296. /* In the case of single files, the name is the filename */
  297. finfo->path = metai->name;
  298. return 0;
  299. }
  300. #ifdef _WIN32
  301. #define PATH_SEP '\\'
  302. #else
  303. #define PATH_SEP '/'
  304. #endif
  305. int metainfo_fileinfo_path(fileinfo_t* finfo, char* out_str) {
  306. int count = 0;
  307. if (bencode_is_list(&finfo->path)) {
  308. bencode_t local_copy = finfo->path;
  309. bencode_t item;
  310. while (bencode_list_has_next(&local_copy)) {
  311. /* If not in the first iter, append separator */
  312. if (count > 0) {
  313. if (out_str)
  314. *out_str++ = PATH_SEP;
  315. count++;
  316. }
  317. bencode_list_get_next(&local_copy, &item);
  318. int slen;
  319. const char* s;
  320. bencode_string_value(&item, &s, &slen);
  321. count += slen;
  322. if (out_str) {
  323. memcpy(out_str, s, slen);
  324. out_str += slen;
  325. }
  326. }
  327. } else {
  328. /* Single file, we shouldn't even copy here, but it's easier... */
  329. int slen;
  330. const char* s;
  331. bencode_string_value(&finfo->path, &s, &slen);
  332. if (out_str) {
  333. memcpy(out_str, s, slen);
  334. }
  335. count = slen;
  336. }
  337. return count;
  338. }
  339. long int metainfo_fileinfo_size(fileinfo_t* finfo) {
  340. return finfo->size;
  341. }
  342. #undef tkey
  343. #undef ttype