hashsum.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2009 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/dl.h>
  19. #include <grub/extcmd.h>
  20. #include <grub/file.h>
  21. #include <grub/disk.h>
  22. #include <grub/mm.h>
  23. #include <grub/misc.h>
  24. #include <grub/crypto.h>
  25. #include <grub/normal.h>
  26. #include <grub/i18n.h>
  27. GRUB_MOD_LICENSE ("GPLv3+");
  28. static const struct grub_arg_option options[] = {
  29. {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING},
  30. {"check", 'c', 0, N_("Check hash list file."), N_("FILE"), ARG_TYPE_STRING},
  31. {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIRECTORY"),
  32. ARG_TYPE_STRING},
  33. {"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0},
  34. {"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 0, 0},
  35. {0, 0, 0, 0, 0, 0}
  36. };
  37. static struct { const char *name; const char *hashname; } aliases[] =
  38. {
  39. {"sha256sum", "sha256"},
  40. {"sha512sum", "sha512"},
  41. {"sha1sum", "sha1"},
  42. {"md5sum", "md5"},
  43. {"crc", "crc32"},
  44. };
  45. static inline int
  46. hextoval (char c)
  47. {
  48. if (c >= '0' && c <= '9')
  49. return c - '0';
  50. if (c >= 'a' && c <= 'f')
  51. return c - 'a' + 10;
  52. if (c >= 'A' && c <= 'F')
  53. return c - 'A' + 10;
  54. return -1;
  55. }
  56. static grub_err_t
  57. hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result)
  58. {
  59. grub_uint8_t context[hash->contextsize];
  60. grub_uint8_t readbuf[4096];
  61. grub_memset (context, 0, sizeof (context));
  62. hash->init (context);
  63. while (1)
  64. {
  65. grub_ssize_t r;
  66. r = grub_file_read (file, readbuf, sizeof (readbuf));
  67. if (r < 0)
  68. return grub_errno;
  69. if (r == 0)
  70. break;
  71. hash->write (context, readbuf, r);
  72. }
  73. hash->final (context);
  74. grub_memcpy (result, hash->read (context), hash->mdlen);
  75. return GRUB_ERR_NONE;
  76. }
  77. static grub_err_t
  78. check_list (const gcry_md_spec_t *hash, const char *hashfilename,
  79. const char *prefix, int keep, int uncompress)
  80. {
  81. grub_file_t hashlist, file;
  82. char *buf = NULL;
  83. grub_uint8_t expected[hash->mdlen];
  84. grub_uint8_t actual[hash->mdlen];
  85. grub_err_t err;
  86. unsigned i;
  87. unsigned unread = 0, mismatch = 0;
  88. hashlist = grub_file_open (hashfilename);
  89. if (!hashlist)
  90. return grub_errno;
  91. while (grub_free (buf), (buf = grub_file_getline (hashlist)))
  92. {
  93. const char *p = buf;
  94. for (i = 0; i < hash->mdlen; i++)
  95. {
  96. int high, low;
  97. high = hextoval (*p++);
  98. low = hextoval (*p++);
  99. if (high < 0 || low < 0)
  100. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
  101. expected[i] = (high << 4) | low;
  102. }
  103. if (*p++ != ' ' || *p++ != ' ')
  104. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
  105. if (prefix)
  106. {
  107. char *filename;
  108. filename = grub_xasprintf ("%s/%s", prefix, p);
  109. if (!filename)
  110. return grub_errno;
  111. if (!uncompress)
  112. grub_file_filter_disable_compression ();
  113. file = grub_file_open (filename);
  114. grub_free (filename);
  115. }
  116. else
  117. {
  118. if (!uncompress)
  119. grub_file_filter_disable_compression ();
  120. file = grub_file_open (p);
  121. }
  122. if (!file)
  123. {
  124. grub_file_close (hashlist);
  125. grub_free (buf);
  126. return grub_errno;
  127. }
  128. err = hash_file (file, hash, actual);
  129. grub_file_close (file);
  130. if (err)
  131. {
  132. grub_printf ("%s: READ ERROR\n", p);
  133. if (!keep)
  134. {
  135. grub_file_close (hashlist);
  136. grub_free (buf);
  137. return err;
  138. }
  139. grub_print_error ();
  140. grub_errno = GRUB_ERR_NONE;
  141. unread++;
  142. continue;
  143. }
  144. if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0)
  145. {
  146. grub_printf ("%s: HASH MISMATCH\n", p);
  147. if (!keep)
  148. {
  149. grub_file_close (hashlist);
  150. grub_free (buf);
  151. return grub_error (GRUB_ERR_TEST_FAILURE,
  152. "hash of '%s' mismatches", p);
  153. }
  154. mismatch++;
  155. continue;
  156. }
  157. grub_printf ("%s: OK\n", p);
  158. }
  159. if (mismatch || unread)
  160. return grub_error (GRUB_ERR_TEST_FAILURE,
  161. "%d files couldn't be read and hash "
  162. "of %d files mismatches", unread, mismatch);
  163. return GRUB_ERR_NONE;
  164. }
  165. static grub_err_t
  166. grub_cmd_hashsum (struct grub_extcmd_context *ctxt,
  167. int argc, char **args)
  168. {
  169. struct grub_arg_list *state = ctxt->state;
  170. const char *hashname = NULL;
  171. const char *prefix = NULL;
  172. const gcry_md_spec_t *hash;
  173. unsigned i;
  174. int keep = state[3].set;
  175. int uncompress = state[4].set;
  176. unsigned unread = 0;
  177. for (i = 0; i < ARRAY_SIZE (aliases); i++)
  178. if (grub_strcmp (ctxt->extcmd->cmd->name, aliases[i].name) == 0)
  179. hashname = aliases[i].hashname;
  180. if (state[0].set)
  181. hashname = state[0].arg;
  182. if (!hashname)
  183. return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified");
  184. hash = grub_crypto_lookup_md_by_name (hashname);
  185. if (!hash)
  186. return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash");
  187. if (state[2].set)
  188. prefix = state[2].arg;
  189. if (state[1].set)
  190. {
  191. if (argc != 0)
  192. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  193. "--check is incompatible with file list");
  194. return check_list (hash, state[1].arg, prefix, keep, uncompress);
  195. }
  196. for (i = 0; i < (unsigned) argc; i++)
  197. {
  198. grub_uint8_t result[hash->mdlen];
  199. grub_file_t file;
  200. grub_err_t err;
  201. unsigned j;
  202. if (!uncompress)
  203. grub_file_filter_disable_compression ();
  204. file = grub_file_open (args[i]);
  205. if (!file)
  206. {
  207. if (!keep)
  208. return grub_errno;
  209. grub_print_error ();
  210. grub_errno = GRUB_ERR_NONE;
  211. unread++;
  212. continue;
  213. }
  214. err = hash_file (file, hash, result);
  215. grub_file_close (file);
  216. if (err)
  217. {
  218. if (!keep)
  219. return err;
  220. grub_print_error ();
  221. grub_errno = GRUB_ERR_NONE;
  222. unread++;
  223. continue;
  224. }
  225. for (j = 0; j < hash->mdlen; j++)
  226. grub_printf ("%02x", result[j]);
  227. grub_printf (" %s\n", args[i]);
  228. }
  229. if (unread)
  230. return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read.",
  231. unread);
  232. return GRUB_ERR_NONE;
  233. }
  234. static grub_extcmd_t cmd, cmd_md5, cmd_sha1, cmd_sha256, cmd_sha512, cmd_crc;
  235. GRUB_MOD_INIT(hashsum)
  236. {
  237. cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, 0,
  238. "hashsum -h HASH [-c FILE [-p PREFIX]] "
  239. "[FILE1 [FILE2 ...]]",
  240. N_("Compute or check hash checksum."),
  241. options);
  242. cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, 0,
  243. N_("[-c FILE [-p PREFIX]] "
  244. "[FILE1 [FILE2 ...]]"),
  245. N_("Compute or check hash checksum."),
  246. options);
  247. cmd_sha1 = grub_register_extcmd ("sha1sum", grub_cmd_hashsum, 0,
  248. N_("[-c FILE [-p PREFIX]] "
  249. "[FILE1 [FILE2 ...]]"),
  250. N_("Compute or check hash checksum."),
  251. options);
  252. cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, 0,
  253. N_("[-c FILE [-p PREFIX]] "
  254. "[FILE1 [FILE2 ...]]"),
  255. N_("Compute or check hash checksum."),
  256. options);
  257. cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, 0,
  258. N_("[-c FILE [-p PREFIX]] "
  259. "[FILE1 [FILE2 ...]]"),
  260. N_("Compute or check hash checksum."),
  261. options);
  262. cmd_crc = grub_register_extcmd ("crc", grub_cmd_hashsum, 0,
  263. N_("[-c FILE [-p PREFIX]] "
  264. "[FILE1 [FILE2 ...]]"),
  265. N_("Compute or check hash checksum."),
  266. options);
  267. }
  268. GRUB_MOD_FINI(hashsum)
  269. {
  270. grub_unregister_extcmd (cmd);
  271. grub_unregister_extcmd (cmd_md5);
  272. grub_unregister_extcmd (cmd_sha1);
  273. grub_unregister_extcmd (cmd_sha256);
  274. grub_unregister_extcmd (cmd_sha512);
  275. grub_unregister_extcmd (cmd_crc);
  276. }