1 /* $NetBSD: cksum.c,v 1.44 2009/01/02 09:42:51 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * James W. Williams of NASA Goddard Space Flight Center. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /*- 36 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. 37 * 38 * This code is derived from software contributed to Berkeley by 39 * James W. Williams of NASA Goddard Space Flight Center. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the University of 52 * California, Berkeley and its contributors. 53 * 4. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 */ 69 70 #if HAVE_NBTOOL_CONFIG_H 71 #include "nbtool_config.h" 72 #endif 73 74 #include <sys/cdefs.h> 75 #if defined(__COPYRIGHT) && !defined(lint) 76 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\ 77 The Regents of the University of California. All rights reserved."); 78 #endif /* not lint */ 79 80 #if defined(__RCSID) && !defined(lint) 81 #if 0 82 static char sccsid[] = "@(#)cksum.c 8.2 (Berkeley) 4/28/95"; 83 #endif 84 __RCSID("$NetBSD: cksum.c,v 1.44 2009/01/02 09:42:51 lukem Exp $"); 85 #endif /* not lint */ 86 87 #include <sys/types.h> 88 89 #include <ctype.h> 90 #include <err.h> 91 #include <errno.h> 92 #include <fcntl.h> 93 #include <locale.h> 94 #include <md2.h> 95 #include <md4.h> 96 #include <md5.h> 97 #include <rmd160.h> 98 #include <sha1.h> 99 #include <sha2.h> 100 #include <stdio.h> 101 #include <stdlib.h> 102 #include <string.h> 103 #include <unistd.h> 104 105 #include "extern.h" 106 107 typedef char *(*_filefunc)(const char *, char *); 108 109 const struct hash { 110 const char *progname; 111 const char *hashname; 112 void (*stringfunc)(const char *); 113 void (*timetrialfunc)(void); 114 void (*testsuitefunc)(void); 115 void (*filterfunc)(int); 116 char *(*filefunc)(const char *, char *); 117 } hashes[] = { 118 { "md2", "MD2", 119 MD2String, MD2TimeTrial, MD2TestSuite, 120 MD2Filter, MD2File }, 121 { "md4", "MD4", 122 MD4String, MD4TimeTrial, MD4TestSuite, 123 MD4Filter, MD4File }, 124 { "md5", "MD5", 125 MD5String, MD5TimeTrial, MD5TestSuite, 126 MD5Filter, MD5File }, 127 { "rmd160", "RMD160", 128 RMD160String, RMD160TimeTrial, RMD160TestSuite, 129 RMD160Filter, (_filefunc) RMD160File }, 130 { "sha1", "SHA1", 131 SHA1String, SHA1TimeTrial, SHA1TestSuite, 132 SHA1Filter, (_filefunc) SHA1File }, 133 { "sha256", "SHA256", 134 SHA256_String, SHA256_TimeTrial, SHA256_TestSuite, 135 SHA256_Filter, (_filefunc) SHA256_File }, 136 { "sha384", "SHA384", 137 SHA384_String, SHA384_TimeTrial, SHA384_TestSuite, 138 SHA384_Filter, (_filefunc) SHA384_File }, 139 { "sha512", "SHA512", 140 SHA512_String, SHA512_TimeTrial, SHA512_TestSuite, 141 SHA512_Filter, (_filefunc) SHA512_File }, 142 { .progname = NULL, }, 143 }; 144 145 int hash_digest_file(char *, const struct hash *, int); 146 void requirehash(const char *); 147 void usage(void); 148 149 int 150 main(int argc, char **argv) 151 { 152 int ch, fd, rval, dosum, pflag, nohashstdin; 153 u_int32_t val; 154 off_t len; 155 char *fn; 156 const char *progname; 157 int (*cfncn) (int, u_int32_t *, off_t *); 158 void (*pfncn) (char *, u_int32_t, off_t); 159 const struct hash *hash; 160 int normal, i, check_warn, do_check; 161 162 cfncn = NULL; 163 pfncn = NULL; 164 dosum = pflag = nohashstdin = 0; 165 normal = 0; 166 check_warn = 0; 167 do_check = 0; 168 169 setlocale(LC_ALL, ""); 170 171 progname = getprogname(); 172 173 for (hash = hashes; hash->hashname != NULL; hash++) 174 if (strcmp(progname, hash->progname) == 0) 175 break; 176 177 if (hash->hashname == NULL) { 178 hash = NULL; 179 180 if (!strcmp(progname, "sum")) { 181 dosum = 1; 182 cfncn = csum1; 183 pfncn = psum1; 184 } else { 185 cfncn = crc; 186 pfncn = pcrc; 187 } 188 } 189 190 while ((ch = getopt(argc, argv, "a:cno:ps:twx")) != -1) 191 switch(ch) { 192 case 'a': 193 if (hash) { 194 warnx("illegal use of -a option\n"); 195 usage(); 196 } 197 i = 0; 198 while (hashes[i].hashname != NULL) { 199 if (!strcasecmp(hashes[i].hashname, optarg)) { 200 hash = &hashes[i]; 201 break; 202 } 203 i++; 204 } 205 if (hash == NULL) { 206 if (!strcasecmp(optarg, "old1")) { 207 cfncn = csum1; 208 pfncn = psum1; 209 } else if (!strcasecmp(optarg, "old2")) { 210 cfncn = csum2; 211 pfncn = psum2; 212 } else if (!strcasecmp(optarg, "crc")) { 213 cfncn = crc; 214 pfncn = pcrc; 215 } else { 216 warnx("illegal argument to -a option"); 217 usage(); 218 } 219 } 220 break; 221 case 'c': 222 do_check = 1; 223 break; 224 case 'n': 225 normal = 1; 226 break; 227 case 'o': 228 if (hash) { 229 warnx("%s mutually exclusive with sum", 230 hash->hashname); 231 usage(); 232 } 233 if (!strcmp(optarg, "1")) { 234 cfncn = csum1; 235 pfncn = psum1; 236 } else if (!strcmp(optarg, "2")) { 237 cfncn = csum2; 238 pfncn = psum2; 239 } else { 240 warnx("illegal argument to -o option"); 241 usage(); 242 } 243 break; 244 case 'p': 245 if (hash == NULL) 246 requirehash("-p"); 247 pflag = 1; 248 break; 249 case 's': 250 if (hash == NULL) 251 requirehash("-s"); 252 nohashstdin = 1; 253 hash->stringfunc(optarg); 254 break; 255 case 't': 256 if (hash == NULL) 257 requirehash("-t"); 258 nohashstdin = 1; 259 hash->timetrialfunc(); 260 break; 261 case 'w': 262 check_warn = 1; 263 break; 264 case 'x': 265 if (hash == NULL) 266 requirehash("-x"); 267 nohashstdin = 1; 268 hash->testsuitefunc(); 269 break; 270 case '?': 271 default: 272 usage(); 273 } 274 argc -= optind; 275 argv += optind; 276 277 if (do_check) { 278 /* 279 * Verify checksums 280 */ 281 FILE *f; 282 char buf[BUFSIZ]; 283 char *s, *p_filename, *p_cksum; 284 int l_filename, l_cksum; 285 char filename[BUFSIZ]; 286 char cksum[BUFSIZ]; 287 int ok,cnt,badcnt; 288 289 rval = 0; 290 cnt = badcnt = 0; 291 292 if (argc == 0) { 293 f = fdopen(STDIN_FILENO, "r"); 294 } else { 295 f = fopen(argv[0], "r"); 296 } 297 if (f == NULL) 298 err(1, "Cannot read %s", 299 argc>0?argv[0]:"stdin"); 300 301 while(fgets(buf, sizeof(buf), f) != NULL) { 302 s=strrchr(buf, '\n'); 303 if (s) 304 *s = '\0'; 305 306 p_cksum = p_filename = NULL; 307 308 p_filename = strchr(buf, '('); 309 if (p_filename) { 310 /* 311 * Assume 'normal' output if there's a '(' 312 */ 313 p_filename += 1; 314 normal = 0; 315 316 p_cksum = strrchr(p_filename, ')'); 317 if (p_cksum == NULL) { 318 if (check_warn) 319 warnx("bogus format: %s. " 320 "Skipping...", 321 buf); 322 rval = 1; 323 continue; 324 } 325 p_cksum += 4; 326 327 l_cksum = strlen(p_cksum); 328 l_filename = p_cksum - p_filename - 4; 329 330 /* Sanity check, and find proper hash if 331 * it's not the same as the current program 332 */ 333 if (hash == NULL || 334 strncmp(buf, hash->hashname, 335 strlen(hash->hashname)) != 0) { 336 /* 337 * Search proper hash 338 */ 339 const struct hash *nhash; 340 341 for (nhash = hashes ; 342 nhash->hashname != NULL; 343 nhash++) 344 if (strncmp(buf, 345 nhash->hashname, 346 strlen(nhash->hashname)) == 0) 347 break; 348 349 350 if (nhash->hashname == NULL) { 351 if (check_warn) 352 warnx("unknown hash: %s", 353 buf); 354 rval = 1; 355 continue; 356 } else { 357 hash = nhash; 358 } 359 } 360 361 } else { 362 if (hash) { 363 int nspaces; 364 365 /* 366 * 'normal' output, no (ck)sum 367 */ 368 normal = 1; 369 nspaces = 1; 370 371 p_cksum = buf; 372 p_filename = strchr(buf, ' '); 373 if (p_filename == NULL) { 374 if (check_warn) 375 warnx("no filename in %s? " 376 "Skipping...", buf); 377 rval = 1; 378 continue; 379 } 380 while (isspace((int)*++p_filename)) 381 nspaces++; 382 l_filename = strlen(p_filename); 383 l_cksum = p_filename - buf - nspaces; 384 } else { 385 /* 386 * sum/cksum output format 387 */ 388 p_cksum = buf; 389 s=strchr(p_cksum, ' '); 390 if (s == NULL) { 391 if (check_warn) 392 warnx("bogus format: %s." 393 " Skipping...", 394 buf); 395 rval = 1; 396 continue; 397 } 398 l_cksum = s - p_cksum; 399 400 p_filename = strrchr(buf, ' '); 401 if (p_filename == NULL) { 402 if (check_warn) 403 warnx("no filename in %s?" 404 " Skipping...", 405 buf); 406 rval = 1; 407 continue; 408 } 409 p_filename++; 410 l_filename = strlen(p_filename); 411 } 412 } 413 414 strlcpy(filename, p_filename, l_filename+1); 415 strlcpy(cksum, p_cksum, l_cksum+1); 416 417 if (hash) { 418 if (access(filename, R_OK) == 0 419 && strcmp(cksum, hash->filefunc(filename, NULL)) == 0) 420 ok = 1; 421 else 422 ok = 0; 423 } else { 424 if ((fd = open(filename, O_RDONLY, 0)) < 0) { 425 if (check_warn) 426 warn("%s", filename); 427 rval = 1; 428 ok = 0; 429 } else { 430 if (cfncn(fd, &val, &len)) 431 ok = 0; 432 else { 433 u_int32_t should_val; 434 435 should_val = 436 strtoul(cksum, NULL, 10); 437 if (val == should_val) 438 ok = 1; 439 else 440 ok = 0; 441 } 442 close(fd); 443 } 444 } 445 446 if (! ok) { 447 if (hash) 448 printf("(%s) ", hash->hashname); 449 printf("%s: FAILED\n", filename); 450 badcnt++; 451 } 452 cnt++; 453 454 } 455 fclose(f); 456 457 if (badcnt > 0) 458 rval = 1; 459 460 } else { 461 /* 462 * Calculate checksums 463 */ 464 465 fd = STDIN_FILENO; 466 fn = NULL; 467 rval = 0; 468 do { 469 if (*argv) { 470 fn = *argv++; 471 if (hash != NULL) { 472 if (hash_digest_file(fn, hash, normal)) { 473 warn("%s", fn); 474 rval = 1; 475 } 476 continue; 477 } 478 if ((fd = open(fn, O_RDONLY, 0)) < 0) { 479 warn("%s", fn); 480 rval = 1; 481 continue; 482 } 483 } else if (hash && !nohashstdin) { 484 hash->filterfunc(pflag); 485 } 486 487 if (hash == NULL) { 488 if (cfncn(fd, &val, &len)) { 489 warn("%s", fn ? fn : "stdin"); 490 rval = 1; 491 } else 492 pfncn(fn, val, len); 493 (void)close(fd); 494 } 495 } while (*argv); 496 } 497 exit(rval); 498 } 499 500 int 501 hash_digest_file(char *fn, const struct hash *hash, int normal) 502 { 503 char *cp; 504 505 cp = hash->filefunc(fn, NULL); 506 if (cp == NULL) 507 return 1; 508 509 if (normal) 510 printf("%s %s\n", cp, fn); 511 else 512 printf("%s (%s) = %s\n", hash->hashname, fn, cp); 513 514 free(cp); 515 516 return 0; 517 } 518 519 void 520 requirehash(const char *flg) 521 { 522 warnx("%s flag requires `-a algorithm'", flg); 523 usage(); 524 } 525 526 void 527 usage(void) 528 { 529 const char fileargs[] = "[file ... | -c [-w] [sumfile]]"; 530 const char sumargs[] = "[-n] [-a algorithm [-ptx] [-s string]] [-o 1|2]"; 531 const char hashargs[] = "[-nptx] [-s string]"; 532 533 (void)fprintf(stderr, "usage: cksum %s\n %s\n", 534 sumargs, fileargs); 535 (void)fprintf(stderr, " sum %s\n %s\n", 536 sumargs, fileargs); 537 (void)fprintf(stderr, " md2 %s %s\n", hashargs, fileargs); 538 (void)fprintf(stderr, " md4 %s %s\n", hashargs, fileargs); 539 (void)fprintf(stderr, " md5 %s %s\n", hashargs, fileargs); 540 (void)fprintf(stderr, " rmd160 %s %s\n", hashargs, fileargs); 541 (void)fprintf(stderr, " sha1 %s %s\n", hashargs, fileargs); 542 exit(1); 543 } 544