|
|
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
1.1.1.2 ! root 10: * Modified June 1993 by Colin Plumb for altered md5.c.
1.1 root 11: */
12: #include <stdio.h>
13: #include <string.h>
14: #include "md5.h"
15:
16: #ifdef UNIX
17: #define FOPRTXT "r"
18: #define FOPRBIN "r"
19: #else
20: #ifdef VMS
21: #define FOPRTXT "r","ctx=stm"
22: #define FOPRBIN "rb","ctx=stm"
23: #else
24: #define FOPRTXT "r"
25: #define FOPRBIN "rb"
26: #endif
27: #endif
28:
29: extern char *optarg;
30: extern int optind;
31:
32: void usage();
33: void print_digest();
34: int mdfile(FILE *fp, unsigned char *digest);
35: int do_check(FILE *chkf);
36:
37: char *progname;
38: int verbose = 0;
39: int bin_mode = 0;
40:
41: void
42: main(int argc, char **argv)
43: {
44: int opt, rc = 0;
45: int check = 0;
46: FILE *fp;
47: unsigned char digest[16];
48:
49: progname = *argv;
50: while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) {
51: switch (opt) {
52: case 'c': check = 1; break;
53: case 'v': verbose = 1; break;
54: case 'b': bin_mode = 1; break;
55: default: usage();
56: }
57: }
58: argc -= optind;
59: argv += optind;
60: if (check) {
61: switch (argc) {
62: case 0: fp = stdin; break;
63: case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) {
64: perror(*argv);
65: exit(2);
66: }
67: break;
68: default: usage();
69: }
70: exit(do_check(fp));
71: }
72: if (argc == 0) {
73: if (mdfile(stdin, digest)) {
74: fprintf(stderr, "%s: read error on stdin\n", progname);
75: exit(2);
76: }
77: print_digest(digest);
78: printf("\n");
79: exit(0);
80: }
81: for ( ; argc > 0; --argc, ++argv) {
82: if (bin_mode)
83: fp = fopen(*argv, FOPRBIN);
84: else
85: fp = fopen(*argv, FOPRTXT);
86: if (fp == NULL) {
87: perror(*argv);
88: rc = 2;
89: continue;
90: }
91: if (mdfile(fp, digest)) {
92: fprintf(stderr, "%s: error reading %s\n", progname, *argv);
93: rc = 2;
94: } else {
95: print_digest(digest);
96: printf(" %c%s\n", bin_mode ? '*' : ' ', *argv);
97: }
98: fclose(fp);
99: }
100: exit(rc);
101: }
102:
103: void
104: usage()
105: {
106: fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n");
107: fprintf(stderr, "Generates or checks MD5 Message Digests\n");
108: fprintf(stderr, " -c check message digests (default is generate)\n");
109: fprintf(stderr, " -v verbose, print file names when checking\n");
110: fprintf(stderr, " -b read files in binary mode\n");
111: fprintf(stderr, "The input for -c should be the list of message digests and file names\n");
112: fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n");
113: exit(2);
114: }
115:
116: int
117: mdfile(FILE *fp, unsigned char *digest)
118: {
119: unsigned char buf[1024];
120: MD5_CTX ctx;
121: int n;
122:
123: MD5Init(&ctx);
124: while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
125: MD5Update(&ctx, buf, n);
1.1.1.2 ! root 126: MD5Final(digest, &ctx);
1.1 root 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.