|
|
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.