|
|
1.1 ! root 1: /* ! 2: * md5sum.c - Generate/check MD5 Message Digests ! 3: * ! 4: * Compile and link with md5.c. If you don't have getopt() in your library ! 5: * also include getopt.c. For MSDOS you can also link with the wildcard ! 6: * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC) ! 7: * so that you can use wildcards on the commandline. ! 8: * ! 9: * Written March 1993 by Branko Lankester ! 10: */ ! 11: #include <stdio.h> ! 12: #include <string.h> ! 13: #include "md5.h" ! 14: ! 15: #ifdef UNIX ! 16: #define FOPRTXT "r" ! 17: #define FOPRBIN "r" ! 18: #else ! 19: #ifdef VMS ! 20: #define FOPRTXT "r","ctx=stm" ! 21: #define FOPRBIN "rb","ctx=stm" ! 22: #else ! 23: #define FOPRTXT "r" ! 24: #define FOPRBIN "rb" ! 25: #endif ! 26: #endif ! 27: ! 28: extern char *optarg; ! 29: extern int optind; ! 30: ! 31: void usage(); ! 32: void print_digest(); ! 33: int mdfile(FILE *fp, unsigned char *digest); ! 34: int do_check(FILE *chkf); ! 35: ! 36: char *progname; ! 37: int verbose = 0; ! 38: int bin_mode = 0; ! 39: ! 40: void ! 41: main(int argc, char **argv) ! 42: { ! 43: int opt, rc = 0; ! 44: int check = 0; ! 45: FILE *fp; ! 46: unsigned char digest[16]; ! 47: ! 48: progname = *argv; ! 49: while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) { ! 50: switch (opt) { ! 51: case 'c': check = 1; break; ! 52: case 'v': verbose = 1; break; ! 53: case 'b': bin_mode = 1; break; ! 54: default: usage(); ! 55: } ! 56: } ! 57: argc -= optind; ! 58: argv += optind; ! 59: if (check) { ! 60: switch (argc) { ! 61: case 0: fp = stdin; break; ! 62: case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) { ! 63: perror(*argv); ! 64: exit(2); ! 65: } ! 66: break; ! 67: default: usage(); ! 68: } ! 69: exit(do_check(fp)); ! 70: } ! 71: if (argc == 0) { ! 72: if (mdfile(stdin, digest)) { ! 73: fprintf(stderr, "%s: read error on stdin\n", progname); ! 74: exit(2); ! 75: } ! 76: print_digest(digest); ! 77: printf("\n"); ! 78: exit(0); ! 79: } ! 80: for ( ; argc > 0; --argc, ++argv) { ! 81: if (bin_mode) ! 82: fp = fopen(*argv, FOPRBIN); ! 83: else ! 84: fp = fopen(*argv, FOPRTXT); ! 85: if (fp == NULL) { ! 86: perror(*argv); ! 87: rc = 2; ! 88: continue; ! 89: } ! 90: if (mdfile(fp, digest)) { ! 91: fprintf(stderr, "%s: error reading %s\n", progname, *argv); ! 92: rc = 2; ! 93: } else { ! 94: print_digest(digest); ! 95: printf(" %c%s\n", bin_mode ? '*' : ' ', *argv); ! 96: } ! 97: fclose(fp); ! 98: } ! 99: exit(rc); ! 100: } ! 101: ! 102: void ! 103: usage() ! 104: { ! 105: fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n"); ! 106: fprintf(stderr, "Generates or checks MD5 Message Digests\n"); ! 107: fprintf(stderr, " -c check message digests (default is generate)\n"); ! 108: fprintf(stderr, " -v verbose, print file names when checking\n"); ! 109: fprintf(stderr, " -b read files in binary mode\n"); ! 110: fprintf(stderr, "The input for -c should be the list of message digests and file names\n"); ! 111: fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n"); ! 112: exit(2); ! 113: } ! 114: ! 115: int ! 116: mdfile(FILE *fp, unsigned char *digest) ! 117: { ! 118: unsigned char buf[1024]; ! 119: MD5_CTX ctx; ! 120: int n; ! 121: ! 122: MD5Init(&ctx); ! 123: while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) ! 124: MD5Update(&ctx, buf, n); ! 125: MD5Final(&ctx); ! 126: memcpy(digest, ctx.digest, 16); ! 127: if (ferror(fp)) ! 128: return -1; ! 129: return 0; ! 130: } ! 131: ! 132: void ! 133: print_digest(unsigned char *p) ! 134: { ! 135: int i; ! 136: ! 137: for (i = 0; i < 16; ++i) ! 138: printf("%02x", *p++); ! 139: } ! 140: ! 141: int ! 142: hex_digit(int c) ! 143: { ! 144: if (c >= '0' && c <= '9') ! 145: return c - '0'; ! 146: if (c >= 'a' && c <= 'f') ! 147: return c - 'a' + 10; ! 148: return -1; ! 149: } ! 150: ! 151: int ! 152: get_md5_line(FILE *fp, unsigned char *digest, char *file) ! 153: { ! 154: char buf[1024]; ! 155: int i, d1, d2, rc; ! 156: char *p = buf; ! 157: ! 158: if (fgets(buf, sizeof(buf), fp) == NULL) ! 159: return -1; ! 160: ! 161: for (i = 0; i < 16; ++i) { ! 162: if ((d1 = hex_digit(*p++)) == -1) ! 163: return 0; ! 164: if ((d2 = hex_digit(*p++)) == -1) ! 165: return 0; ! 166: *digest++ = d1*16 + d2; ! 167: } ! 168: if (*p++ != ' ') ! 169: return 0; ! 170: /* ! 171: * next char is an attribute char, space means text file ! 172: * if it's a '*' the file should be checked in binary mode. ! 173: */ ! 174: if (*p == ' ') ! 175: rc = 1; ! 176: else if (*p == '*') ! 177: rc = 2; ! 178: else { ! 179: fprintf(stderr, "%s: unrecognized line: %s", progname, buf); ! 180: return 0; ! 181: } ! 182: ++p; ! 183: i = strlen(p); ! 184: if (i < 2 || i > 255) ! 185: return 0; ! 186: p[i-1] = '\0'; ! 187: strcpy(file, p); ! 188: return rc; ! 189: } ! 190: ! 191: int ! 192: do_check(FILE *chkf) ! 193: { ! 194: int rc, ex = 0, failed = 0, checked = 0; ! 195: unsigned char chk_digest[16], file_digest[16]; ! 196: char filename[256]; ! 197: FILE *fp; ! 198: int flen = 14; ! 199: ! 200: while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) { ! 201: if (rc == 0) /* not an md5 line */ ! 202: continue; ! 203: if (verbose) { ! 204: if (strlen(filename) > flen) ! 205: flen = strlen(filename); ! 206: fprintf(stderr, "%-*s ", flen, filename); ! 207: } ! 208: if (bin_mode || rc == 2) ! 209: fp = fopen(filename, FOPRBIN); ! 210: else ! 211: fp = fopen(filename, FOPRTXT); ! 212: if (fp == NULL) { ! 213: fprintf(stderr, "%s: can't open %s\n", progname, filename); ! 214: ex = 2; ! 215: continue; ! 216: } ! 217: if (mdfile(fp, file_digest)) { ! 218: fprintf(stderr, "%s: error reading %s\n", progname, filename); ! 219: ex = 2; ! 220: fclose(fp); ! 221: continue; ! 222: } ! 223: fclose(fp); ! 224: if (memcmp(chk_digest, file_digest, 16) != 0) { ! 225: if (verbose) ! 226: fprintf(stderr, "FAILED\n"); ! 227: else ! 228: fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename); ! 229: ++failed; ! 230: } else if (verbose) ! 231: fprintf(stderr, "OK\n"); ! 232: ++checked; ! 233: } ! 234: if (verbose && failed) ! 235: fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked); ! 236: if (!checked) { ! 237: fprintf(stderr, "%s: no files checked\n", progname); ! 238: return 3; ! 239: } ! 240: if (!ex && failed) ! 241: ex = 1; ! 242: return ex; ! 243: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.