[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: md5 package summaries on ftp server (was Re: System integrity)



On Wed, Jun 23, 1999 at 12:40:45PM -0600, Jason Gunthorpe wrote:
> 
> Go read some of the crypto sites, if you can vary the size of the thing
> you are computing a digest for and the digest does not include the size as
> part of it's input then it is lots easier to attack MD5. You really should
> include the size, ownership and permissions of each file+dir, then you can
> make sure someone hasn't gone around and made something setuid that
> shouldn't be or somesuch.
> 

Fair enough.  Perhaps we should modify out .md5sums file to have the
following format...

MD5 file_mode file_uid file_gid file_size filename

ie:

mort:~$ md5sum -l /bin/bash
d92ec046e0b08d83858ede621a65890f  33261 0 0 364336 /bin/bash
mort:~$


I have modified the source of md5sum to include the -l option for checking
and generating md5sums.  Attached is the patch to md5sum.c for this.  No
promises that it's bug free, I just hacked it together this morning...

Best regards,

Chris



-- 
----------------------------------------------------------------------
       As a computer, I find your faith in technology amusing.
----------------------------------------------------------------------
Reply with subject 'request key' for PGP public key.  KeyID 0xA9E087D5
--- md5sum.c.old	Mon Nov  2 03:06:49 1998
+++ md5sum.c	Thu Jun 24 14:36:57 1999
@@ -16,6 +16,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <getopt.h>
+#include <sys/stat.h>
 #include "config.h"
 #include "md5.h"
 
@@ -61,10 +62,13 @@
 int do_check(FILE *chkf);
 int hex_digit(int c);
 int get_md5_line(FILE *fp, unsigned char *digest, char *file);
+int get_long_md5_line(FILE *, unsigned char *, char *, int *, int *, int *, int *);
+int print_longfile(char *filename);
 
 char *progname;
 int verbose = 0;
 int bin_mode = 0;
+int long_mode = 0;
 
 void
 main(int argc, char **argv)
@@ -79,9 +83,10 @@
 	textdomain(PACKAGE);
 
 	progname = *argv;
-	while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) {
+	while ((opt = getopt(argc, argv, "cblvp:h")) != EOF) {
 		switch (opt) {
 			case 'c': check = 1; break;
+			case 'l': long_mode = 1; break;
 			case 'v': verbose = 1; break;
 			case 'b': bin_mode = 1; break;
 			default: usage();
@@ -125,7 +130,12 @@
 			rc = 2;
 		} else {
 			print_digest(digest);
-			printf(" %c%s\n", bin_mode ? '*' : ' ', *argv);
+			printf(" %c", bin_mode ? '*' : ' ');
+			if (long_mode)
+				print_longfile(*argv);
+			else
+				printf("%s", *argv);
+			putchar('\n');
 		}
 		fclose(fp);
 	}
@@ -135,9 +145,10 @@
 void
 usage()
 {
-        fputs(_("usage: md5sum [-bv] [-c [file]] | [file...]\n\
+        fputs(_("usage: md5sum [-blv] [-c [file]] | [file...]\n\
 Generates or checks MD5 Message Digests\n\
     -c  check message digests (default is generate)\n\
+    -l  long output (includes file mode, uid, byte size and filename)\n\
     -v  verbose, print file names when checking\n\
     -b  read files in binary mode\n\
 The input for -c should be the list of message digests and file names\n\
@@ -220,6 +231,53 @@
 	return rc;
 }
 
+int 
+get_long_md5_line(FILE *fp, unsigned char *digest, char *file, int *mode,
+   int *uid, int *gid, int *size)
+{
+	char buf[1024];
+	int i, d1, d2, rc;
+	char *p = buf;
+
+	if (fgets(buf, sizeof(buf), fp) == NULL)
+		return -1;
+
+	for (i = 0; i < 16; ++i) {
+		if ((d1 = hex_digit(*p++)) == -1)
+			return 0;
+		if ((d2 = hex_digit(*p++)) == -1)
+			return 0;
+		*digest++ = d1*16 + d2;
+	}
+	if (*p++ != ' ')
+		return 0;
+	/*
+	 * next char is an attribute char, space means text file
+	 * if it's a '*' the file should be checked in binary mode.
+	 */
+	if (*p == ' ')
+		rc = 1;
+	else if (*p == '*')
+		rc = 2;
+	else {
+		fprintf(stderr, _("%s: unrecognized line: %s"), progname, buf);
+		return 0;
+	}
+	++p;
+	if (sscanf(p, "%d %d %d %d%l", mode, uid, gid, size, &i) < 4) {
+		fprintf(stderr, _("%s: unrecognized line: %s"), progname, buf);
+		return 0;
+	}
+	p+=i+1;
+	i = strlen(p);
+	if (i < 2 || i > 255)
+		return 0;
+	p[i-1] = '\0';
+	strcpy(file, p);
+	return rc;
+}
+
+
 int
 do_check(FILE *chkf)
 {
@@ -228,8 +286,20 @@
 	char filename[256];
 	FILE *fp;
 	int flen = 14;
+	int mode, uid, gid, size;
+	struct stat s;
 
-	while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) {
+	while (1) {
+		if (!long_mode)
+		{
+			rc = get_md5_line(chkf, chk_digest, filename);
+		}
+		else
+		{
+	       rc = get_long_md5_line(chkf, chk_digest, filename, &mode, &uid, 
+           &gid, &size);
+		}
+		if (rc < 0) break;
 		if (rc == 0)	/* not an md5 line */
 			continue;
 		if (verbose) {
@@ -253,14 +323,53 @@
 			continue;
 		}
 		fclose(fp);
-		if (memcmp(chk_digest, file_digest, 16) != 0) {
-			if (verbose)
+		if (lstat(filename, &s) != 0)
+		{
+			fprintf(stderr, _("%s: Stat of %s failed\n"), progname, filename);
+			ex = 2;
+			continue;
+		}
+
+		if (!verbose)
+		{
+			if (s.st_mode != mode)
+			{
+				++failed;
+				fprintf(stderr, _("%s: mode check failed for '%s'\n"), progname, filename);
+			}
+			else if (s.st_uid != uid)
+			{
+				++failed;
+				fprintf(stderr, _("%s: uid check failed for '%s'\n"), progname, filename);
+			}
+			else if (s.st_gid != gid)
+			{
+				++failed;
+				fprintf(stderr, _("%s: gid check failed for '%s'\n"), progname, filename);
+			}
+			else if (s.st_size != size)
+			{
+				++failed;
+				fprintf(stderr, _("%s: size check failed for '%s'\n"), progname, filename);
+			}
+			else if (memcmp(chk_digest, file_digest, 16) != 0)
+			{
+				++failed;
+				fprintf(stderr, _("%s: MD5 check failed for '%s'\n"), progname, filename);
+			}
+		}
+		else
+		{
+			if ((s.st_mode != mode) || (s.st_uid != uid) || 
+				 (s.st_gid != gid) || (s.st_size != size) ||
+				 (memcmp(chk_digest, file_digest, 16) != 0)) 
+			{
 				fprintf(stderr, _("FAILED\n"));
+				++failed;
+			}
 			else
-				fprintf(stderr, _("%s: MD5 check failed for '%s'\n"), progname, filename);
-			++failed;
-		} else if (verbose)
-			fprintf(stderr, _("OK\n"));
+				fprintf(stderr, _("OK\n"));
+		}
 		++checked;
 	}
 	if (verbose && failed)
@@ -274,3 +383,21 @@
 	return ex;
 }
 
+
+int print_longfile(char *filename)
+{
+	struct stat s;
+
+	if (lstat(filename, &s) != 0)
+	{
+		fprintf(stderr, _("%s: Stat of %s failed\n"), progname, filename);
+		return 1;
+	}
+
+//	printf("%d %s %s %d %s", s->st_mode, getpwuid(s->st_uid)->pw_name,
+//	   getgrgid(s->st_gid)->gr_name, s->st_size, filename);
+	printf("%d %d %d %d %s", s.st_mode, s.st_uid,
+	   s.st_gid, s.st_size, filename);
+
+	return 0;
+}

Attachment: pgpKFM5Dq5FjA.pgp
Description: PGP signature


Reply to: