1 /* $NetBSD: cksum.c,v 1.46 2013/10/18 20:47:06 christos 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.46 2013/10/18 20:47:06 christos 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 static int hash_digest_file(char *, const struct hash *, int); 146 __dead static void requirehash(const char *); 147 __dead static void usage(void); 148 149 int 150 main(int argc, char **argv) 151 { 152 int ch, fd, rval, 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 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 cfncn = csum1; 182 pfncn = psum1; 183 } else { 184 cfncn = crc; 185 pfncn = pcrc; 186 } 187 } 188 189 while ((ch = getopt(argc, argv, "a:cno:ps:twx")) != -1) 190 switch(ch) { 191 case 'a': 192 if (hash) { 193 warnx("illegal use of -a option\n"); 194 usage(); 195 } 196 i = 0; 197 while (hashes[i].hashname != NULL) { 198 if (!strcasecmp(hashes[i].hashname, optarg)) { 199 hash = &hashes[i]; 200 break; 201 } 202 i++; 203 } 204 if (hash == NULL) { 205 if (!strcasecmp(optarg, "old1")) { 206 cfncn = csum1; 207 pfncn = psum1; 208 } else if (!strcasecmp(optarg, "old2")) { 209 cfncn = csum2; 210 pfncn = psum2; 211 } else if (!strcasecmp(optarg, "crc")) { 212 cfncn = crc; 213 pfncn = pcrc; 214 } else { 215 warnx("illegal argument to -a option"); 216 usage(); 217 } 218 } 219 break; 220 case 'c': 221 do_check = 1; 222 break; 223 case 'n': 224 normal = 1; 225 break; 226 case 'o': 227 if (hash) { 228 warnx("%s mutually exclusive with sum", 229 hash->hashname); 230 usage(); 231 } 232 if (!strcmp(optarg, "1")) { 233 cfncn = csum1; 234 pfncn = psum1; 235 } else if (!strcmp(optarg, "2")) { 236 cfncn = csum2; 237 pfncn = psum2; 238 } else { 239 warnx("illegal argument to -o option"); 240 usage(); 241 } 242 break; 243 case 'p': 244 if (hash == NULL) 245 requirehash("-p"); 246 pflag = 1; 247 break; 248 case 's': 249 if (hash == NULL) 250 requirehash("-s"); 251 nohashstdin = 1; 252 hash->stringfunc(optarg); 253 break; 254 case 't': 255 if (hash == NULL) 256 requirehash("-t"); 257 nohashstdin = 1; 258 hash->timetrialfunc(); 259 break; 260 case 'w': 261 check_warn = 1; 262 break; 263 case 'x': 264 if (hash == NULL) 265 requirehash("-x"); 266 nohashstdin = 1; 267 hash->testsuitefunc(); 268 break; 269 case '?': 270 default: 271 usage(); 272 } 273 argc -= optind; 274 argv += optind; 275 276 if (do_check) { 277 /* 278 * Verify checksums 279 */ 280 FILE *f; 281 char buf[BUFSIZ]; 282 char *s, *p_filename, *p_cksum; 283 int l_filename, l_cksum; 284 char filename[BUFSIZ]; 285 char cksum[BUFSIZ]; 286 int ok,cnt,badcnt; 287 288 rval = 0; 289 cnt = badcnt = 0; 290 291 if (argc == 0) { 292 f = fdopen(STDIN_FILENO, "r"); 293 } else { 294 f = fopen(argv[0], "r"); 295 } 296 if (f == NULL) 297 err(1, "Cannot read %s", 298 argc>0?argv[0]:"stdin"); 299 300 while(fgets(buf, sizeof(buf), f) != NULL) { 301 s=strrchr(buf, '\n'); 302 if (s) 303 *s = '\0'; 304 305 p_cksum = p_filename = NULL; 306 307 p_filename = strchr(buf, '('); 308 if (p_filename) { 309 /* 310 * Assume 'normal' output if there's a '(' 311 */ 312 p_filename += 1; 313 normal = 0; 314 315 p_cksum = strrchr(p_filename, ')'); 316 if (p_cksum == NULL) { 317 if (check_warn) 318 warnx("bogus format: %s. " 319 "Skipping...", 320 buf); 321 rval = 1; 322 continue; 323 } 324 p_cksum += 4; 325 326 l_cksum = strlen(p_cksum); 327 l_filename = p_cksum - p_filename - 4; 328 329 /* Sanity check, and find proper hash if 330 * it's not the same as the current program 331 */ 332 if (hash == NULL || 333 strncmp(buf, hash->hashname, 334 strlen(hash->hashname)) != 0) { 335 /* 336 * Search proper hash 337 */ 338 const struct hash *nhash; 339 340 for (nhash = hashes ; 341 nhash->hashname != NULL; 342 nhash++) 343 if (strncmp(buf, 344 nhash->hashname, 345 strlen(nhash->hashname)) == 0) 346 break; 347 348 349 if (nhash->hashname == NULL) { 350 if (check_warn) 351 warnx("unknown hash: %s", 352 buf); 353 rval = 1; 354 continue; 355 } else { 356 hash = nhash; 357 } 358 } 359 360 } else { 361 if (hash) { 362 int nspaces; 363 364 /* 365 * 'normal' output, no (ck)sum 366 */ 367 normal = 1; 368 nspaces = 1; 369 370 p_cksum = buf; 371 p_filename = strchr(buf, ' '); 372 if (p_filename == NULL) { 373 if (check_warn) 374 warnx("no filename in %s? " 375 "Skipping...", buf); 376 rval = 1; 377 continue; 378 } 379 while (isspace((int)*++p_filename)) 380 nspaces++; 381 l_filename = strlen(p_filename); 382 l_cksum = p_filename - buf - nspaces; 383 } else { 384 /* 385 * sum/cksum output format 386 */ 387 p_cksum = buf; 388 s=strchr(p_cksum, ' '); 389 if (s == NULL) { 390 if (check_warn) 391 warnx("bogus format: %s." 392 " Skipping...", 393 buf); 394 rval = 1; 395 continue; 396 } 397 l_cksum = s - p_cksum; 398 399 p_filename = strrchr(buf, ' '); 400 if (p_filename == NULL) { 401 if (check_warn) 402 warnx("no filename in %s?" 403 " Skipping...", 404 buf); 405 rval = 1; 406 continue; 407 } 408 p_filename++; 409 l_filename = strlen(p_filename); 410 } 411 } 412 413 strlcpy(filename, p_filename, l_filename+1); 414 strlcpy(cksum, p_cksum, l_cksum+1); 415 416 if (hash) { 417 if (access(filename, R_OK) == 0 418 && strcmp(cksum, hash->filefunc(filename, NULL)) == 0) 419 ok = 1; 420 else 421 ok = 0; 422 } else { 423 if ((fd = open(filename, O_RDONLY, 0)) < 0) { 424 if (check_warn) 425 warn("%s", filename); 426 rval = 1; 427 ok = 0; 428 } else { 429 if (cfncn(fd, &val, &len)) 430 ok = 0; 431 else { 432 u_int32_t should_val; 433 434 should_val = 435 strtoul(cksum, NULL, 10); 436 if (val == should_val) 437 ok = 1; 438 else 439 ok = 0; 440 } 441 close(fd); 442 } 443 } 444 445 if (! ok) { 446 if (hash) 447 printf("(%s) ", hash->hashname); 448 printf("%s: FAILED\n", filename); 449 badcnt++; 450 } 451 cnt++; 452 453 } 454 fclose(f); 455 456 if (badcnt > 0) 457 rval = 1; 458 459 } else { 460 /* 461 * Calculate checksums 462 */ 463 464 fd = STDIN_FILENO; 465 fn = NULL; 466 rval = 0; 467 do { 468 if (*argv) { 469 fn = *argv++; 470 if (hash != NULL) { 471 if (hash_digest_file(fn, hash, normal)) { 472 warn("%s", fn); 473 rval = 1; 474 } 475 continue; 476 } 477 if ((fd = open(fn, O_RDONLY, 0)) < 0) { 478 warn("%s", fn); 479 rval = 1; 480 continue; 481 } 482 } else if (hash && !nohashstdin) { 483 hash->filterfunc(pflag); 484 } 485 486 if (hash == NULL) { 487 if (cfncn(fd, &val, &len)) { 488 warn("%s", fn ? fn : "stdin"); 489 rval = 1; 490 } else 491 pfncn(fn, val, len); 492 (void)close(fd); 493 } 494 } while (*argv); 495 } 496 exit(rval); 497 } 498 499 static int 500 hash_digest_file(char *fn, const struct hash *hash, int normal) 501 { 502 char *cp; 503 504 cp = hash->filefunc(fn, NULL); 505 if (cp == NULL) 506 return 1; 507 508 if (normal) 509 printf("%s %s\n", cp, fn); 510 else 511 printf("%s (%s) = %s\n", hash->hashname, fn, cp); 512 513 free(cp); 514 515 return 0; 516 } 517 518 static void 519 requirehash(const char *flg) 520 { 521 warnx("%s flag requires `-a algorithm'", flg); 522 usage(); 523 } 524 525 static void 526 usage(void) 527 { 528 const char fileargs[] = "[file ... | -c [-w] [sumfile]]"; 529 const char sumargs[] = "[-n] [-a algorithm [-ptx] [-s string]] [-o 1|2]"; 530 const char hashargs[] = "[-nptx] [-s string]"; 531 532 (void)fprintf(stderr, "usage: cksum %s\n %s\n", 533 sumargs, fileargs); 534 (void)fprintf(stderr, " sum %s\n %s\n", 535 sumargs, fileargs); 536 (void)fprintf(stderr, " md2 %s %s\n", hashargs, fileargs); 537 (void)fprintf(stderr, " md4 %s %s\n", hashargs, fileargs); 538 (void)fprintf(stderr, " md5 %s %s\n", hashargs, fileargs); 539 (void)fprintf(stderr, " rmd160 %s %s\n", hashargs, fileargs); 540 (void)fprintf(stderr, " sha1 %s %s\n", hashargs, fileargs); 541 exit(1); 542 } 543