1 /* $NetBSD: cksum.c,v 1.38 2006/09/22 22:35:57 elad 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\n\ 77 The Regents of the University of California. All rights reserved.\n"); 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.38 2006/09/22 22:35:57 elad Exp $"); 85 #endif /* not lint */ 86 87 #include <sys/cdefs.h> 88 #include <sys/types.h> 89 90 #include <ctype.h> 91 #include <err.h> 92 #include <errno.h> 93 #include <fcntl.h> 94 #include <locale.h> 95 #include <md5.h> 96 #include <md4.h> 97 #include <md2.h> 98 #include <sha1.h> 99 #include <crypto/sha2.h> 100 #include <crypto/rmd160.h> 101 #include <stdio.h> 102 #include <stdlib.h> 103 #include <string.h> 104 #include <unistd.h> 105 106 #include "extern.h" 107 108 #define HASH_MD2 0 109 #define HASH_MD4 1 110 #define HASH_MD5 2 111 #define HASH_SHA1 3 112 #define HASH_RMD160 4 113 114 typedef char *(*_filefunc)(const char *, char *); 115 116 struct hash { 117 const char *progname; 118 const char *hashname; 119 void (*stringfunc)(const char *); 120 void (*timetrialfunc)(void); 121 void (*testsuitefunc)(void); 122 void (*filterfunc)(int); 123 char *(*filefunc)(const char *, char *); 124 } hashes[] = { 125 { "md2", "MD2", 126 MD2String, MD2TimeTrial, MD2TestSuite, 127 MD2Filter, MD2File }, 128 { "md4", "MD4", 129 MD4String, MD4TimeTrial, MD4TestSuite, 130 MD4Filter, MD4File }, 131 { "md5", "MD5", 132 MD5String, MD5TimeTrial, MD5TestSuite, 133 MD5Filter, MD5File }, 134 { "sha1", "SHA1", 135 SHA1String, SHA1TimeTrial, SHA1TestSuite, 136 SHA1Filter, (_filefunc) SHA1File }, 137 { "rmd160", "RMD160", 138 RMD160String, RMD160TimeTrial, RMD160TestSuite, 139 RMD160Filter, (_filefunc) RMD160File }, 140 { "sha256", "SHA256", 141 SHA256_String, SHA256_TimeTrial, SHA256_TestSuite, 142 SHA256_Filter, (_filefunc) SHA256_File }, 143 { "sha384", "SHA384", 144 SHA384_String, SHA384_TimeTrial, SHA384_TestSuite, 145 SHA384_Filter, (_filefunc) SHA384_File }, 146 { "sha512", "SHA512", 147 SHA512_String, SHA512_TimeTrial, SHA512_TestSuite, 148 SHA512_Filter, (_filefunc) SHA512_File }, 149 { NULL } 150 }; 151 152 int hash_digest_file(char *, struct hash *, int); 153 void requirehash(const char *); 154 void usage(void); 155 156 int 157 main(int argc, char **argv) 158 { 159 int ch, fd, rval, dosum, pflag, nohashstdin; 160 u_int32_t val; 161 off_t len; 162 char *fn; 163 const char *progname; 164 int (*cfncn) (int, u_int32_t *, off_t *); 165 void (*pfncn) (char *, u_int32_t, off_t); 166 struct hash *hash; 167 int normal, i, check_warn, do_check; 168 169 cfncn = NULL; 170 pfncn = NULL; 171 dosum = pflag = nohashstdin = 0; 172 normal = 0; 173 check_warn = 0; 174 do_check = 0; 175 176 setlocale(LC_ALL, ""); 177 178 progname = getprogname(); 179 180 for (hash = hashes; hash->hashname != NULL; hash++) 181 if (strcmp(progname, hash->progname) == 0) 182 break; 183 184 if (hash->hashname == NULL) { 185 hash = NULL; 186 187 if (!strcmp(progname, "sum")) { 188 dosum = 1; 189 cfncn = csum1; 190 pfncn = psum1; 191 } else { 192 cfncn = crc; 193 pfncn = pcrc; 194 } 195 } 196 197 while ((ch = getopt(argc, argv, "a:cno:ps:twx")) != -1) 198 switch(ch) { 199 case 'a': 200 if (hash != NULL || dosum) { 201 warnx("illegal use of -a option\n"); 202 usage(); 203 } 204 i = 0; 205 while (hashes[i].hashname != NULL) { 206 if (!strcasecmp(hashes[i].hashname, optarg)) { 207 hash = &hashes[i]; 208 break; 209 } 210 i++; 211 } 212 if (hash == NULL) { 213 if (!strcasecmp(optarg, "old1")) { 214 cfncn = csum1; 215 pfncn = psum1; 216 } else if (!strcasecmp(optarg, "old2")) { 217 cfncn = csum2; 218 pfncn = psum2; 219 } else if (!strcasecmp(optarg, "crc")) { 220 cfncn = crc; 221 pfncn = pcrc; 222 } else { 223 warnx("illegal argument to -a option"); 224 usage(); 225 } 226 } 227 break; 228 case 'c': 229 do_check = 1; 230 break; 231 case 'n': 232 normal = 1; 233 break; 234 case 'o': 235 if (hash) { 236 warnx("%s mutually exclusive with sum", 237 hash->hashname); 238 usage(); 239 } 240 if (!strcmp(optarg, "1")) { 241 cfncn = csum1; 242 pfncn = psum1; 243 } else if (!strcmp(optarg, "2")) { 244 cfncn = csum2; 245 pfncn = psum2; 246 } else { 247 warnx("illegal argument to -o option"); 248 usage(); 249 } 250 break; 251 case 'p': 252 if (hash == NULL) 253 requirehash("-p"); 254 pflag = 1; 255 break; 256 case 's': 257 if (hash == NULL) 258 requirehash("-s"); 259 nohashstdin = 1; 260 hash->stringfunc(optarg); 261 break; 262 case 't': 263 if (hash == NULL) 264 requirehash("-t"); 265 nohashstdin = 1; 266 hash->timetrialfunc(); 267 break; 268 case 'w': 269 check_warn = 1; 270 break; 271 case 'x': 272 if (hash == NULL) 273 requirehash("-x"); 274 nohashstdin = 1; 275 hash->testsuitefunc(); 276 break; 277 case '?': 278 default: 279 usage(); 280 } 281 argc -= optind; 282 argv += optind; 283 284 if (do_check) { 285 /* 286 * Verify checksums 287 */ 288 FILE *f; 289 char buf[BUFSIZ]; 290 char *s, *p_filename, *p_cksum; 291 int l_filename, l_cksum; 292 char filename[BUFSIZ]; 293 char cksum[BUFSIZ]; 294 int ok,cnt,badcnt; 295 296 rval = 0; 297 cnt = badcnt = 0; 298 299 if (argc == 0) { 300 f = fdopen(STDIN_FILENO, "r"); 301 } else { 302 f = fopen(argv[0], "r"); 303 } 304 if (f == NULL) 305 err(1, "Cannot read %s", 306 argc>0?argv[0]:"stdin"); 307 308 while(fgets(buf, sizeof(buf), f) != NULL) { 309 s=strrchr(buf, '\n'); 310 if (s) 311 *s = '\0'; 312 313 p_cksum = p_filename = NULL; 314 315 p_filename = strchr(buf, '('); 316 if (p_filename) { 317 /* 318 * Assume 'normal' output if there's a '(' 319 */ 320 p_filename += 1; 321 normal = 0; 322 323 p_cksum = strrchr(p_filename, ')'); 324 if (p_cksum == NULL) { 325 if (check_warn) 326 warnx("bogus format: %s. " 327 "Skipping...", 328 buf); 329 rval = 1; 330 continue; 331 } 332 p_cksum += 4; 333 334 l_cksum = strlen(p_cksum); 335 l_filename = p_cksum - p_filename - 4; 336 337 /* Sanity check, and find proper hash if 338 * it's not the same as the current program 339 */ 340 if (hash == NULL || 341 strncmp(buf, hash->hashname, 342 strlen(hash->hashname)) != 0) { 343 /* 344 * Search proper hash 345 */ 346 struct hash *nhash; 347 348 for (nhash = hashes ; 349 nhash->hashname != NULL; 350 nhash++) 351 if (strncmp(buf, 352 nhash->hashname, 353 strlen(nhash->hashname)) == 0) 354 break; 355 356 357 if (nhash->hashname == NULL) { 358 if (check_warn) 359 warnx("unknown hash: %s", 360 buf); 361 rval = 1; 362 continue; 363 } else { 364 hash = nhash; 365 } 366 } 367 368 } else { 369 if (hash) { 370 int nspaces; 371 372 /* 373 * 'normal' output, no (ck)sum 374 */ 375 normal = 1; 376 nspaces = 1; 377 378 p_cksum = buf; 379 p_filename = strchr(buf, ' '); 380 if (p_filename == NULL) { 381 if (check_warn) 382 warnx("no filename in %s? " 383 "Skipping...", buf); 384 rval = 1; 385 continue; 386 } 387 while (isspace((int)*++p_filename)) 388 nspaces++; 389 l_filename = strlen(p_filename); 390 l_cksum = p_filename - buf - nspaces; 391 } else { 392 /* 393 * sum/cksum output format 394 */ 395 p_cksum = buf; 396 s=strchr(p_cksum, ' '); 397 if (s == NULL) { 398 if (check_warn) 399 warnx("bogus format: %s." 400 " Skipping...", 401 buf); 402 rval = 1; 403 continue; 404 } 405 l_cksum = s - p_cksum; 406 407 p_filename = strrchr(buf, ' '); 408 if (p_filename == NULL) { 409 if (check_warn) 410 warnx("no filename in %s?" 411 " Skipping...", 412 buf); 413 rval = 1; 414 continue; 415 } 416 p_filename++; 417 l_filename = strlen(p_filename); 418 } 419 } 420 421 strlcpy(filename, p_filename, l_filename+1); 422 strlcpy(cksum, p_cksum, l_cksum+1); 423 424 if (hash) { 425 if (access(filename, R_OK) == 0 426 && strcmp(cksum, hash->filefunc(filename, NULL)) == 0) 427 ok = 1; 428 else 429 ok = 0; 430 } else { 431 if ((fd = open(filename, O_RDONLY, 0)) < 0) { 432 if (check_warn) 433 warn("%s", filename); 434 rval = 1; 435 ok = 0; 436 } else { 437 if (cfncn(fd, &val, &len)) 438 ok = 0; 439 else { 440 u_int32_t should_val; 441 442 should_val = 443 strtoul(cksum, NULL, 10); 444 if (val == should_val) 445 ok = 1; 446 else 447 ok = 0; 448 } 449 close(fd); 450 } 451 } 452 453 if (! ok) { 454 if (hash) 455 printf("(%s) ", hash->hashname); 456 printf("%s: FAILED\n", filename); 457 badcnt++; 458 } 459 cnt++; 460 461 } 462 fclose(f); 463 464 if (badcnt > 0) 465 rval = 1; 466 467 } else { 468 /* 469 * Calculate checksums 470 */ 471 472 fd = STDIN_FILENO; 473 fn = NULL; 474 rval = 0; 475 do { 476 if (*argv) { 477 fn = *argv++; 478 if (hash != NULL) { 479 if (hash_digest_file(fn, hash, normal)) { 480 warn("%s", fn); 481 rval = 1; 482 } 483 continue; 484 } 485 if ((fd = open(fn, O_RDONLY, 0)) < 0) { 486 warn("%s", fn); 487 rval = 1; 488 continue; 489 } 490 } else if (hash && !nohashstdin) { 491 hash->filterfunc(pflag); 492 } 493 494 if (hash == NULL) { 495 if (cfncn(fd, &val, &len)) { 496 warn("%s", fn ? fn : "stdin"); 497 rval = 1; 498 } else 499 pfncn(fn, val, len); 500 (void)close(fd); 501 } 502 } while (*argv); 503 } 504 exit(rval); 505 } 506 507 int 508 hash_digest_file(char *fn, struct hash *hash, int normal) 509 { 510 char *cp; 511 512 cp = hash->filefunc(fn, NULL); 513 if (cp == NULL) 514 return 1; 515 516 if (normal) 517 printf("%s %s\n", cp, fn); 518 else 519 printf("%s (%s) = %s\n", hash->hashname, fn, cp); 520 521 free(cp); 522 523 return 0; 524 } 525 526 void 527 requirehash(const char *flg) 528 { 529 warnx("%s flag requires `md2', `md4', `md5', `sha1', or `rmd160'", 530 flg); 531 usage(); 532 } 533 534 void 535 usage(void) 536 { 537 538 (void)fprintf(stderr, "usage: cksum [-nw] [-a algorithm | -c file ]\n\t\t| [-o 1 | 2]] [file ...]\n"); 539 (void)fprintf(stderr, " sum [-c] [file ...]\n"); 540 (void)fprintf(stderr, 541 " md2 [-n] [-p | -t | -x | -s string] [file ...]\n"); 542 (void)fprintf(stderr, 543 " md4 [-n] [-p | -t | -x | -s string] [file ...]\n"); 544 (void)fprintf(stderr, 545 " md5 [-n] [-p | -t | -x | -s string] [file ...]\n"); 546 (void)fprintf(stderr, 547 " sha1 [-n] [-p | -t | -x | -s string] [file ...]\n"); 548 (void)fprintf(stderr, 549 " rmd160 [-n] [-p | -t | -x | -s string] [file ...]\n"); 550 exit(1); 551 } 552