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.

394 lines
11KB

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