Bug Summary

File:src/bin/md5/md5.c
Warning:line 396, column 9
Potential leak of memory pointed to by 'hl.tqh_first'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name md5.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/bin/md5/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/bin/md5 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/bin/md5/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/bin/md5/md5.c
1/* $OpenBSD: md5.c,v 1.97 2020/10/19 18:15:18 millert Exp $ */
2
3/*
4 * Copyright (c) 2001,2003,2005-2007,2010,2013,2014
5 * Todd C. Miller <millert@openbsd.org>
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(*__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_MD50 0
48#define STYLE_CKSUM1 1
49#define STYLE_TERSE2 2
50
51#define MAX_DIGEST_LEN128 128
52
53#define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b))
54#define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b))
55
56union 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
66struct 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)struct { struct hash_function *tqe_next; struct hash_function
**tqe_prev; }
tailq;
77} functions[] = {
78#if !defined(SHA2_ONLY)
79 {
80 "CKSUM",
81 CKSUM_DIGEST_LENGTH4,
82 STYLE_CKSUM1,
83 -1,
84 NULL((void *)0),
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_LENGTH16,
93 STYLE_MD50,
94 0,
95 NULL((void *)0),
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_LENGTH20,
104 STYLE_MD50,
105 0,
106 NULL((void *)0),
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_LENGTH20,
115 STYLE_MD50,
116 0,
117 NULL((void *)0),
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_LENGTH28,
126 STYLE_MD50,
127 0,
128 NULL((void *)0),
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_LENGTH32,
138 STYLE_MD50,
139 0,
140 NULL((void *)0),
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_LENGTH48,
150 STYLE_MD50,
151 0,
152 NULL((void *)0),
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_LENGTH32,
161 STYLE_MD50,
162 0,
163 NULL((void *)0),
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_LENGTH64,
173 STYLE_MD50,
174 0,
175 NULL((void *)0),
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((void *)0),
183 }
184};
185
186TAILQ_HEAD(hash_list, hash_function)struct hash_list { struct hash_function *tqh_first; struct hash_function
**tqh_last; }
;
187
188void digest_end(const struct hash_function *, void *, char *, size_t, int);
189int digest_file(const char *, struct hash_list *, int);
190void digest_print(const struct hash_function *, const char *, const char *);
191#if !defined(SHA2_ONLY)
192int digest_filelist(const char *, struct hash_function *, int, char **);
193void digest_printstr(const struct hash_function *, const char *, const char *);
194void digest_string(char *, struct hash_list *);
195void digest_test(struct hash_list *);
196void digest_time(struct hash_list *, int);
197#endif /* !defined(SHA2_ONLY) */
198void hash_insert(struct hash_list *, struct hash_function *, int);
199void usage(void) __attribute__((__noreturn__));
200
201extern char *__progname;
202int qflag = 0;
203FILE *ofile = NULL((void *)0);
204
205int
206main(int argc, char **argv)
207{
208 struct hash_function *hf, *hftmp;
209 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 if (pledge("stdio rpath wpath cpath", NULL((void *)0)) == -1)
1
Assuming the condition is false
2
Taking false branch
217 err(1, "pledge");
218
219 TAILQ_INIT(&hl)do { (&hl)->tqh_first = ((void *)0); (&hl)->tqh_last
= &(&hl)->tqh_first; } while (0)
;
3
Loop condition is false. Exiting loop
220 input_string = NULL((void *)0);
221 selective_checklist = NULL((void *)0);
222 error = bflag = cflag = pflag = qflag = rflag = tflag = xflag = 0;
223
224#if !defined(SHA2_ONLY)
225 if (strcmp(__progname, "cksum") == 0)
4
Assuming the condition is false
5
Taking false branch
226 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 while ((fl = getopt(argc, argv, optstr)) != -1) {
6
Assuming the condition is false
7
Loop condition is false. Execution continues on line 241
233 switch (fl) {
234 case 'b':
235 bflag = 1;
236 break;
237 case '?':
238 usage();
239 }
240 }
241 optind = 1;
242 optreset = 1;
243 while ((fl = getopt(argc, argv, optstr)) != -1) {
8
Assuming the condition is true
9
Loop condition is true. Entering loop body
36
Assuming the condition is false
37
Loop condition is false. Execution continues on line 324
244 switch (fl) {
10
Control jumps to 'case 97:' at line 245
245 case 'a':
246 while ((cp = strsep(&optarg, " \t,")) != NULL((void *)0)) {
11
Assuming the condition is true
12
Loop condition is true. Entering loop body
33
Assuming the condition is false
34
Loop condition is false. Execution continues on line 285
247 if (*cp == '\0')
13
Assuming the condition is false
14
Taking false branch
248 continue;
249 base64 = -1;
250 for (hf = functions; hf->name != NULL((void *)0); hf++) {
15
Assuming field 'name' is not equal to NULL
16
Loop condition is true. Entering loop body
251 len = strlen(hf->name);
252 if (strncasecmp(cp, hf->name, len) != 0)
17
Assuming the condition is false
18
Taking false branch
253 continue;
254 if (cp[len] == '\0') {
19
Assuming the condition is true
20
Taking true branch
255 if (hf->base64 != -1)
21
Assuming the condition is true
22
Taking true branch
256 base64 = bflag;
257 break; /* exact match */
23
Execution continues on line 266
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 if (hf->name
23.1
Field 'name' is not equal to NULL
== NULL((void *)0)) {
24
Taking false branch
267 warnx("unknown algorithm \"%s\"", cp);
268 usage();
269 }
270 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 TAILQ_FOREACH(hftmp, &hl, tailq)for((hftmp) = ((&hl)->tqh_first); (hftmp) != ((void *)
0); (hftmp) = ((hftmp)->tailq.tqe_next))
{
25
Loop condition is false. Execution continues on line 282
278 if (hftmp->base64 == base64 &&
279 strcmp(hf->name, hftmp->name) == 0)
280 break;
281 }
282 if (hftmp
25.1
'hftmp' is equal to NULL
== NULL((void *)0))
26
Taking true branch
283 hash_insert(&hl, hf, base64);
27
Calling 'hash_insert'
32
Returned allocated memory
284 }
285 break;
35
Execution continues on line 243
286 case 'b':
287 /* has already been parsed */
288 break;
289 case 'h':
290 ofile = fopen(optarg, "w");
291 if (ofile == NULL((void *)0))
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 break;
305 case 'q':
306 qflag = 1;
307 break;
308 case 'r':
309 rflag = 1;
310 break;
311 case 's':
312 input_string = optarg;
313 break;
314 case 't':
315 tflag++;
316 break;
317 case 'x':
318 xflag = 1;
319 break;
320 default:
321 usage();
322 }
323 }
324 argc -= optind;
325 argv += optind;
326
327 if (ofile == NULL((void *)0))
38
Assuming 'ofile' is not equal to NULL
39
Taking false branch
328 ofile = stdout(&__sF[1]);
329
330 if (pledge("stdio rpath", NULL((void *)0)) == -1)
40
Assuming the condition is false
41
Taking false branch
331 err(1, "pledge");
332
333 /* Most arguments are mutually exclusive */
334 fl = pflag + (tflag
41.1
'tflag' is 0
? 1 : 0) + xflag + cflag + (input_string != NULL((void *)0));
42
'?' condition is false
335 if (fl
42.1
'fl' is <= 1
> 1 || (fl
42.2
'fl' is 0
&& argc && cflag == 0) || (rflag
42.3
'rflag' is 0
&& qflag) ||
336 (selective_checklist
42.4
'selective_checklist' is equal to NULL
!= NULL((void *)0) && argc == 0))
337 usage();
338 if (selective_checklist
42.5
'selective_checklist' is null
|| cflag
42.6
'cflag' is 0
) {
43
Taking false branch
339 if (TAILQ_FIRST(&hl)((&hl)->tqh_first) != TAILQ_LAST(&hl, hash_list)(*(((struct hash_list *)((&hl)->tqh_last))->tqh_last
))
)
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 if (TAILQ_EMPTY(&hl)(((&hl)->tqh_first) == ((void *)0))) {
44
Taking false branch
346 for (hf = functions; hf->name != NULL((void *)0); hf++) {
347 if (strcasecmp(hf->name, __progname) == 0)
348 break;
349 }
350 if (hf->name == NULL((void *)0))
351 hf = &functions[0]; /* default to cksum */
352 hash_insert(&hl, hf, (hf->base64 == -1 ? 0 : bflag));
353 }
354
355 if (rflag
44.1
'rflag' is 0
|| qflag
44.2
'qflag' is 0
) {
45
Taking false branch
356 const int new_style = rflag ? STYLE_CKSUM1 : STYLE_TERSE2;
357 TAILQ_FOREACH(hf, &hl, tailq)for((hf) = ((&hl)->tqh_first); (hf) != ((void *)0); (hf
) = ((hf)->tailq.tqe_next))
{
358 hf->style = new_style;
359 }
360 }
361
362#if !defined(SHA2_ONLY)
363 if (tflag
45.1
'tflag' is 0
)
46
Taking false branch
364 digest_time(&hl, tflag);
365 else if (xflag
46.1
'xflag' is 0
)
47
Taking false branch
366 digest_test(&hl);
367 else if (input_string
47.1
'input_string' is null
)
48
Taking false branch
368 digest_string(input_string, &hl);
369 else if (selective_checklist
48.1
'selective_checklist' is null
) {
49
Taking false branch
370 int i;
371
372 error = digest_filelist(selective_checklist, TAILQ_FIRST(&hl)((&hl)->tqh_first),
373 argc, argv);
374 for (i = 0; i < argc; i++) {
375 if (argv[i] != NULL((void *)0)) {
376 warnx("%s does not exist in %s", argv[i],
377 selective_checklist);
378 error++;
379 }
380 }
381 } else if (cflag
49.1
'cflag' is 0
) {
50
Taking false branch
382 if (argc == 0)
383 error = digest_filelist("-", TAILQ_FIRST(&hl)((&hl)->tqh_first), 0, NULL((void *)0));
384 else
385 while (argc--)
386 error += digest_filelist(*argv++,
387 TAILQ_FIRST(&hl)((&hl)->tqh_first), 0, NULL((void *)0));
388 } else
389#endif /* !defined(SHA2_ONLY) */
390 if (pflag
50.1
'pflag' is 0
|| argc == 0)
51
Assuming 'argc' is not equal to 0
52
Taking false branch
391 error = digest_file("-", &hl, pflag);
392 else
393 while (argc--)
53
Loop condition is false. Execution continues on line 396
394 error += digest_file(*argv++, &hl, 0);
395
396 return(error ? EXIT_FAILURE1 : EXIT_SUCCESS0);
54
Potential leak of memory pointed to by 'hl.tqh_first'
397}
398
399void
400hash_insert(struct hash_list *hl, struct hash_function *hf, int base64)
401{
402 struct hash_function *hftmp;
403
404 hftmp = malloc(sizeof(*hftmp));
28
Memory is allocated
405 if (hftmp == NULL((void *)0))
29
Assuming 'hftmp' is not equal to NULL
30
Taking false branch
406 err(1, NULL((void *)0));
407 *hftmp = *hf;
408 hftmp->base64 = base64;
409 TAILQ_INSERT_TAIL(hl, hftmp, tailq)do { (hftmp)->tailq.tqe_next = ((void *)0); (hftmp)->tailq
.tqe_prev = (hl)->tqh_last; *(hl)->tqh_last = (hftmp); (
hl)->tqh_last = &(hftmp)->tailq.tqe_next; } while (
0)
;
31
Loop condition is false. Exiting loop
410}
411
412void
413digest_end(const struct hash_function *hf, void *ctx, char *buf, size_t bsize,
414 int base64)
415{
416 u_char *digest;
417
418 if (base64 == 1) {
419 if ((digest = malloc(hf->digestlen)) == NULL((void *)0))
420 err(1, NULL((void *)0));
421 hf->final(digest, ctx);
422 if (b64_ntop__b64_ntop(digest, hf->digestlen, buf, bsize) == -1)
423 errx(1, "error encoding base64");
424 free(digest);
425 } else {
426 hf->end(ctx, buf);
427 }
428}
429
430#if !defined(SHA2_ONLY)
431void
432digest_string(char *string, struct hash_list *hl)
433{
434 struct hash_function *hf;
435 char digest[MAX_DIGEST_LEN128 + 1];
436 union ANY_CTX context;
437
438 TAILQ_FOREACH(hf, hl, tailq)for((hf) = ((hl)->tqh_first); (hf) != ((void *)0); (hf) = (
(hf)->tailq.tqe_next))
{
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
448void
449digest_print(const struct hash_function *hf, const char *what,
450 const char *digest)
451{
452 switch (hf->style) {
453 case STYLE_MD50:
454 (void)fprintf(ofile, "%s (%s) = %s\n", hf->name, what, digest);
455 break;
456 case STYLE_CKSUM1:
457 (void)fprintf(ofile, "%s %s\n", digest, what);
458 break;
459 case STYLE_TERSE2:
460 (void)fprintf(ofile, "%s\n", digest);
461 break;
462 }
463}
464
465#if !defined(SHA2_ONLY)
466void
467digest_printstr(const struct hash_function *hf, const char *what,
468 const char *digest)
469{
470 switch (hf->style) {
471 case STYLE_MD50:
472 (void)fprintf(ofile, "%s (\"%s\") = %s\n", hf->name, what, digest);
473 break;
474 case STYLE_CKSUM1:
475 (void)fprintf(ofile, "%s %s\n", digest, what);
476 break;
477 case STYLE_TERSE2:
478 (void)fprintf(ofile, "%s\n", digest);
479 break;
480 }
481}
482#endif /* !defined(SHA2_ONLY) */
483
484int
485digest_file(const char *file, struct hash_list *hl, int echo)
486{
487 struct hash_function *hf;
488 FILE *fp;
489 size_t nread;
490 u_char data[32 * 1024];
491 char digest[MAX_DIGEST_LEN128 + 1];
492
493 if (strcmp(file, "-") == 0)
494 fp = stdin(&__sF[0]);
495 else if ((fp = fopen(file, "r")) == NULL((void *)0)) {
496 warn("cannot open %s", file);
497 return(1);
498 }
499
500 TAILQ_FOREACH(hf, hl, tailq)for((hf) = ((hl)->tqh_first); (hf) != ((void *)0); (hf) = (
(hf)->tailq.tqe_next))
{
501 if ((hf->ctx = malloc(sizeof(union ANY_CTX))) == NULL((void *)0))
502 err(1, NULL((void *)0));
503 hf->init(hf->ctx);
504 }
505 while ((nread = fread(data, 1UL, sizeof(data), fp)) != 0) {
506 if (echo) {
507 (void)fwrite(data, nread, 1UL, stdout(&__sF[1]));
508 (void)fflush(stdout(&__sF[1]));
509 if (ferror(stdout)(!__isthreaded ? ((((&__sF[1]))->_flags & 0x0040) !=
0) : (ferror)((&__sF[1])))
)
510 err(1, "stdout: write error");
511 }
512 TAILQ_FOREACH(hf, hl, tailq)for((hf) = ((hl)->tqh_first); (hf) != ((void *)0); (hf) = (
(hf)->tailq.tqe_next))
513 hf->update(hf->ctx, data, nread);
514 }
515 if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
) {
516 warn("%s: read error", file);
517 if (fp != stdin(&__sF[0]))
518 fclose(fp);
519 TAILQ_FOREACH(hf, hl, tailq)for((hf) = ((hl)->tqh_first); (hf) != ((void *)0); (hf) = (
(hf)->tailq.tqe_next))
{
520 free(hf->ctx);
521 hf->ctx = NULL((void *)0);
522 }
523 return(1);
524 }
525 if (fp != stdin(&__sF[0]))
526 fclose(fp);
527 TAILQ_FOREACH(hf, hl, tailq)for((hf) = ((hl)->tqh_first); (hf) != ((void *)0); (hf) = (
(hf)->tailq.tqe_next))
{
528 digest_end(hf, hf->ctx, digest, sizeof(digest), hf->base64);
529 free(hf->ctx);
530 hf->ctx = NULL((void *)0);
531 if (fp == stdin(&__sF[0]))
532 fprintf(ofile, "%s\n", digest);
533 else
534 digest_print(hf, file, digest);
535 }
536 return(0);
537}
538
539#if !defined(SHA2_ONLY)
540/*
541 * Parse through the input file looking for valid lines.
542 * If one is found, use this checksum and file as a reference and
543 * generate a new checksum against the file on the filesystem.
544 * Print out the result of each comparison.
545 */
546int
547digest_filelist(const char *file, struct hash_function *defhash, int selcount,
548 char **sel)
549{
550 int found, base64, error, cmp, i;
551 size_t algorithm_max, algorithm_min;
552 const char *algorithm;
553 char *filename, *checksum, *line, *p, *tmpline;
554 char digest[MAX_DIGEST_LEN128 + 1];
555 ssize_t linelen;
556 FILE *listfp, *fp;
557 size_t len, linesize, nread;
558 int *sel_found = NULL((void *)0);
559 u_char data[32 * 1024];
560 union ANY_CTX context;
561 struct hash_function *hf;
562
563 if (strcmp(file, "-") == 0) {
564 listfp = stdin(&__sF[0]);
565 } else if ((listfp = fopen(file, "r")) == NULL((void *)0)) {
566 warn("cannot open %s", file);
567 return(1);
568 }
569
570 if (sel != NULL((void *)0)) {
571 sel_found = calloc((size_t)selcount, sizeof(*sel_found));
572 if (sel_found == NULL((void *)0))
573 err(1, NULL((void *)0));
574 }
575
576 algorithm_max = algorithm_min = strlen(functions[0].name);
577 for (hf = &functions[1]; hf->name != NULL((void *)0); hf++) {
578 len = strlen(hf->name);
579 algorithm_max = MAXIMUM(algorithm_max, len)(((algorithm_max) > (len)) ? (algorithm_max) : (len));
580 algorithm_min = MINIMUM(algorithm_min, len)(((algorithm_min) < (len)) ? (algorithm_min) : (len));
581 }
582
583 error = found = 0;
584 line = NULL((void *)0);
585 linesize = 0;
586 while ((linelen = getline(&line, &linesize, listfp)) != -1) {
587 tmpline = line;
588 base64 = 0;
589 if (line[linelen - 1] == '\n')
590 line[linelen - 1] = '\0';
591 while (isspace((unsigned char)*tmpline))
592 tmpline++;
593
594 /*
595 * Crack the line into an algorithm, filename, and checksum.
596 * Lines are of the form:
597 * ALGORITHM (FILENAME) = CHECKSUM
598 *
599 * Fallback on GNU form:
600 * CHECKSUM FILENAME
601 */
602 p = strchr(tmpline, ' ');
603 if (p != NULL((void *)0) && *(p + 1) == '(') {
604 /* BSD form */
605 *p = '\0';
606 algorithm = tmpline;
607 len = strlen(algorithm);
608 if (len > algorithm_max || len < algorithm_min)
609 continue;
610
611 filename = p + 2;
612 p = strrchr(filename, ')');
613 if (p == NULL((void *)0) || strncmp(p + 1, " = ", (size_t)3) != 0)
614 continue;
615 *p = '\0';
616
617 checksum = p + 4;
618 p = strpbrk(checksum, " \t\r");
619 if (p != NULL((void *)0))
620 *p = '\0';
621
622 /*
623 * Check that the algorithm is one we recognize.
624 */
625 for (hf = functions; hf->name != NULL((void *)0); hf++) {
626 if (strcasecmp(algorithm, hf->name) == 0)
627 break;
628 }
629 if (hf->name == NULL((void *)0) || *checksum == '\0')
630 continue;
631 /*
632 * Check the length to see if this could be
633 * a valid checksum. If hex, it will be 2x the
634 * size of the binary data. For base64, we have
635 * to check both with and without the '=' padding.
636 */
637 len = strlen(checksum);
638 if (len != hf->digestlen * 2) {
639 size_t len2;
640
641 if (checksum[len - 1] == '=') {
642 /* use padding */
643 len2 = 4 * ((hf->digestlen + 2) / 3);
644 } else {
645 /* no padding */
646 len2 = (4 * hf->digestlen + 2) / 3;
647 }
648 if (len != len2)
649 continue;
650 base64 = 1;
651 }
652 } else {
653 /* could be GNU form */
654 if ((hf = defhash) == NULL((void *)0))
655 continue;
656 algorithm = hf->name;
657 checksum = tmpline;
658 if ((p = strchr(checksum, ' ')) == NULL((void *)0))
659 continue;
660 if (hf->style == STYLE_CKSUM1) {
661 if ((p = strchr(p + 1, ' ')) == NULL((void *)0))
662 continue;
663 }
664 *p++ = '\0';
665 while (isspace((unsigned char)*p))
666 p++;
667 if (*p == '\0')
668 continue;
669 filename = p;
670 p = strpbrk(filename, "\t\r");
671 if (p != NULL((void *)0))
672 *p = '\0';
673 }
674 found = 1;
675
676 /*
677 * If only a selection of files is wanted, proceed only
678 * if the filename matches one of those in the selection.
679 */
680 if (sel != NULL((void *)0)) {
681 for (i = 0; i < selcount; i++) {
682 if (strcmp(sel[i], filename) == 0) {
683 sel_found[i] = 1;
684 break;
685 }
686 }
687 if (i == selcount)
688 continue;
689 }
690
691 if ((fp = fopen(filename, "r")) == NULL((void *)0)) {
692 warn("cannot open %s", filename);
693 (void)printf("(%s) %s: %s\n", algorithm, filename,
694 (errno(*__errno()) == ENOENT2 ? "MISSING" : "FAILED"));
695 error = 1;
696 continue;
697 }
698
699 hf->init(&context);
700 while ((nread = fread(data, 1UL, sizeof(data), fp)) > 0)
701 hf->update(&context, data, nread);
702 if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
) {
703 warn("%s: read error", file);
704 error = 1;
705 fclose(fp);
706 continue;
707 }
708 fclose(fp);
709 digest_end(hf, &context, digest, sizeof(digest), base64);
710
711 if (base64)
712 cmp = strncmp(checksum, digest, len);
713 else
714 cmp = strcasecmp(checksum, digest);
715 if (cmp == 0) {
716 if (qflag == 0)
717 (void)printf("(%s) %s: OK\n", algorithm,
718 filename);
719 } else {
720 (void)printf("(%s) %s: FAILED\n", algorithm, filename);
721 error = 1;
722 }
723 }
724 free(line);
725 if (ferror(listfp)(!__isthreaded ? (((listfp)->_flags & 0x0040) != 0) : (
ferror)(listfp))
) {
726 warn("%s: getline", file);
727 error = 1;
728 }
729 if (listfp != stdin(&__sF[0]))
730 fclose(listfp);
731 if (!found)
732 warnx("%s: no properly formatted checksum lines found", file);
733 if (sel_found != NULL((void *)0)) {
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((void *)0);
741 }
742 free(sel_found);
743 }
744 return(error || !found);
745}
746
747#define TEST_BLOCK_LEN10000 10000
748#define TEST_BLOCK_COUNT10000 10000
749
750void
751digest_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_LEN10000];
759 char digest[MAX_DIGEST_LEN128 + 1];
760 double elapsed;
761 int count = TEST_BLOCK_COUNT10000;
762 while (--times > 0 && count < INT_MAX2147483647 / 10)
763 count *= 10;
764
765 TAILQ_FOREACH(hf, hl, tailq)for((hf) = ((hl)->tqh_first); (hf) != ((void *)0); (hf) = (
(hf)->tailq.tqe_next))
{
766 (void)printf("%s time trial. Processing %d %d-byte blocks...",
767 hf->name, count, TEST_BLOCK_LEN10000);
768 fflush(stdout(&__sF[1]));
769
770 /* Initialize data based on block number. */
771 for (i = 0; i < TEST_BLOCK_LEN10000; i++)
772 data[i] = (u_char)(i & 0xff);
773
774 getrusage(RUSAGE_SELF0, &start);
775 hf->init(&context);
776 for (i = 0; i < count; i++)
777 hf->update(&context, data, (size_t)TEST_BLOCK_LEN10000);
778 digest_end(hf, &context, digest, sizeof(digest), hf->base64);
779 getrusage(RUSAGE_SELF0, &stop);
780 timersub(&stop.ru_utime, &start.ru_utime, &res)do { (&res)->tv_sec = (&stop.ru_utime)->tv_sec -
(&start.ru_utime)->tv_sec; (&res)->tv_usec = (
&stop.ru_utime)->tv_usec - (&start.ru_utime)->tv_usec
; if ((&res)->tv_usec < 0) { (&res)->tv_sec--
; (&res)->tv_usec += 1000000; } } while (0)
;
781 elapsed = (double)res.tv_sec + (double)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_LEN10000 * count / elapsed);
787 }
788}
789
790void
791digest_test(struct hash_list *hl)
792{
793 struct hash_function *hf;
794 union ANY_CTX context;
795 int i;
796 char digest[MAX_DIGEST_LEN128 + 1];
797 unsigned char buf[1000];
798 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 TAILQ_FOREACH(hf, hl, tailq)for((hf) = ((hl)->tqh_first); (hf) != ((void *)0); (hf) = (
(hf)->tailq.tqe_next))
{
812 (void)printf("%s test suite:\n", hf->name);
813
814 for (i = 0; i < 8; i++) {
815 hf->init(&context);
816 hf->update(&context, test_strings[i],
817 strlen(test_strings[i]));
818 digest_end(hf, &context, digest, sizeof(digest),
819 hf->base64);
820 digest_printstr(hf, test_strings[i], digest);
821 }
822
823 /* Now simulate a string of a million 'a' characters. */
824 memset(buf, 'a', sizeof(buf));
825 hf->init(&context);
826 for (i = 0; i < 1000; i++)
827 hf->update(&context, buf, sizeof(buf));
828 digest_end(hf, &context, digest, sizeof(digest), hf->base64);
829 digest_print(hf, "one million 'a' characters",
830 digest);
831 }
832}
833#endif /* !defined(SHA2_ONLY) */
834
835void
836usage(void)
837{
838#if !defined(SHA2_ONLY)
839 if (strcmp(__progname, "cksum") == 0)
840 fprintf(stderr(&__sF[2]), "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 fprintf(stderr(&__sF[2]), "usage:"
847 "\t%s [-bcpqrtx] [-C checklist] [-h hashfile] [-s string] "
848 "[file ...]\n",
849 __progname);
850
851 exit(EXIT_FAILURE1);
852}