GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/md5/md5.c Lines: 134 339 39.5 %
Date: 2017-11-13 Branches: 91 271 33.6 %

Line Branch Exec Source
1
/*	$OpenBSD: md5.c,v 1.92 2017/09/11 16:35:38 millert Exp $	*/
2
3
/*
4
 * Copyright (c) 2001,2003,2005-2007,2010,2013,2014
5
 *	Todd C. Miller <Todd.Miller@courtesan.com>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 *
19
 * Sponsored in part by the Defense Advanced Research Projects
20
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22
 */
23
24
#include <sys/types.h>
25
#include <sys/time.h>
26
#include <sys/queue.h>
27
#include <sys/resource.h>
28
#include <netinet/in.h>
29
#include <ctype.h>
30
#include <err.h>
31
#include <fcntl.h>
32
#include <resolv.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <limits.h>
37
#include <time.h>
38
#include <unistd.h>
39
#include <errno.h>
40
41
#include <md5.h>
42
#include <rmd160.h>
43
#include <sha1.h>
44
#include <sha2.h>
45
#include <crc.h>
46
47
#define STYLE_MD5	0
48
#define STYLE_CKSUM	1
49
#define STYLE_TERSE	2
50
51
#define MAX_DIGEST_LEN	128
52
53
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
54
#define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
55
56
union ANY_CTX {
57
#if !defined(SHA2_ONLY)
58
	CKSUM_CTX cksum;
59
	MD5_CTX md5;
60
	RMD160_CTX rmd160;
61
	SHA1_CTX sha1;
62
#endif /* !defined(SHA2_ONLY) */
63
	SHA2_CTX sha2;
64
};
65
66
struct hash_function {
67
	const char *name;
68
	size_t digestlen;
69
	int style;
70
	int base64;
71
	void *ctx;	/* XXX - only used by digest_file() */
72
	void (*init)(void *);
73
	void (*update)(void *, const unsigned char *, size_t);
74
	void (*final)(unsigned char *, void *);
75
	char * (*end)(void *, char *);
76
	TAILQ_ENTRY(hash_function) tailq;
77
} functions[] = {
78
#if !defined(SHA2_ONLY)
79
	{
80
		"CKSUM",
81
		CKSUM_DIGEST_LENGTH,
82
		STYLE_CKSUM,
83
		-1,
84
		NULL,
85
		(void (*)(void *))CKSUM_Init,
86
		(void (*)(void *, const unsigned char *, size_t))CKSUM_Update,
87
		(void (*)(unsigned char *, void *))CKSUM_Final,
88
		(char *(*)(void *, char *))CKSUM_End
89
	},
90
	{
91
		"MD5",
92
		MD5_DIGEST_LENGTH,
93
		STYLE_MD5,
94
		0,
95
		NULL,
96
		(void (*)(void *))MD5Init,
97
		(void (*)(void *, const unsigned char *, size_t))MD5Update,
98
		(void (*)(unsigned char *, void *))MD5Final,
99
		(char *(*)(void *, char *))MD5End
100
	},
101
	{
102
		"RMD160",
103
		RMD160_DIGEST_LENGTH,
104
		STYLE_MD5,
105
		0,
106
		NULL,
107
		(void (*)(void *))RMD160Init,
108
		(void (*)(void *, const unsigned char *, size_t))RMD160Update,
109
		(void (*)(unsigned char *, void *))RMD160Final,
110
		(char *(*)(void *, char *))RMD160End
111
	},
112
	{
113
		"SHA1",
114
		SHA1_DIGEST_LENGTH,
115
		STYLE_MD5,
116
		0,
117
		NULL,
118
		(void (*)(void *))SHA1Init,
119
		(void (*)(void *, const unsigned char *, size_t))SHA1Update,
120
		(void (*)(unsigned char *, void *))SHA1Final,
121
		(char *(*)(void *, char *))SHA1End
122
	},
123
	{
124
		"SHA224",
125
		SHA224_DIGEST_LENGTH,
126
		STYLE_MD5,
127
		0,
128
		NULL,
129
		(void (*)(void *))SHA224Init,
130
		(void (*)(void *, const unsigned char *, size_t))SHA224Update,
131
		(void (*)(unsigned char *, void *))SHA224Final,
132
		(char *(*)(void *, char *))SHA224End
133
	},
134
#endif /* !defined(SHA2_ONLY) */
135
	{
136
		"SHA256",
137
		SHA256_DIGEST_LENGTH,
138
		STYLE_MD5,
139
		0,
140
		NULL,
141
		(void (*)(void *))SHA256Init,
142
		(void (*)(void *, const unsigned char *, size_t))SHA256Update,
143
		(void (*)(unsigned char *, void *))SHA256Final,
144
		(char *(*)(void *, char *))SHA256End
145
	},
146
#if !defined(SHA2_ONLY)
147
	{
148
		"SHA384",
149
		SHA384_DIGEST_LENGTH,
150
		STYLE_MD5,
151
		0,
152
		NULL,
153
		(void (*)(void *))SHA384Init,
154
		(void (*)(void *, const unsigned char *, size_t))SHA384Update,
155
		(void (*)(unsigned char *, void *))SHA384Final,
156
		(char *(*)(void *, char *))SHA384End
157
	},
158
	{
159
		"SHA512/256",
160
		SHA512_256_DIGEST_LENGTH,
161
		STYLE_MD5,
162
		0,
163
		NULL,
164
		(void (*)(void *))SHA512_256Init,
165
		(void (*)(void *, const unsigned char *, size_t))SHA512_256Update,
166
		(void (*)(unsigned char *, void *))SHA512_256Final,
167
		(char *(*)(void *, char *))SHA512_256End
168
	},
169
#endif /* !defined(SHA2_ONLY) */
170
	{
171
		"SHA512",
172
		SHA512_DIGEST_LENGTH,
173
		STYLE_MD5,
174
		0,
175
		NULL,
176
		(void (*)(void *))SHA512Init,
177
		(void (*)(void *, const unsigned char *, size_t))SHA512Update,
178
		(void (*)(unsigned char *, void *))SHA512Final,
179
		(char *(*)(void *, char *))SHA512End
180
	},
181
	{
182
		NULL,
183
	}
184
};
185
186
TAILQ_HEAD(hash_list, hash_function);
187
188
void digest_end(const struct hash_function *, void *, char *, size_t, int);
189
int  digest_file(const char *, struct hash_list *, int);
190
void digest_print(const struct hash_function *, const char *, const char *);
191
#if !defined(SHA2_ONLY)
192
int  digest_filelist(const char *, struct hash_function *, int, char **);
193
void digest_printstr(const struct hash_function *, const char *, const char *);
194
void digest_string(char *, struct hash_list *);
195
void digest_test(struct hash_list *);
196
void digest_time(struct hash_list *, int);
197
#endif /* !defined(SHA2_ONLY) */
198
void hash_insert(struct hash_list *, struct hash_function *, int);
199
void usage(void) __attribute__((__noreturn__));
200
201
extern char *__progname;
202
int qflag = 0;
203
FILE *ofile = NULL;
204
205
int
206
main(int argc, char **argv)
207
{
208
	struct hash_function *hf, *hftmp;
209
160
	struct hash_list hl;
210
	size_t len;
211
	char *cp, *input_string, *selective_checklist;
212
	const char *optstr;
213
	int fl, error, base64;
214
	int bflag, cflag, pflag, rflag, tflag, xflag;
215
216
80
	if (pledge("stdio rpath wpath cpath flock", NULL) == -1)
217
		err(1, "pledge");
218
219
80
	TAILQ_INIT(&hl);
220
	input_string = NULL;
221
	selective_checklist = NULL;
222
80
	error = bflag = cflag = pflag = qflag = rflag = tflag = xflag = 0;
223
224
#if !defined(SHA2_ONLY)
225
80
	if (strcmp(__progname, "cksum") == 0)
226
18
		optstr = "a:bC:ch:pqrs:tx";
227
	else
228
#endif /* !defined(SHA2_ONLY) */
229
		optstr = "bC:ch:pqrs:tx";
230
231
	/* Check for -b option early since it changes behavior. */
232
316
	while ((fl = getopt(argc, argv, optstr)) != -1) {
233
78
		switch (fl) {
234
		case 'b':
235
			bflag = 1;
236
			break;
237
		case '?':
238
			usage();
239
		}
240
	}
241
80
	optind = 1;
242
80
	optreset = 1;
243
316
	while ((fl = getopt(argc, argv, optstr)) != -1) {
244



156
		switch (fl) {
245
		case 'a':
246
48
			while ((cp = strsep(&optarg, " \t,")) != NULL) {
247
12
				if (*cp == '\0')
248
					continue;
249
				base64 = -1;
250
144
				for (hf = functions; hf->name != NULL; hf++) {
251
72
					len = strlen(hf->name);
252
72
					if (strncasecmp(cp, hf->name, len) != 0)
253
						continue;
254
12
					if (cp[len] == '\0') {
255
12
						if (hf->base64 != -1)
256
12
							base64 = bflag;
257
						break;	/* exact match */
258
					}
259
					if (cp[len + 1] == '\0' &&
260
					    (cp[len] == 'b' || cp[len] == 'x')) {
261
						base64 =
262
						    cp[len] == 'b' ?  1 : 0;
263
						break;	/* match w/ suffix */
264
					}
265
				}
266
12
				if (hf->name == NULL) {
267
					warnx("unknown algorithm \"%s\"", cp);
268
					usage();
269
				}
270
12
				if (hf->base64 == -1 && base64 != -1) {
271
					warnx("%s doesn't support %s",
272
					    hf->name,
273
					    base64 ? "base64" : "hex");
274
					usage();
275
				}
276
				/* Check for dupes. */
277
24
				TAILQ_FOREACH(hftmp, &hl, tailq) {
278
					if (hftmp->base64 == base64 &&
279
					    strcmp(hf->name, hftmp->name) == 0)
280
						break;
281
				}
282
12
				if (hftmp == NULL)
283
12
					hash_insert(&hl, hf, base64);
284
			}
285
			break;
286
		case 'b':
287
			/* has already been parsed */
288
			break;
289
		case 'h':
290
			ofile = fopen(optarg, "w");
291
			if (ofile == NULL)
292
				err(1, "%s", optarg);
293
			break;
294
#if !defined(SHA2_ONLY)
295
		case 'C':
296
			selective_checklist = optarg;
297
			break;
298
		case 'c':
299
			cflag = 1;
300
			break;
301
#endif /* !defined(SHA2_ONLY) */
302
		case 'p':
303
			pflag = 1;
304
12
			break;
305
		case 'q':
306
6
			qflag = 1;
307
6
			break;
308
		case 'r':
309
			rflag = 1;
310
			break;
311
		case 's':
312
6
			input_string = optarg;
313
6
			break;
314
		case 't':
315
			tflag++;
316
			break;
317
		case 'x':
318
			xflag = 1;
319
42
			break;
320
		default:
321
			usage();
322
		}
323
	}
324
80
	argc -= optind;
325
80
	argv += optind;
326
327
80
	if (ofile == NULL)
328
80
		ofile = stdout;
329
330
80
	if (pledge("stdio rpath flock cpath wpath", NULL) == -1)
331
		err(1, "pledge");
332
333
	/* Most arguments are mutually exclusive */
334
80
	fl = pflag + (tflag ? 1 : 0) + xflag + cflag + (input_string != NULL);
335

228
	if (fl > 1 || (fl && argc && cflag == 0) || (rflag && qflag) ||
336
68
	    (selective_checklist != NULL && argc == 0))
337
		usage();
338
68
	if (selective_checklist || cflag) {
339
		if (TAILQ_FIRST(&hl) != TAILQ_LAST(&hl, hash_list))
340
			errx(1, "only a single algorithm may be specified "
341
			    "in -C or -c mode");
342
	}
343
344
	/* No algorithm specified, check the name we were called as. */
345
68
	if (TAILQ_EMPTY(&hl)) {
346
456
		for (hf = functions; hf->name != NULL; hf++) {
347
228
			if (strcasecmp(hf->name, __progname) == 0)
348
				break;
349
		}
350
56
		if (hf->name == NULL)
351
			hf = &functions[0];	/* default to cksum */
352
56
		hash_insert(&hl, hf, (hf->base64 == -1 ? 0 : bflag));
353
56
	}
354
355
68
	if (rflag || qflag) {
356
6
		const int new_style = rflag ? STYLE_CKSUM : STYLE_TERSE;
357
24
		TAILQ_FOREACH(hf, &hl, tailq) {
358
6
			hf->style = new_style;
359
		}
360
6
	}
361
362
#if !defined(SHA2_ONLY)
363
68
	if (tflag)
364
		digest_time(&hl, tflag);
365
68
	else if (xflag)
366
42
		digest_test(&hl);
367
26
	else if (input_string)
368
		digest_string(input_string, &hl);
369
26
	else if (selective_checklist) {
370
		int i;
371
372
		error = digest_filelist(selective_checklist, TAILQ_FIRST(&hl),
373
		    argc, argv);
374
		for (i = 0; i < argc; i++) {
375
			if (argv[i] != NULL) {
376
				warnx("%s does not exist in %s", argv[i],
377
				    selective_checklist);
378
				error++;
379
			}
380
		}
381
26
	} else if (cflag) {
382
		if (argc == 0)
383
			error = digest_filelist("-", TAILQ_FIRST(&hl), 0, NULL);
384
		else
385
			while (argc--)
386
				error += digest_filelist(*argv++,
387
				    TAILQ_FIRST(&hl), 0, NULL);
388
	} else
389
#endif /* !defined(SHA2_ONLY) */
390
26
	if (pflag || argc == 0)
391
6
		error = digest_file("-", &hl, pflag);
392
	else
393
108
		while (argc--)
394
34
			error += digest_file(*argv++, &hl, 0);
395
396
136
	return(error ? EXIT_FAILURE : EXIT_SUCCESS);
397
68
}
398
399
void
400
hash_insert(struct hash_list *hl, struct hash_function *hf, int base64)
401
{
402
	struct hash_function *hftmp;
403
404
136
	hftmp = malloc(sizeof(*hftmp));
405
68
	if (hftmp == NULL)
406
		err(1, NULL);
407
68
	*hftmp = *hf;
408
68
	hftmp->base64 = base64;
409
68
	TAILQ_INSERT_TAIL(hl, hftmp, tailq);
410
68
}
411
412
void
413
digest_end(const struct hash_function *hf, void *ctx, char *buf, size_t bsize,
414
    int base64)
415
{
416
	u_char *digest;
417
418
836
	if (base64 == 1) {
419
		if ((digest = malloc(hf->digestlen)) == NULL)
420
			err(1, NULL);
421
		hf->final(digest, ctx);
422
		if (b64_ntop(digest, hf->digestlen, buf, bsize) == -1)
423
			errx(1, "error encoding base64");
424
		freezero(digest, hf->digestlen);
425
	} else {
426
418
		hf->end(ctx, buf);
427
	}
428
418
}
429
430
#if !defined(SHA2_ONLY)
431
void
432
digest_string(char *string, struct hash_list *hl)
433
{
434
	struct hash_function *hf;
435
	char digest[MAX_DIGEST_LEN + 1];
436
	union ANY_CTX context;
437
438
	TAILQ_FOREACH(hf, hl, tailq) {
439
		hf->init(&context);
440
		hf->update(&context, string, strlen(string));
441
		digest_end(hf, &context, digest, sizeof(digest),
442
		    hf->base64);
443
		digest_printstr(hf, string, digest);
444
	}
445
}
446
#endif /* !defined(SHA2_ONLY) */
447
448
void
449
digest_print(const struct hash_function *hf, const char *what,
450
    const char *digest)
451
{
452

228
	switch (hf->style) {
453
	case STYLE_MD5:
454
64
		(void)fprintf(ofile, "%s (%s) = %s\n", hf->name, what, digest);
455
64
		break;
456
	case STYLE_CKSUM:
457
6
		(void)fprintf(ofile, "%s %s\n", digest, what);
458
6
		break;
459
	case STYLE_TERSE:
460
6
		(void)fprintf(ofile, "%s\n", digest);
461
6
		break;
462
	}
463
76
}
464
465
#if !defined(SHA2_ONLY)
466
void
467
digest_printstr(const struct hash_function *hf, const char *what,
468
    const char *digest)
469
{
470

1008
	switch (hf->style) {
471
	case STYLE_MD5:
472
288
		(void)fprintf(ofile, "%s (\"%s\") = %s\n", hf->name, what, digest);
473
288
		break;
474
	case STYLE_CKSUM:
475
48
		(void)fprintf(ofile, "%s %s\n", digest, what);
476
48
		break;
477
	case STYLE_TERSE:
478
		(void)fprintf(ofile, "%s\n", digest);
479
		break;
480
	}
481
336
}
482
#endif /* !defined(SHA2_ONLY) */
483
484
int
485
digest_file(const char *file, struct hash_list *hl, int echo)
486
{
487
	struct hash_function *hf;
488
	FILE *fp;
489
	size_t nread;
490
80
	u_char data[32 * 1024];
491
40
	char digest[MAX_DIGEST_LEN + 1];
492
493
40
	if (strcmp(file, "-") == 0)
494
6
		fp = stdin;
495
34
	else if ((fp = fopen(file, "r")) == NULL) {
496
		warn("cannot open %s", file);
497
		return(1);
498
	}
499
500
160
	TAILQ_FOREACH(hf, hl, tailq) {
501
40
		if ((hf->ctx = malloc(sizeof(union ANY_CTX))) == NULL)
502
			err(1, NULL);
503
40
		hf->init(hf->ctx);
504
	}
505
131328
	while ((nread = fread(data, 1UL, sizeof(data), fp)) != 0) {
506
65624
		if (echo) {
507
6
			(void)fwrite(data, nread, 1UL, stdout);
508
6
			if (fflush(stdout) != 0)
509
				err(1, "stdout: write error");
510
		}
511
262496
		TAILQ_FOREACH(hf, hl, tailq)
512
65624
			hf->update(hf->ctx, data, nread);
513
	}
514

80
	if (ferror(fp)) {
515
		warn("%s: read error", file);
516
		if (fp != stdin)
517
			fclose(fp);
518
		TAILQ_FOREACH(hf, hl, tailq) {
519
			free(hf->ctx);
520
			hf->ctx = NULL;
521
		}
522
		return(1);
523
	}
524
40
	if (fp != stdin)
525
34
		fclose(fp);
526
160
	TAILQ_FOREACH(hf, hl, tailq) {
527
40
		digest_end(hf, hf->ctx, digest, sizeof(digest), hf->base64);
528
40
		free(hf->ctx);
529
40
		hf->ctx = NULL;
530
40
		if (fp == stdin)
531
6
			fprintf(ofile, "%s\n", digest);
532
		else
533
34
			digest_print(hf, file, digest);
534
	}
535
40
	return(0);
536
40
}
537
538
#if !defined(SHA2_ONLY)
539
/*
540
 * Parse through the input file looking for valid lines.
541
 * If one is found, use this checksum and file as a reference and
542
 * generate a new checksum against the file on the filesystem.
543
 * Print out the result of each comparison.
544
 */
545
int
546
digest_filelist(const char *file, struct hash_function *defhash, int selcount,
547
    char **sel)
548
{
549
	int found, base64, error, cmp, i;
550
	size_t algorithm_max, algorithm_min;
551
	const char *algorithm;
552
	char *filename, *checksum, *buf, *p;
553
	char digest[MAX_DIGEST_LEN + 1];
554
	char *lbuf = NULL;
555
	FILE *listfp, *fp;
556
	size_t len, nread;
557
	int *sel_found = NULL;
558
	u_char data[32 * 1024];
559
	union ANY_CTX context;
560
	struct hash_function *hf;
561
562
	if (strcmp(file, "-") == 0) {
563
		listfp = stdin;
564
	} else if ((listfp = fopen(file, "r")) == NULL) {
565
		warn("cannot open %s", file);
566
		return(1);
567
	}
568
569
	if (sel != NULL) {
570
		sel_found = calloc((size_t)selcount, sizeof(*sel_found));
571
		if (sel_found == NULL)
572
			err(1, NULL);
573
	}
574
575
	algorithm_max = algorithm_min = strlen(functions[0].name);
576
	for (hf = &functions[1]; hf->name != NULL; hf++) {
577
		len = strlen(hf->name);
578
		algorithm_max = MAXIMUM(algorithm_max, len);
579
		algorithm_min = MINIMUM(algorithm_min, len);
580
	}
581
582
	error = found = 0;
583
	while ((buf = fgetln(listfp, &len))) {
584
		base64 = 0;
585
		if (buf[len - 1] == '\n')
586
			buf[len - 1] = '\0';
587
		else {
588
			if ((lbuf = malloc(len + 1)) == NULL)
589
				err(1, NULL);
590
591
			(void)memcpy(lbuf, buf, len);
592
			lbuf[len] = '\0';
593
			buf = lbuf;
594
		}
595
		while (isspace((unsigned char)*buf))
596
			buf++;
597
598
		/*
599
		 * Crack the line into an algorithm, filename, and checksum.
600
		 * Lines are of the form:
601
		 *  ALGORITHM (FILENAME) = CHECKSUM
602
		 *
603
		 * Fallback on GNU form:
604
		 *  CHECKSUM  FILENAME
605
		 */
606
		p = strchr(buf, ' ');
607
		if (p != NULL && *(p + 1) == '(') {
608
			/* BSD form */
609
			*p = '\0';
610
			algorithm = buf;
611
			len = strlen(algorithm);
612
			if (len > algorithm_max || len < algorithm_min)
613
				continue;
614
615
			filename = p + 2;
616
			p = strrchr(filename, ')');
617
			if (p == NULL || strncmp(p + 1, " = ", (size_t)3) != 0)
618
				continue;
619
			*p = '\0';
620
621
			checksum = p + 4;
622
			p = strpbrk(checksum, " \t\r");
623
			if (p != NULL)
624
				*p = '\0';
625
626
			/*
627
			 * Check that the algorithm is one we recognize.
628
			 */
629
			for (hf = functions; hf->name != NULL; hf++) {
630
				if (strcasecmp(algorithm, hf->name) == 0)
631
					break;
632
			}
633
			if (hf->name == NULL || *checksum == '\0')
634
				continue;
635
			/*
636
			 * Check the length to see if this could be
637
			 * a valid checksum.  If hex, it will be 2x the
638
			 * size of the binary data.  For base64, we have
639
			 * to check both with and without the '=' padding.
640
			 */
641
			len = strlen(checksum);
642
			if (len != hf->digestlen * 2) {
643
				size_t len2;
644
645
				if (checksum[len - 1] == '=') {
646
					/* use padding */
647
					len2 = 4 * ((hf->digestlen + 2) / 3);
648
				} else {
649
					/* no padding */
650
					len2 = (4 * hf->digestlen + 2) / 3;
651
				}
652
				if (len != len2)
653
					continue;
654
				base64 = 1;
655
			}
656
		} else {
657
			/* could be GNU form */
658
			if ((hf = defhash) == NULL)
659
				continue;
660
			algorithm = hf->name;
661
			checksum = buf;
662
			if ((p = strchr(checksum, ' ')) == NULL)
663
				continue;
664
			if (hf->style == STYLE_CKSUM) {
665
				if ((p = strchr(p + 1, ' ')) == NULL)
666
					continue;
667
			}
668
			*p++ = '\0';
669
			while (isspace((unsigned char)*p))
670
				p++;
671
			if (*p == '\0')
672
				continue;
673
			filename = p;
674
			p = strpbrk(filename, "\t\r");
675
			if (p != NULL)
676
				*p = '\0';
677
		}
678
		found = 1;
679
680
		/*
681
		 * If only a selection of files is wanted, proceed only
682
		 * if the filename matches one of those in the selection.
683
		 */
684
		if (sel != NULL) {
685
			for (i = 0; i < selcount; i++) {
686
				if (strcmp(sel[i], filename) == 0) {
687
					sel_found[i] = 1;
688
					break;
689
				}
690
			}
691
			if (i == selcount)
692
				continue;
693
		}
694
695
		if ((fp = fopen(filename, "r")) == NULL) {
696
			warn("cannot open %s", filename);
697
			(void)printf("(%s) %s: %s\n", algorithm, filename,
698
			    (errno == ENOENT ? "MISSING" : "FAILED"));
699
			error = 1;
700
			continue;
701
		}
702
703
		hf->init(&context);
704
		while ((nread = fread(data, 1UL, sizeof(data), fp)) > 0)
705
			hf->update(&context, data, nread);
706
		if (ferror(fp)) {
707
			warn("%s: read error", file);
708
			error = 1;
709
			fclose(fp);
710
			continue;
711
		}
712
		fclose(fp);
713
		digest_end(hf, &context, digest, sizeof(digest), base64);
714
715
		if (base64)
716
			cmp = strncmp(checksum, digest, len);
717
		else
718
			cmp = strcasecmp(checksum, digest);
719
		if (cmp == 0) {
720
			if (qflag == 0)
721
				(void)printf("(%s) %s: OK\n", algorithm,
722
				    filename);
723
		} else {
724
			(void)printf("(%s) %s: FAILED\n", algorithm, filename);
725
			error = 1;
726
		}
727
	}
728
	if (listfp != stdin)
729
		fclose(listfp);
730
	if (!found)
731
		warnx("%s: no properly formatted checksum lines found", file);
732
	free(lbuf);
733
	if (sel_found != NULL) {
734
		/*
735
		 * Mark found files by setting them to NULL so that we can
736
		 * detect files that are missing from the checklist later.
737
		 */
738
		for (i = 0; i < selcount; i++) {
739
			if (sel_found[i])
740
				sel[i] = NULL;
741
		}
742
		free(sel_found);
743
	}
744
	return(error || !found);
745
}
746
747
#define TEST_BLOCK_LEN 10000
748
#define TEST_BLOCK_COUNT 10000
749
750
void
751
digest_time(struct hash_list *hl, int times)
752
{
753
	struct hash_function *hf;
754
	struct rusage start, stop;
755
	struct timeval res;
756
	union ANY_CTX context;
757
	u_int i;
758
	u_char data[TEST_BLOCK_LEN];
759
	char digest[MAX_DIGEST_LEN + 1];
760
	double elapsed;
761
	int count = TEST_BLOCK_COUNT;
762
	while (--times > 0 && count < INT_MAX / 10)
763
		count *= 10;
764
765
	TAILQ_FOREACH(hf, hl, tailq) {
766
		(void)printf("%s time trial.  Processing %d %d-byte blocks...",
767
		    hf->name, count, TEST_BLOCK_LEN);
768
		fflush(stdout);
769
770
		/* Initialize data based on block number. */
771
		for (i = 0; i < TEST_BLOCK_LEN; i++)
772
			data[i] = (u_char)(i & 0xff);
773
774
		getrusage(RUSAGE_SELF, &start);
775
		hf->init(&context);
776
		for (i = 0; i < count; i++)
777
			hf->update(&context, data, (size_t)TEST_BLOCK_LEN);
778
		digest_end(hf, &context, digest, sizeof(digest), hf->base64);
779
		getrusage(RUSAGE_SELF, &stop);
780
		timersub(&stop.ru_utime, &start.ru_utime, &res);
781
		elapsed = res.tv_sec + res.tv_usec / 1000000.0;
782
783
		(void)printf("\nDigest = %s\n", digest);
784
		(void)printf("Time   = %f seconds\n", elapsed);
785
		(void)printf("Speed  = %f bytes/second\n",
786
		    (double)TEST_BLOCK_LEN * count / elapsed);
787
	}
788
}
789
790
void
791
digest_test(struct hash_list *hl)
792
{
793
	struct hash_function *hf;
794
84
	union ANY_CTX context;
795
	int i;
796
42
	char digest[MAX_DIGEST_LEN + 1];
797
42
	unsigned char buf[1000];
798
42
	unsigned const char *test_strings[] = {
799
		"",
800
		"a",
801
		"abc",
802
		"message digest",
803
		"abcdefghijklmnopqrstuvwxyz",
804
		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
805
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
806
		    "0123456789",
807
		"12345678901234567890123456789012345678901234567890123456789"
808
		    "012345678901234567890",
809
	};
810
811
168
	TAILQ_FOREACH(hf, hl, tailq) {
812
42
		(void)printf("%s test suite:\n", hf->name);
813
814
756
		for (i = 0; i < 8; i++) {
815
336
			hf->init(&context);
816
672
			hf->update(&context, test_strings[i],
817
336
			    strlen(test_strings[i]));
818
672
			digest_end(hf, &context, digest, sizeof(digest),
819
336
			    hf->base64);
820
336
			digest_printstr(hf, test_strings[i], digest);
821
		}
822
823
		/* Now simulate a string of a million 'a' characters. */
824
42
		memset(buf, 'a', sizeof(buf));
825
42
		hf->init(&context);
826
84084
		for (i = 0; i < 1000; i++)
827
42000
			hf->update(&context, buf, sizeof(buf));
828
42
		digest_end(hf, &context, digest, sizeof(digest), hf->base64);
829
42
		digest_print(hf, "one million 'a' characters",
830
		    digest);
831
	}
832
42
}
833
#endif /* !defined(SHA2_ONLY) */
834
835
void
836
usage(void)
837
{
838
#if !defined(SHA2_ONLY)
839
24
	if (strcmp(__progname, "cksum") == 0)
840
		fprintf(stderr, "usage: %s [-bcpqrtx] [-a algorithms] [-C checklist] "
841
		    "[-h hashfile]\n"
842
		    "	[-s string] [file ...]\n",
843
		    __progname);
844
	else
845
#endif /* !defined(SHA2_ONLY) */
846
12
		fprintf(stderr, "usage:"
847
		    "\t%s [-bcpqrtx] [-C checklist] [-h hashfile] [-s string] "
848
		    "[file ...]\n",
849
		    __progname);
850
851
	exit(EXIT_FAILURE);
852
}