diff options
-rw-r--r-- | bin/md5/md5.1 | 16 | ||||
-rw-r--r-- | bin/md5/md5.c | 201 | ||||
-rw-r--r-- | bin/md5/rmd160.1 | 16 | ||||
-rw-r--r-- | bin/md5/sha1.1 | 16 |
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 |