md5sum: handle BSD reversed format checksums
authorPádraig Brady <P@draigBrady.com>
Fri, 16 Sep 2011 10:47:35 +0000 (11:47 +0100)
committerPádraig Brady <P@draigBrady.com>
Fri, 16 Sep 2011 18:09:26 +0000 (19:09 +0100)
* src/md5sum.c (split_3): Detect and handle BSD reversed
format checksums.
* tests/misc/md5sum-bsd: Add a new test.
* tests/Makefile.am: Reference new test.
* NEWS: Mention the improvement
Suggested by Rimas Kudelis.

NEWS
src/md5sum.c
tests/Makefile.am
tests/misc/md5sum-bsd [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 879828e..8c218b7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,11 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Improvements
+
+  md5sum --check now supports the -r format from the corresponding BSD tool.
+  This also affects sha1sum, sha224sum, sha384sum and sha512sum.
+
 
 * Noteworthy changes in release 8.13 (2011-09-08) [stable]
 
index ff9538a..9de34a5 100644 (file)
@@ -99,7 +99,7 @@
    not include any newline character at the end of a line.  */
 #define MIN_DIGEST_LINE_LENGTH \
   (DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
-   + 2 /* blank and binary indicator */ \
+   + 1 /* blank */ \
    + 1 /* minimum filename length */ )
 
 /* True if any of the files read were the standard input. */
@@ -126,6 +126,9 @@ static bool quiet = false;
    improperly formatted. */
 static bool strict = false;
 
+/* Whether a BSD reversed format checksum is detected.  */
+static int bsd_reversed = -1;
+
 /* For long options that have no equivalent short option, use a
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
@@ -307,9 +310,24 @@ split_3 (char *s, size_t s_len,
 
   s[i++] = '\0';
 
-  if (s[i] != ' ' && s[i] != '*')
-    return false;
-  *binary = (s[i++] == '*');
+  /* If "bsd reversed" format detected.  */
+  if ((s_len - i == 1) || (s[i] != ' ' && s[i] != '*'))
+    {
+      /* Don't allow mixing bsd and standard formats,
+         to minimize security issues with attackers
+         renaming files with leading spaces.
+         This assumes that with bsd format checksums
+         that the first file name does not have
+         a leading ' ' or '*'.  */
+      if (bsd_reversed == 0)
+        return false;
+      bsd_reversed = 1;
+    }
+  else if (bsd_reversed != 1)
+    {
+      bsd_reversed = 0;
+      *binary = (s[i++] == '*');
+    }
 
   /* All characters between the type indicator and end of line are
      significant -- that includes leading and trailing white space.  */
index b920aba..eeb4cab 100644 (file)
@@ -198,6 +198,7 @@ TESTS =                                             \
   misc/id-context                              \
   misc/id-groups                               \
   misc/md5sum                                  \
+  misc/md5sum-bsd                              \
   misc/md5sum-newline                          \
   misc/md5sum-parallel                         \
   misc/mknod                                   \
diff --git a/tests/misc/md5sum-bsd b/tests/misc/md5sum-bsd
new file mode 100755 (executable)
index 0000000..324530c
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+# make sure `md5sum -c' works for alternate BSD format (md5 -r)
+
+# Copyright (C) 2011 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+print_ver_ md5sum
+
+# Note we start this list with a name
+# that's unambiguous in BSD format.
+# I.E. one not starting with ' ' or '*'
+for i in 'a' ' b' '*c' 'dd' ' '; do
+  echo "$i" > "$i"
+  md5sum "$i" >> check.md5sum
+done
+sed 's/  / /' check.md5sum > check.md5
+
+# Note only a single format is supported per run
+md5sum --strict -c check.md5sum || fail=1
+md5sum --strict -c check.md5 || fail=1
+
+# If we skip the first entry in the BSD format checksums
+# then it'll be detected as standard format and error.
+# This unlikely caveat was thought better than mandating
+# an option to avoid the ambiguity.
+tail -n+2 check.md5 | md5sum --strict -c && fail=1
+
+Exit $fail