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