1/* Compute MD5, SHA1, SHA224, SHA256, SHA384 or SHA512 checksum of files or strings
2   Copyright (C) 1995-2010 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 <http://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
26#if HASH_ALGO_MD5
27# include "md5.h"
28#endif
29#if HASH_ALGO_SHA1
30# include "sha1.h"
31#endif
32#if HASH_ALGO_SHA256 || HASH_ALGO_SHA224
33# include "sha256.h"
34#endif
35#if HASH_ALGO_SHA512 || HASH_ALGO_SHA384
36# include "sha512.h"
37#endif
38#include "error.h"
39#include "stdio--.h"
40#include "xfreopen.h"
41
42/* The official name of this program (e.g., no `g' prefix).  */
43#if HASH_ALGO_MD5
44# define PROGRAM_NAME "md5sum"
45# define DIGEST_TYPE_STRING "MD5"
46# define DIGEST_STREAM md5_stream
47# define DIGEST_BITS 128
48# define DIGEST_REFERENCE "RFC 1321"
49# define DIGEST_ALIGN 4
50#elif HASH_ALGO_SHA1
51# define PROGRAM_NAME "sha1sum"
52# define DIGEST_TYPE_STRING "SHA1"
53# define DIGEST_STREAM sha1_stream
54# define DIGEST_BITS 160
55# define DIGEST_REFERENCE "FIPS-180-1"
56# define DIGEST_ALIGN 4
57#elif HASH_ALGO_SHA256
58# define PROGRAM_NAME "sha256sum"
59# define DIGEST_TYPE_STRING "SHA256"
60# define DIGEST_STREAM sha256_stream
61# define DIGEST_BITS 256
62# define DIGEST_REFERENCE "FIPS-180-2"
63# define DIGEST_ALIGN 4
64#elif HASH_ALGO_SHA224
65# define PROGRAM_NAME "sha224sum"
66# define DIGEST_TYPE_STRING "SHA224"
67# define DIGEST_STREAM sha224_stream
68# define DIGEST_BITS 224
69# define DIGEST_REFERENCE "RFC 3874"
70# define DIGEST_ALIGN 4
71#elif HASH_ALGO_SHA512
72# define PROGRAM_NAME "sha512sum"
73# define DIGEST_TYPE_STRING "SHA512"
74# define DIGEST_STREAM sha512_stream
75# define DIGEST_BITS 512
76# define DIGEST_REFERENCE "FIPS-180-2"
77# define DIGEST_ALIGN 8
78#elif HASH_ALGO_SHA384
79# define PROGRAM_NAME "sha384sum"
80# define DIGEST_TYPE_STRING "SHA384"
81# define DIGEST_STREAM sha384_stream
82# define DIGEST_BITS 384
83# define DIGEST_REFERENCE "FIPS-180-2"
84# define DIGEST_ALIGN 8
85#else
86# error "Can't decide which hash algorithm to compile."
87#endif
88
89#define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
90#define DIGEST_BIN_BYTES (DIGEST_BITS / 8)
91
92#define AUTHORS \
93  proper_name ("Ulrich Drepper"), \
94  proper_name ("Scott Miller"), \
95  proper_name ("David Madore")
96
97/* The minimum length of a valid digest line.  This length does
98   not include any newline character at the end of a line.  */
99#define MIN_DIGEST_LINE_LENGTH \
100  (DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
101   + 2 /* blank and binary indicator */ \
102   + 1 /* minimum filename length */ )
103
104/* True if any of the files read were the standard input. */
105static bool have_read_stdin;
106
107/* The minimum length of a valid checksum line for the selected algorithm.  */
108static size_t min_digest_line_length;
109
110/* Set to the length of a digest hex string for the selected algorithm.  */
111static size_t digest_hex_bytes;
112
113/* With --check, don't generate any output.
114   The exit code indicates success or failure.  */
115static bool status_only = false;
116
117/* With --check, print a message to standard error warning about each
118   improperly formatted checksum line.  */
119static bool warn = false;
120
121/* With --check, suppress the "OK" printed for each verified file.  */
122static bool quiet = false;
123
124/* For long options that have no equivalent short option, use a
125   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
126enum
127{
128  STATUS_OPTION = CHAR_MAX + 1,
129  QUIET_OPTION
130};
131
132static struct option const long_options[] =
133{
134  { "binary", no_argument, NULL, 'b' },
135  { "check", no_argument, NULL, 'c' },
136  { "quiet", no_argument, NULL, QUIET_OPTION },
137  { "status", no_argument, NULL, STATUS_OPTION },
138  { "text", no_argument, NULL, 't' },
139  { "warn", no_argument, NULL, 'w' },
140  { GETOPT_HELP_OPTION_DECL },
141  { GETOPT_VERSION_OPTION_DECL },
142  { NULL, 0, NULL, 0 }
143};
144
145void
146usage (int status)
147{
148  if (status != EXIT_SUCCESS)
149    fprintf (stderr, _("Try `%s --help' for more information.\n"),
150             program_name);
151  else
152    {
153      printf (_("\
154Usage: %s [OPTION]... [FILE]...\n\
155Print or check %s (%d-bit) checksums.\n\
156With no FILE, or when FILE is -, read standard input.\n\
157\n\
158"),
159              program_name,
160              DIGEST_TYPE_STRING,
161              DIGEST_BITS);
162      if (O_BINARY)
163        fputs (_("\
164  -b, --binary            read in binary mode (default unless reading tty stdin)\n\
165"), stdout);
166      else
167        fputs (_("\
168  -b, --binary            read in binary mode\n\
169"), stdout);
170      printf (_("\
171  -c, --check             read %s sums from the FILEs and check them\n"),
172              DIGEST_TYPE_STRING);
173      if (O_BINARY)
174        fputs (_("\
175  -t, --text              read in text mode (default if reading tty stdin)\n\
176"), stdout);
177      else
178        fputs (_("\
179  -t, --text              read in text mode (default)\n\
180"), stdout);
181      fputs (_("\
182\n\
183The following three options are useful only when verifying checksums:\n\
184      --quiet             don't print OK for each successfully verified file\n\
185      --status            don't output anything, status code shows success\n\
186  -w, --warn              warn about improperly formatted checksum lines\n\
187\n\
188"), stdout);
189      fputs (HELP_OPTION_DESCRIPTION, stdout);
190      fputs (VERSION_OPTION_DESCRIPTION, stdout);
191      printf (_("\
192\n\
193The sums are computed as described in %s.  When checking, the input\n\
194should be a former output of this program.  The default mode is to print\n\
195a line with checksum, a character indicating type (`*' for binary, ` ' for\n\
196text), and name for each FILE.\n"),
197              DIGEST_REFERENCE);
198      emit_ancillary_info ();
199    }
200
201  exit (status);
202}
203
204#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
205
206/* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
207   'sha1' command into two parts: a hexadecimal digest, and the file
208   name.  S is modified.  Return true if successful.  */
209
210static bool
211bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest, char **file_name)
212{
213  size_t i;
214
215  if (s_len == 0)
216    return false;
217
218  *file_name = s;
219
220  /* Find end of filename. The BSD 'md5' and 'sha1' commands do not escape
221     filenames, so search backwards for the last ')'. */
222  i = s_len - 1;
223  while (i && s[i] != ')')
224    i--;
225
226  if (s[i] != ')')
227    return false;
228
229  s[i++] = '\0';
230
231  while (ISWHITE (s[i]))
232    i++;
233
234  if (s[i] != '=')
235    return false;
236
237  i++;
238
239  while (ISWHITE (s[i]))
240    i++;
241
242  *hex_digest = (unsigned char *) &s[i];
243  return true;
244}
245
246/* Split the string S (of length S_LEN) into three parts:
247   a hexadecimal digest, binary flag, and the file name.
248   S is modified.  Return true if successful.  */
249
250static bool
251split_3 (char *s, size_t s_len,
252         unsigned char **hex_digest, int *binary, char **file_name)
253{
254  bool escaped_filename = false;
255  size_t algo_name_len;
256
257  size_t i = 0;
258  while (ISWHITE (s[i]))
259    ++i;
260
261  /* Check for BSD-style checksum line. */
262  algo_name_len = strlen (DIGEST_TYPE_STRING);
263  if (strncmp (s + i, DIGEST_TYPE_STRING, algo_name_len) == 0)
264    {
265      if (s[i + algo_name_len] == ' ')
266        ++i;
267      if (s[i + algo_name_len] == '(')
268        {
269          *binary = 0;
270          return bsd_split_3 (s +      i + algo_name_len + 1,
271                              s_len - (i + algo_name_len + 1),
272                              hex_digest, file_name);
273        }
274    }
275
276  /* Ignore this line if it is too short.
277     Each line must have at least `min_digest_line_length - 1' (or one more, if
278     the first is a backslash) more characters to contain correct message digest
279     information.  */
280  if (s_len - i < min_digest_line_length + (s[i] == '\\'))
281    return false;
282
283  if (s[i] == '\\')
284    {
285      ++i;
286      escaped_filename = true;
287    }
288  *hex_digest = (unsigned char *) &s[i];
289
290  /* The first field has to be the n-character hexadecimal
291     representation of the message digest.  If it is not followed
292     immediately by a white space it's an error.  */
293  i += digest_hex_bytes;
294  if (!ISWHITE (s[i]))
295    return false;
296
297  s[i++] = '\0';
298
299  if (s[i] != ' ' && s[i] != '*')
300    return false;
301  *binary = (s[i++] == '*');
302
303  /* All characters between the type indicator and end of line are
304     significant -- that includes leading and trailing white space.  */
305  *file_name = &s[i];
306
307  if (escaped_filename)
308    {
309      /* Translate each `\n' string in the file name to a NEWLINE,
310         and each `\\' string to a backslash.  */
311
312      char *dst = &s[i];
313
314      while (i < s_len)
315        {
316          switch (s[i])
317            {
318            case '\\':
319              if (i == s_len - 1)
320                {
321                  /* A valid line does not end with a backslash.  */
322                  return false;
323                }
324              ++i;
325              switch (s[i++])
326                {
327                case 'n':
328                  *dst++ = '\n';
329                  break;
330                case '\\':
331                  *dst++ = '\\';
332                  break;
333                default:
334                  /* Only `\' or `n' may follow a backslash.  */
335                  return false;
336                }
337              break;
338
339            case '\0':
340              /* The file name may not contain a NUL.  */
341              return false;
342              break;
343
344            default:
345              *dst++ = s[i++];
346              break;
347            }
348        }
349      *dst = '\0';
350    }
351  return true;
352}
353
354/* Return true if S is a NUL-terminated string of DIGEST_HEX_BYTES hex digits.
355   Otherwise, return false.  */
356static bool
357hex_digits (unsigned char const *s)
358{
359  unsigned int i;
360  for (i = 0; i < digest_hex_bytes; i++)
361    {
362      if (!isxdigit (*s))
363        return false;
364      ++s;
365    }
366  return *s == '\0';
367}
368
369/* An interface to the function, DIGEST_STREAM.
370   Operate on FILENAME (it may be "-").
371
372   *BINARY indicates whether the file is binary.  BINARY < 0 means it
373   depends on whether binary mode makes any difference and the file is
374   a terminal; in that case, clear *BINARY if the file was treated as
375   text because it was a terminal.
376
377   Put the checksum in *BIN_RESULT, which must be properly aligned.
378   Return true if successful.  */
379
380static bool
381digest_file (const char *filename, int *binary, unsigned char *bin_result)
382{
383  FILE *fp;
384  int err;
385  bool is_stdin = STREQ (filename, "-");
386
387  if (is_stdin)
388    {
389      have_read_stdin = true;
390      fp = stdin;
391      if (O_BINARY && *binary)
392        {
393          if (*binary < 0)
394            *binary = ! isatty (STDIN_FILENO);
395          if (*binary)
396            xfreopen (NULL, "rb", stdin);
397        }
398    }
399  else
400    {
401      fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r"));
402      if (fp == NULL)
403        {
404          error (0, errno, "%s", filename);
405          return false;
406        }
407    }
408
409  err = DIGEST_STREAM (fp, bin_result);
410  if (err)
411    {
412      error (0, errno, "%s", filename);
413      if (fp != stdin)
414        fclose (fp);
415      return false;
416    }
417
418  if (!is_stdin && fclose (fp) != 0)
419    {
420      error (0, errno, "%s", filename);
421      return false;
422    }
423
424  return true;
425}
426
427static bool
428digest_check (const char *checkfile_name)
429{
430  FILE *checkfile_stream;
431  uintmax_t n_properly_formatted_lines = 0;
432  uintmax_t n_mismatched_checksums = 0;
433  uintmax_t n_open_or_read_failures = 0;
434  unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
435  /* Make sure bin_buffer is properly aligned. */
436  unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
437  uintmax_t line_number;
438  char *line;
439  size_t line_chars_allocated;
440  bool is_stdin = STREQ (checkfile_name, "-");
441
442  if (is_stdin)
443    {
444      have_read_stdin = true;
445      checkfile_name = _("standard input");
446      checkfile_stream = stdin;
447    }
448  else
449    {
450      checkfile_stream = fopen (checkfile_name, "r");
451      if (checkfile_stream == NULL)
452        {
453          error (0, errno, "%s", checkfile_name);
454          return false;
455        }
456    }
457
458  line_number = 0;
459  line = NULL;
460  line_chars_allocated = 0;
461  do
462    {
463      char *filename IF_LINT (= NULL);
464      int binary;
465      unsigned char *hex_digest IF_LINT (= NULL);
466      ssize_t line_length;
467
468      ++line_number;
469      if (line_number == 0)
470        error (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
471               checkfile_name);
472
473      line_length = getline (&line, &line_chars_allocated, checkfile_stream);
474      if (line_length <= 0)
475        break;
476
477      /* Ignore comment lines, which begin with a '#' character.  */
478      if (line[0] == '#')
479        continue;
480
481      /* Remove any trailing newline.  */
482      if (line[line_length - 1] == '\n')
483        line[--line_length] = '\0';
484
485      if (! (split_3 (line, line_length, &hex_digest, &binary, &filename)
486             && ! (is_stdin && STREQ (filename, "-"))
487             && hex_digits (hex_digest)))
488        {
489          if (warn)
490            {
491              error (0, 0,
492                     _("%s: %" PRIuMAX
493                       ": improperly formatted %s checksum line"),
494                     checkfile_name, line_number,
495                     DIGEST_TYPE_STRING);
496            }
497        }
498      else
499        {
500          static const char bin2hex[] = { '0', '1', '2', '3',
501                                          '4', '5', '6', '7',
502                                          '8', '9', 'a', 'b',
503                                          'c', 'd', 'e', 'f' };
504          bool ok;
505
506          ++n_properly_formatted_lines;
507
508          ok = digest_file (filename, &binary, bin_buffer);
509
510          if (!ok)
511            {
512              ++n_open_or_read_failures;
513              if (!status_only)
514                {
515                  printf (_("%s: FAILED open or read\n"), filename);
516                }
517            }
518          else
519            {
520              size_t digest_bin_bytes = digest_hex_bytes / 2;
521              size_t cnt;
522              /* Compare generated binary number with text representation
523                 in check file.  Ignore case of hex digits.  */
524              for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
525                {
526                  if (tolower (hex_digest[2 * cnt])
527                      != bin2hex[bin_buffer[cnt] >> 4]
528                      || (tolower (hex_digest[2 * cnt + 1])
529                          != (bin2hex[bin_buffer[cnt] & 0xf])))
530                    break;
531                }
532              if (cnt != digest_bin_bytes)
533                ++n_mismatched_checksums;
534
535              if (!status_only)
536                {
537                  if (cnt != digest_bin_bytes)
538                    printf ("%s: %s\n", filename, _("FAILED"));
539                  else if (!quiet)
540                    printf ("%s: %s\n", filename, _("OK"));
541                }
542            }
543        }
544    }
545  while (!feof (checkfile_stream) && !ferror (checkfile_stream));
546
547  free (line);
548
549  if (ferror (checkfile_stream))
550    {
551      error (0, 0, _("%s: read error"), checkfile_name);
552      return false;
553    }
554
555  if (!is_stdin && fclose (checkfile_stream) != 0)
556    {
557      error (0, errno, "%s", checkfile_name);
558      return false;
559    }
560
561  if (n_properly_formatted_lines == 0)
562    {
563      /* Warn if no tests are found.  */
564      error (0, 0, _("%s: no properly formatted %s checksum lines found"),
565             checkfile_name, DIGEST_TYPE_STRING);
566    }
567  else
568    {
569      if (!status_only)
570        {
571          if (n_open_or_read_failures != 0)
572            error (0, 0,
573                   ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
574                             " listed file could not be read",
575                             "WARNING: %" PRIuMAX " of %" PRIuMAX
576                             " listed files could not be read",
577                             select_plural (n_properly_formatted_lines)),
578                   n_open_or_read_failures, n_properly_formatted_lines);
579
580          if (n_mismatched_checksums != 0)
581            {
582              uintmax_t n_computed_checksums =
583                (n_properly_formatted_lines - n_open_or_read_failures);
584              error (0, 0,
585                     ngettext ("WARNING: %" PRIuMAX " of %" PRIuMAX
586                               " computed checksum did NOT match",
587                               "WARNING: %" PRIuMAX " of %" PRIuMAX
588                               " computed checksums did NOT match",
589                               select_plural (n_computed_checksums)),
590                     n_mismatched_checksums, n_computed_checksums);
591            }
592        }
593    }
594
595  return (n_properly_formatted_lines != 0
596          && n_mismatched_checksums == 0
597          && n_open_or_read_failures == 0);
598}
599
600int
601main (int argc, char **argv)
602{
603  unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
604  /* Make sure bin_buffer is properly aligned. */
605  unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
606  bool do_check = false;
607  int opt;
608  bool ok = true;
609  int binary = -1;
610
611  /* Setting values of global variables.  */
612  initialize_main (&argc, &argv);
613  set_program_name (argv[0]);
614  setlocale (LC_ALL, "");
615  bindtextdomain (PACKAGE, LOCALEDIR);
616  textdomain (PACKAGE);
617
618  atexit (close_stdout);
619
620  /* Line buffer stdout to ensure lines are written atomically and immediately
621     so that processes running in parallel do not intersperse their output.  */
622  setvbuf (stdout, NULL, _IOLBF, 0);
623
624  while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
625    switch (opt)
626      {
627      case 'b':
628        binary = 1;
629        break;
630      case 'c':
631        do_check = true;
632        break;
633      case STATUS_OPTION:
634        status_only = true;
635        warn = false;
636        quiet = false;
637        break;
638      case 't':
639        binary = 0;
640        break;
641      case 'w':
642        status_only = false;
643        warn = true;
644        quiet = false;
645        break;
646      case QUIET_OPTION:
647        status_only = false;
648        warn = false;
649        quiet = true;
650        break;
651      case_GETOPT_HELP_CHAR;
652      case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
653      default:
654        usage (EXIT_FAILURE);
655      }
656
657  min_digest_line_length = MIN_DIGEST_LINE_LENGTH;
658  digest_hex_bytes = DIGEST_HEX_BYTES;
659
660  if (0 <= binary && do_check)
661    {
662      error (0, 0, _("the --binary and --text options are meaningless when "
663                     "verifying checksums"));
664      usage (EXIT_FAILURE);
665    }
666
667  if (status_only && !do_check)
668    {
669      error (0, 0,
670       _("the --status option is meaningful only when verifying checksums"));
671      usage (EXIT_FAILURE);
672    }
673
674  if (warn && !do_check)
675    {
676      error (0, 0,
677       _("the --warn option is meaningful only when verifying checksums"));
678      usage (EXIT_FAILURE);
679    }
680
681  if (quiet && !do_check)
682    {
683      error (0, 0,
684       _("the --quiet option is meaningful only when verifying checksums"));
685      usage (EXIT_FAILURE);
686    }
687
688  if (!O_BINARY && binary < 0)
689    binary = 0;
690
691  if (optind == argc)
692    argv[argc++] = bad_cast ("-");
693
694  for (; optind < argc; ++optind)
695    {
696      char *file = argv[optind];
697
698      if (do_check)
699        ok &= digest_check (file);
700      else
701        {
702          int file_is_binary = binary;
703
704          if (! digest_file (file, &file_is_binary, bin_buffer))
705            ok = false;
706          else
707            {
708              size_t i;
709
710              /* Output a leading backslash if the file name contains
711                 a newline or backslash.  */
712              if (strchr (file, '\n') || strchr (file, '\\'))
713                putchar ('\\');
714
715              for (i = 0; i < (digest_hex_bytes / 2); ++i)
716                printf ("%02x", bin_buffer[i]);
717
718              putchar (' ');
719              if (file_is_binary)
720                putchar ('*');
721              else
722                putchar (' ');
723
724              /* Translate each NEWLINE byte to the string, "\\n",
725                 and each backslash to "\\\\".  */
726              for (i = 0; i < strlen (file); ++i)
727                {
728                  switch (file[i])
729                    {
730                    case '\n':
731                      fputs ("\\n", stdout);
732                      break;
733
734                    case '\\':
735                      fputs ("\\\\", stdout);
736                      break;
737
738                    default:
739                      putchar (file[i]);
740                      break;
741                    }
742                }
743              putchar ('\n');
744            }
745        }
746    }
747
748  if (have_read_stdin && fclose (stdin) == EOF)
749    error (EXIT_FAILURE, errno, _("standard input"));
750
751  exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
752}
753