summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-03-12 21:29:49 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-03-12 21:29:49 +0000
commit1bbcfba63374504a5459a48ea8a981b8b9f7a124 (patch)
tree5cb9a09f7f31a7e648d43d275cb50feeb0c87fac /bin
parentac43af987f8e2a72b28ac1667dad943c99786692 (diff)
Add -c option similar to GNU md5sum.
Original patch from zyrnix but significantly modified by me. deraadt@ OK
Diffstat (limited to 'bin')
-rw-r--r--bin/md5/md5.116
-rw-r--r--bin/md5/md5.c201
-rw-r--r--bin/md5/rmd160.116
-rw-r--r--bin/md5/sha1.116
4 files changed, 207 insertions, 42 deletions
diff --git a/bin/md5/md5.1 b/bin/md5/md5.1
index d7dc96d3298..f6fd7c9e3df 100644
--- a/bin/md5/md5.1
+++ b/bin/md5/md5.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: md5.1,v 1.13 2003/02/19 17:52:18 millert Exp $
+.\" $OpenBSD: md5.1,v 1.14 2003/03/12 21:29:48 millert Exp $
.\"
.\" Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
.\" All rights reserved.
@@ -33,7 +33,9 @@
.Nm md5
.Oo
.Fl p | Fl t | Fl x |
-.Fl s Ar string | Ar file ...
+.Fl s Ar string |
+.Fl c Ar [ file ... ] |
+.Ar file ...
.Oc
.Sh DESCRIPTION
.Nm
@@ -56,6 +58,16 @@ The options are as follows:
.It Fl s Ar string
Prints a checksum of the given
.Ar string .
+.It Fl c Ar [ file ... ]
+Compares all checksums in the
+.Ar file
+with new computed checksums for the files mentioned in the
+.Ar file .
+Output consists of which digest was used, the file name,
+and an OK or FAILED for the result of the comparison. This will
+validate any of the supported checksums in the
+.Ar file
+including RMD-160 and SHA-1. If no file is given, stdin is used.
.It Fl p
Echos stdin to stdout and appends the
.Em MD5
diff --git a/bin/md5/md5.c b/bin/md5/md5.c
index 4177eb5c90b..49aaef57a44 100644
--- a/bin/md5/md5.c
+++ b/bin/md5/md5.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: md5.c,v 1.16 2003/01/14 17:15:53 millert Exp $ */
+/* $OpenBSD: md5.c,v 1.17 2003/03/12 21:29:48 millert Exp $ */
/*
- * Copyright (c) 2001 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2001,2003 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,6 +28,7 @@
*/
#include <sys/param.h>
+#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
@@ -40,9 +41,7 @@
#include <sha1.h>
#include <rmd160.h>
-#define DIGEST_MD5 0
-#define DIGEST_SHA1 1
-#define DIGEST_RMD160 2
+#define MAX_DIGEST_LEN 40
union ANY_CTX {
MD5_CTX md5;
@@ -52,6 +51,7 @@ union ANY_CTX {
struct hash_functions {
char *name;
+ int digestlen;
void (*init)();
void (*update)();
char * (*end)();
@@ -61,19 +61,25 @@ struct hash_functions {
struct hash_functions functions[] = {
{
"MD5",
+ 32,
MD5Init, MD5Update, MD5End, MD5File, MD5Data
}, {
"SHA1",
+ 40,
SHA1Init, SHA1Update, SHA1End, SHA1File, SHA1Data
}, {
"RMD160",
+ 40,
RMD160Init, RMD160Update, RMD160End, RMD160File, RMD160Data
+ }, {
+ NULL,
},
};
extern char *__progname;
static void usage(void);
static void digest_file(char *, struct hash_functions *, int);
+static int digest_filelist(char *);
static void digest_string(char *, struct hash_functions *);
static void digest_test(struct hash_functions *);
static void digest_time(struct hash_functions *);
@@ -81,22 +87,26 @@ static void digest_time(struct hash_functions *);
int
main(int argc, char **argv)
{
- int fl, digest_type;
- int pflag, tflag, xflag;
+ int fl, digest_type, error;
+ int cflag, pflag, tflag, xflag;
char *input_string;
/* Set digest type based on program name, defaults to MD5. */
- if (strcmp(__progname, "rmd160") == 0)
- digest_type = DIGEST_RMD160;
- else if (strcmp(__progname, "sha1") == 0)
- digest_type = DIGEST_SHA1;
- else
- digest_type = DIGEST_MD5;
+ for (digest_type = 0; functions[digest_type].name != NULL;
+ digest_type++) {
+ if (strcasecmp(functions[digest_type].name, __progname) == 0)
+ break;
+ }
+ if (functions[digest_type].name == NULL)
+ digest_type = 0;
input_string = NULL;
- pflag = tflag = xflag = 0;
- while ((fl = getopt(argc, argv, "ps:tx")) != -1) {
+ error = cflag = pflag = tflag = xflag = 0;
+ while ((fl = getopt(argc, argv, "pctxs:")) != -1) {
switch (fl) {
+ case 'c':
+ cflag = 1;
+ break;
case 'p':
pflag = 1;
break;
@@ -117,8 +127,8 @@ main(int argc, char **argv)
argv += optind;
/* All arguments are mutually exclusive */
- fl = pflag + tflag + xflag + (input_string != NULL);
- if (fl > 1 || (fl && argc))
+ fl = pflag + tflag + xflag + cflag + (input_string != NULL);
+ if (fl > 1 || (fl && argc && cflag == 0))
usage();
if (tflag)
@@ -127,23 +137,28 @@ main(int argc, char **argv)
digest_test(&functions[digest_type]);
else if (input_string)
digest_string(input_string, &functions[digest_type]);
+ else if (cflag)
+ if (argc == 0)
+ error = digest_filelist("-");
+ else
+ while (argc--)
+ error += digest_filelist(*argv++);
else if (pflag || argc == 0)
digest_file("-", &functions[digest_type], pflag);
else
while (argc--)
digest_file(*argv++, &functions[digest_type], 0);
- exit(0);
+ exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
}
static void
digest_string(char *string, struct hash_functions *hf)
{
- char *digest;
+ char digest[MAX_DIGEST_LEN + 1];
- digest = hf->data(string, strlen(string), NULL);
+ (void)hf->data(string, strlen(string), digest);
(void)printf("%s (\"%s\") = %s\n", hf->name, string, digest);
- free(digest);
}
static void
@@ -152,7 +167,7 @@ digest_file(char *file, struct hash_functions *hf, int echo)
int fd;
ssize_t nread;
u_char data[BUFSIZ];
- char *digest;
+ char digest[MAX_DIGEST_LEN + 1];
union ANY_CTX context;
if (strcmp(file, "-") == 0)
@@ -173,11 +188,11 @@ digest_file(char *file, struct hash_functions *hf, int echo)
}
if (nread == -1) {
warn("%s: read error", file);
- if (fd != STDIN_FILENO)
+ if (fd != STDIN_FILENO)
close(fd);
return;
}
- digest = hf->end(&context, NULL);
+ (void)hf->end(&context, digest);
if (fd == STDIN_FILENO) {
(void)puts(digest);
@@ -185,7 +200,124 @@ digest_file(char *file, struct hash_functions *hf, int echo)
close(fd);
(void)printf("%s (%s) = %s\n", hf->name, file, digest);
}
- free(digest);
+}
+
+/*
+ * Parse through the input file looking for valid lines.
+ * If one is found, use this checksum and file as a reference and
+ * generate a new checksum against the file on the filesystem.
+ * Print out the result of each comparison.
+ */
+static int
+digest_filelist(char *file)
+{
+ int fd, found, error;
+ int algorithm_max, algorithm_min;
+ char *algorithm, *filename, *checksum, *buf, *p;
+ char digest[MAX_DIGEST_LEN + 1];
+ char *lbuf = NULL;
+ FILE *fp;
+ ssize_t nread;
+ size_t len;
+ u_char data[BUFSIZ];
+ union ANY_CTX context;
+ struct hash_functions *hf;
+
+ if (strcmp(file, "-") == 0) {
+ fp = stdin;
+ } else if ((fp = fopen(file, "r")) == NULL) {
+ warn("cannot open %s", file);
+ return(1);
+ }
+
+ algorithm_max = algorithm_min = strlen(functions[0].name);
+ for (hf = &functions[1]; hf->name != NULL; hf++) {
+ len = strlen(hf->name);
+ algorithm_max = MAX(algorithm_max, len);
+ algorithm_min = MIN(algorithm_min, len);
+ }
+
+ error = found = 0;
+ while ((buf = fgetln(fp, &len))) {
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ else {
+ if ((lbuf = malloc(len + 1)) == NULL)
+ err(1, NULL);
+
+ (void)memcpy(lbuf, buf, len);
+ lbuf[len] = '\0';
+ buf = lbuf;
+ }
+ while (isspace(*buf))
+ buf++;
+
+ /*
+ * Crack the line into an algorithm, filename, and checksum.
+ * Lines are of the form:
+ * ALGORITHM (FILENAME) = CHECKSUM
+ */
+ algorithm = buf;
+ p = strchr(algorithm, ' ');
+ if (p == NULL || *(p + 1) != '(')
+ continue;
+ *p = '\0';
+ len = strlen(algorithm);
+ if (len > algorithm_max || len < algorithm_min)
+ continue;
+
+ filename = p + 2;
+ p = strchr(filename, ')');
+ if (p == NULL || strncmp(p + 1, " = ", 3) != 0)
+ continue;
+ *p = '\0';
+
+ checksum = p + 4;
+ p = strpbrk(checksum, " \t\r");
+ if (p != NULL)
+ *p = '\0';
+
+ /*
+ * Check that the algorithm is one we recognize.
+ */
+ for (hf = functions; hf->name != NULL; hf++) {
+ if (strcmp(algorithm, hf->name) == 0)
+ break;
+ }
+ if (hf->name == NULL || strlen(checksum) != hf->digestlen)
+ continue;
+
+ if ((fd = open(filename, O_RDONLY, 0)) == -1) {
+ warn("cannot open %s", filename);
+ (void)printf("(%s) %s: FAILED\n", algorithm, filename);
+ error = 1;
+ continue;
+ }
+
+ found = 1;
+ hf->init(&context);
+ while ((nread = read(fd, data, sizeof(data))) > 0)
+ hf->update(&context, data, nread);
+ if (nread == -1) {
+ warn("%s: read error", file);
+ error = 1;
+ close(fd);
+ continue;
+ }
+ close(fd);
+ (void)hf->end(&context, digest);
+
+ if (strcmp(checksum, digest) == 0)
+ (void)printf("(%s) %s: OK\n", algorithm, filename);
+ else
+ (void)printf("(%s) %s: FAILED\n", algorithm, filename);
+ }
+ (void)fclose(fp);
+ if (!found)
+ warnx("%s: no properly formatted checksum lines found", file);
+ if (lbuf != NULL)
+ free(lbuf);
+ return(error || !found);
}
#define TEST_BLOCK_LEN 10000
@@ -198,7 +330,7 @@ digest_time(struct hash_functions *hf)
union ANY_CTX context;
u_int i;
u_char data[TEST_BLOCK_LEN];
- char *digest;
+ char digest[MAX_DIGEST_LEN + 1];
double elapsed;
(void)printf("%s time trial. Processing %d %d-byte blocks...",
@@ -213,7 +345,7 @@ digest_time(struct hash_functions *hf)
hf->init(&context);
for (i = 0; i < TEST_BLOCK_COUNT; i++)
hf->update(&context, data, TEST_BLOCK_LEN);
- digest = hf->end(&context, NULL);
+ (void)hf->end(&context, digest);
gettimeofday(&stop, NULL);
timersub(&stop, &start, &res);
elapsed = res.tv_sec + res.tv_usec / 1000000.0;
@@ -222,7 +354,6 @@ digest_time(struct hash_functions *hf)
(void)printf("Time = %f seconds\n", elapsed);
(void)printf("Speed = %f bytes/second\n",
TEST_BLOCK_LEN * TEST_BLOCK_COUNT / elapsed);
- free(digest);
}
static void
@@ -230,7 +361,7 @@ digest_test(struct hash_functions *hf)
{
union ANY_CTX context;
int i;
- char *digest, buf[1000];
+ char digest[MAX_DIGEST_LEN + 1], buf[1000];
char *test_strings[] = {
"",
"a",
@@ -249,10 +380,9 @@ digest_test(struct hash_functions *hf)
for (i = 0; i < 8; i++) {
hf->init(&context);
hf->update(&context, test_strings[i], strlen(test_strings[i]));
- digest = hf->end(&context, NULL);
+ (void)hf->end(&context, digest);
(void)printf("%s (\"%s\") = %s\n", hf->name, test_strings[i],
digest);
- free(digest);
}
/* Now simulate a string of a million 'a' characters. */
@@ -260,17 +390,16 @@ digest_test(struct hash_functions *hf)
hf->init(&context);
for (i = 0; i < 1000; i++)
hf->update(&context, buf, sizeof(buf));
- digest = hf->end(&context, NULL);
+ (void)hf->end(&context, digest);
(void)printf("%s (one million 'a' characters) = %s\n",
hf->name, digest);
- free(digest);
-
}
static void
usage()
{
- fprintf(stderr, "usage: %s [-p | -t | -x | -s string | file ...]\n",
+ fprintf(stderr, "usage: %s [-p | -t | -x | -c [ checksum_file ... ]",
__progname);
- exit(1);
+ fprintf(stderr, " | -s string | file ...]\n");
+ exit(EXIT_FAILURE);
}
diff --git a/bin/md5/rmd160.1 b/bin/md5/rmd160.1
index 5d13e974c07..0b0e671bc03 100644
--- a/bin/md5/rmd160.1
+++ b/bin/md5/rmd160.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: rmd160.1,v 1.11 2003/02/19 17:52:18 millert Exp $
+.\" $OpenBSD: rmd160.1,v 1.12 2003/03/12 21:29:48 millert Exp $
.\"
.\" Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
.\" All rights reserved.
@@ -33,7 +33,9 @@
.Nm rmd160
.Oo
.Fl p | Fl t | Fl x |
-.Fl s Ar string | Ar file ...
+.Fl s Ar string |
+.Fl c Ar [ file ... ] |
+.Ar file ...
.Oc
.Sh DESCRIPTION
.Nm
@@ -56,6 +58,16 @@ The options are as follows:
.It Fl s Ar string
Prints a checksum of the given
.Ar string .
+.It Fl c Ar [ file ... ]
+Compares all checksums in the
+.Ar file
+with new computed checksums for the files mentioned in the
+.Ar file .
+Output consists of which digest was used, the file name,
+and an OK or FAILED for the result of the comparison. This will
+validate any of the supported checksums in the
+.Ar file
+including MD5 and SHA-1. If no file is given, stdin is used.
.It Fl p
Echos stdin to stdout and appends the
.Em RMD-160
diff --git a/bin/md5/sha1.1 b/bin/md5/sha1.1
index 4fc3f547d6e..cd0a226ce80 100644
--- a/bin/md5/sha1.1
+++ b/bin/md5/sha1.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sha1.1,v 1.12 2003/02/19 17:52:18 millert Exp $
+.\" $OpenBSD: sha1.1,v 1.13 2003/03/12 21:29:48 millert Exp $
.\"
.\" Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
.\" All rights reserved.
@@ -33,7 +33,9 @@
.Nm sha1
.Oo
.Fl p | Fl t | Fl x |
-.Fl s Ar string | Ar file ...
+.Fl s Ar string |
+.Fl c Ar [ file ... ] |
+.Ar file ...
.Oc
.Sh DESCRIPTION
.Nm
@@ -56,6 +58,16 @@ The options are as follows:
.It Fl s Ar string
Prints a checksum of the given
.Ar string .
+.It Fl c Ar [ file ... ]
+Compares all checksums in the
+.Ar file
+with new computed checksums for the files mentioned in the
+.Ar file .
+Output consists of which digest was used, the file name,
+and an OK or FAILED for the result of the comparison. This will
+validate any of the supported checksums in the
+.Ar file
+including MD5 and RMD-160. If no file is given, stdin is used.
.It Fl p
Echos stdin to stdout and appends the
.Em SHA-1