Verify bittorrent .torrent metainfo files.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

394 lignes
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