1 /* $NetBSD: cgdconfig.c,v 1.27 2008/07/24 19:07:36 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Roland C. Dowdeswell. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 2002, 2003\ 35 The NetBSD Foundation, Inc. All rights reserved."); 36 __RCSID("$NetBSD: cgdconfig.c,v 1.27 2008/07/24 19:07:36 christos Exp $"); 37 #endif 38 39 #include <err.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <libgen.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include <util.h> 48 49 #include <sys/ioctl.h> 50 #include <sys/disklabel.h> 51 #include <sys/mman.h> 52 #include <sys/param.h> 53 #include <sys/resource.h> 54 55 #include <dev/cgdvar.h> 56 57 #include <ufs/ffs/fs.h> 58 59 #include "params.h" 60 #include "pkcs5_pbkdf2.h" 61 #include "utils.h" 62 63 #define CGDCONFIG_DIR "/etc/cgd" 64 #define CGDCONFIG_CFILE CGDCONFIG_DIR "/cgd.conf" 65 66 enum action { 67 ACTION_DEFAULT, /* default -> configure */ 68 ACTION_CONFIGURE, /* configure, with paramsfile */ 69 ACTION_UNCONFIGURE, /* unconfigure */ 70 ACTION_GENERATE, /* generate a paramsfile */ 71 ACTION_GENERATE_CONVERT, /* generate a ``dup'' paramsfile */ 72 ACTION_CONFIGALL, /* configure all from config file */ 73 ACTION_UNCONFIGALL, /* unconfigure all from config file */ 74 ACTION_CONFIGSTDIN /* configure, key from stdin */ 75 }; 76 77 /* if nflag is set, do not configure/unconfigure the cgd's */ 78 79 int nflag = 0; 80 81 /* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */ 82 83 #define PFLAG_GETPASS 0x01 84 #define PFLAG_STDIN 0x02 85 int pflag = PFLAG_GETPASS; 86 87 static int configure(int, char **, struct params *, int); 88 static int configure_stdin(struct params *, int argc, char **); 89 static int generate(struct params *, int, char **, const char *); 90 static int generate_convert(struct params *, int, char **, const char *); 91 static int unconfigure(int, char **, struct params *, int); 92 static int do_all(const char *, int, char **, 93 int (*)(int, char **, struct params *, int)); 94 95 #define CONFIG_FLAGS_FROMALL 1 /* called from configure_all() */ 96 #define CONFIG_FLAGS_FROMMAIN 2 /* called from main() */ 97 98 static int configure_params(int, const char *, const char *, 99 struct params *); 100 static void eliminate_cores(void); 101 static bits_t *getkey(const char *, struct keygen *, size_t); 102 static bits_t *getkey_storedkey(const char *, struct keygen *, size_t); 103 static bits_t *getkey_randomkey(const char *, struct keygen *, size_t, int); 104 static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t, 105 int); 106 static bits_t *getkey_shell_cmd(const char *, struct keygen *, size_t); 107 static char *maybe_getpass(char *); 108 static int opendisk_werror(const char *, char *, size_t); 109 static int unconfigure_fd(int); 110 static int verify(struct params *, int); 111 static int verify_disklabel(int); 112 static int verify_ffs(int); 113 static int verify_reenter(struct params *); 114 115 static void usage(void); 116 117 /* Verbose Framework */ 118 unsigned verbose = 0; 119 120 #define VERBOSE(x,y) if (verbose >= x) y 121 #define VPRINTF(x,y) if (verbose >= x) (void)printf y 122 123 static void 124 usage(void) 125 { 126 127 (void)fprintf(stderr, "usage: %s [-nv] [-V vmeth] cgd dev [paramsfile]\n", 128 getprogname()); 129 (void)fprintf(stderr, " %s -C [-nv] [-f configfile]\n", getprogname()); 130 (void)fprintf(stderr, " %s -U [-nv] [-f configfile]\n", getprogname()); 131 (void)fprintf(stderr, " %s -G [-nv] [-i ivmeth] [-k kgmeth] " 132 "[-o outfile] paramsfile\n", getprogname()); 133 (void)fprintf(stderr, " %s -g [-nv] [-i ivmeth] [-k kgmeth] " 134 "[-o outfile] alg [keylen]\n", getprogname()); 135 (void)fprintf(stderr, " %s -s [-nv] [-i ivmeth] cgd dev alg " 136 "[keylen]\n", getprogname()); 137 (void)fprintf(stderr, " %s -u [-nv] cgd\n", getprogname()); 138 exit(EXIT_FAILURE); 139 } 140 141 static int 142 parse_size_t(const char *s, size_t *l) 143 { 144 char *endptr; 145 long v; 146 147 errno = 0; 148 v = strtol(s, &endptr, 10); 149 if ((v == LONG_MIN || v == LONG_MAX) && errno) 150 return -1; 151 if (v < INT_MIN || v > INT_MAX) { 152 errno = ERANGE; 153 return -1; 154 } 155 if (endptr == s) { 156 errno = EINVAL; 157 return -1; 158 } 159 *l = (size_t)v; 160 return 0; 161 } 162 163 static void 164 set_action(enum action *action, enum action value) 165 { 166 if (*action != ACTION_DEFAULT) 167 usage(); 168 *action = value; 169 } 170 171 int 172 main(int argc, char **argv) 173 { 174 struct params *p; 175 struct params *tp; 176 struct keygen *kg; 177 enum action action = ACTION_DEFAULT; 178 int ch; 179 const char *cfile = NULL; 180 const char *outfile = NULL; 181 182 setprogname(*argv); 183 eliminate_cores(); 184 if (mlockall(MCL_FUTURE)) 185 err(EXIT_FAILURE, "Can't lock memory"); 186 p = params_new(); 187 kg = NULL; 188 189 while ((ch = getopt(argc, argv, "CGUV:b:f:gi:k:no:spuv")) != -1) 190 switch (ch) { 191 case 'C': 192 set_action(&action, ACTION_CONFIGALL); 193 break; 194 case 'G': 195 set_action(&action, ACTION_GENERATE_CONVERT); 196 break; 197 case 'U': 198 set_action(&action, ACTION_UNCONFIGALL); 199 break; 200 case 'V': 201 tp = params_verify_method(string_fromcharstar(optarg)); 202 if (!tp) 203 usage(); 204 p = params_combine(p, tp); 205 break; 206 case 'b': 207 { 208 size_t size; 209 210 if (parse_size_t(optarg, &size) == -1) 211 usage(); 212 tp = params_bsize(size); 213 if (!tp) 214 usage(); 215 p = params_combine(p, tp); 216 } 217 break; 218 case 'f': 219 if (cfile) 220 usage(); 221 cfile = estrdup(optarg); 222 break; 223 case 'g': 224 set_action(&action, ACTION_GENERATE); 225 break; 226 case 'i': 227 tp = params_ivmeth(string_fromcharstar(optarg)); 228 p = params_combine(p, tp); 229 break; 230 case 'k': 231 kg = keygen_method(string_fromcharstar(optarg)); 232 if (!kg) 233 usage(); 234 keygen_addlist(&p->keygen, kg); 235 break; 236 case 'n': 237 nflag = 1; 238 break; 239 case 'o': 240 if (outfile) 241 usage(); 242 outfile = estrdup(optarg); 243 break; 244 case 'p': 245 pflag = PFLAG_STDIN; 246 break; 247 case 's': 248 set_action(&action, ACTION_CONFIGSTDIN); 249 break; 250 251 case 'u': 252 set_action(&action, ACTION_UNCONFIGURE); 253 break; 254 case 'v': 255 verbose++; 256 break; 257 default: 258 usage(); 259 /* NOTREACHED */ 260 } 261 262 argc -= optind; 263 argv += optind; 264 265 if (!outfile) 266 outfile = ""; 267 if (!cfile) 268 cfile = ""; 269 270 /* validate the consistency of the arguments */ 271 272 switch (action) { 273 case ACTION_DEFAULT: /* ACTION_CONFIGURE is the default */ 274 case ACTION_CONFIGURE: 275 return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN); 276 case ACTION_UNCONFIGURE: 277 return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN); 278 case ACTION_GENERATE: 279 return generate(p, argc, argv, outfile); 280 case ACTION_GENERATE_CONVERT: 281 return generate_convert(p, argc, argv, outfile); 282 case ACTION_CONFIGALL: 283 return do_all(cfile, argc, argv, configure); 284 case ACTION_UNCONFIGALL: 285 return do_all(cfile, argc, argv, unconfigure); 286 case ACTION_CONFIGSTDIN: 287 return configure_stdin(p, argc, argv); 288 default: 289 errx(EXIT_FAILURE, "undefined action"); 290 /* NOTREACHED */ 291 } 292 } 293 294 static bits_t * 295 getkey(const char *dev, struct keygen *kg, size_t len) 296 { 297 bits_t *ret = NULL; 298 bits_t *tmp; 299 300 VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len)); 301 for (; kg; kg=kg->next) { 302 switch (kg->kg_method) { 303 case KEYGEN_STOREDKEY: 304 tmp = getkey_storedkey(dev, kg, len); 305 break; 306 case KEYGEN_RANDOMKEY: 307 tmp = getkey_randomkey(dev, kg, len, 1); 308 break; 309 case KEYGEN_URANDOMKEY: 310 tmp = getkey_randomkey(dev, kg, len, 0); 311 break; 312 case KEYGEN_PKCS5_PBKDF2_SHA1: 313 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0); 314 break; 315 /* provide backwards compatibility for old config files */ 316 case KEYGEN_PKCS5_PBKDF2_OLD: 317 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1); 318 break; 319 case KEYGEN_SHELL_CMD: 320 tmp = getkey_shell_cmd(dev, kg, len); 321 break; 322 default: 323 warnx("unrecognised keygen method %d in getkey()", 324 kg->kg_method); 325 if (ret) 326 bits_free(ret); 327 return NULL; 328 } 329 330 if (ret) 331 ret = bits_xor_d(tmp, ret); 332 else 333 ret = tmp; 334 } 335 336 return ret; 337 } 338 339 /*ARGSUSED*/ 340 static bits_t * 341 getkey_storedkey(const char *target, struct keygen *kg, size_t keylen) 342 { 343 return bits_dup(kg->kg_key); 344 } 345 346 /*ARGSUSED*/ 347 static bits_t * 348 getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard) 349 { 350 return bits_getrandombits(keylen, hard); 351 } 352 353 static char * 354 maybe_getpass(char *prompt) 355 { 356 char buf[1024]; 357 char *p = buf; 358 char *tmp; 359 360 switch (pflag) { 361 case PFLAG_GETPASS: 362 p = getpass(prompt); 363 break; 364 365 case PFLAG_STDIN: 366 p = fgets(buf, sizeof(buf), stdin); 367 if (p) { 368 tmp = strchr(p, '\n'); 369 if (tmp) 370 *tmp = '\0'; 371 } 372 break; 373 374 default: 375 errx(EXIT_FAILURE, "pflag set inappropriately?"); 376 } 377 378 if (!p) 379 err(EXIT_FAILURE, "failed to read passphrase"); 380 381 return estrdup(p); 382 } 383 384 /*ARGSUSED*/ 385 /* 386 * XXX take, and pass through, a compat flag that indicates whether we 387 * provide backwards compatibility with a previous bug. The previous 388 * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a 389 * non-zero compat flag. The new default, and correct keygen method is 390 * called pcks5_pbkdf2/sha1. When the old method is removed, so will 391 * be the compat argument. 392 */ 393 static bits_t * 394 getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen, 395 int compat) 396 { 397 bits_t *ret; 398 char *passp; 399 char buf[1024]; 400 u_int8_t *tmp; 401 402 snprintf(buf, sizeof(buf), "%s's passphrase:", target); 403 passp = maybe_getpass(buf); 404 if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp, 405 strlen(passp), 406 bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)), 407 kg->kg_iterations, compat)) { 408 warnx("failed to generate PKCS#5 PBKDF2 key"); 409 return NULL; 410 } 411 412 ret = bits_new(tmp, keylen); 413 kg->kg_key = bits_dup(ret); 414 memset(passp, 0, strlen(passp)); 415 free(passp); 416 free(tmp); 417 return ret; 418 } 419 420 /*ARGSUSED*/ 421 static bits_t * 422 getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen) 423 { 424 FILE *f; 425 bits_t *ret; 426 427 f = popen(string_tocharstar(kg->kg_cmd), "r"); 428 ret = bits_fget(f, keylen); 429 pclose(f); 430 431 return ret; 432 } 433 434 /*ARGSUSED*/ 435 static int 436 unconfigure(int argc, char **argv, struct params *inparams, int flags) 437 { 438 int fd; 439 int ret; 440 char buf[MAXPATHLEN] = ""; 441 442 /* only complain about additional arguments, if called from main() */ 443 if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1) 444 usage(); 445 446 /* if called from do_all(), then ensure that 2 or 3 args exist */ 447 if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3)) 448 return -1; 449 450 fd = opendisk(*argv, O_RDWR, buf, sizeof(buf), 1); 451 if (fd == -1) { 452 int saved_errno = errno; 453 454 warn("can't open cgd \"%s\", \"%s\"", *argv, buf); 455 456 /* this isn't fatal with nflag != 0 */ 457 if (!nflag) 458 return saved_errno; 459 } 460 461 VPRINTF(1, ("%s (%s): clearing\n", *argv, buf)); 462 463 if (nflag) 464 return 0; 465 466 ret = unconfigure_fd(fd); 467 (void)close(fd); 468 return ret; 469 } 470 471 static int 472 unconfigure_fd(int fd) 473 { 474 struct cgd_ioctl ci; 475 476 if (ioctl(fd, CGDIOCCLR, &ci) == -1) { 477 warn("ioctl"); 478 return -1; 479 } 480 481 return 0; 482 } 483 484 /*ARGSUSED*/ 485 static int 486 configure(int argc, char **argv, struct params *inparams, int flags) 487 { 488 struct params *p; 489 struct keygen *kg; 490 int fd; 491 int loop = 0; 492 int ret; 493 char cgdname[PATH_MAX]; 494 495 if (argc == 2) { 496 char *pfile; 497 498 if (asprintf(&pfile, "%s/%s", 499 CGDCONFIG_DIR, basename(argv[1])) == -1) 500 return -1; 501 502 p = params_cget(pfile); 503 free(pfile); 504 } else if (argc == 3) { 505 p = params_cget(argv[2]); 506 } else { 507 /* print usage and exit, only if called from main() */ 508 if (flags == CONFIG_FLAGS_FROMMAIN) { 509 warnx("wrong number of args"); 510 usage(); 511 } 512 return -1; 513 } 514 515 if (!p) 516 return -1; 517 518 /* 519 * over-ride with command line specifications and fill in default 520 * values. 521 */ 522 523 p = params_combine(p, inparams); 524 ret = params_filldefaults(p); 525 if (ret) { 526 params_free(p); 527 return ret; 528 } 529 530 if (!params_verify(p)) { 531 warnx("params invalid"); 532 return -1; 533 } 534 535 /* 536 * loop over configuring the disk and checking to see if it 537 * verifies properly. We open and close the disk device each 538 * time, because if the user passes us the block device we 539 * need to flush the buffer cache. 540 * 541 * We only loop if one of the verification methods prompts for 542 * a password. 543 */ 544 545 for (kg = p->keygen; pflag == PFLAG_GETPASS && kg; kg = kg->next) 546 if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) || 547 (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) { 548 loop = 1; 549 break; 550 } 551 552 for (;;) { 553 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 554 if (fd == -1) 555 return -1; 556 557 if (p->key) 558 bits_free(p->key); 559 560 p->key = getkey(argv[1], p->keygen, p->keylen); 561 if (!p->key) 562 goto bail_err; 563 564 ret = configure_params(fd, cgdname, argv[1], p); 565 if (ret) 566 goto bail_err; 567 568 ret = verify(p, fd); 569 if (ret == -1) 570 goto bail_err; 571 if (!ret) 572 break; 573 574 (void)unconfigure_fd(fd); 575 (void)close(fd); 576 577 if (!loop) { 578 warnx("verification failed permanently"); 579 goto bail_err; 580 } 581 582 warnx("verification failed, please reenter passphrase"); 583 } 584 585 params_free(p); 586 (void)close(fd); 587 return 0; 588 bail_err: 589 params_free(p); 590 (void)close(fd); 591 return -1; 592 } 593 594 static int 595 configure_stdin(struct params *p, int argc, char **argv) 596 { 597 int fd; 598 int ret; 599 char cgdname[PATH_MAX]; 600 601 if (argc < 3 || argc > 4) 602 usage(); 603 604 p->algorithm = string_fromcharstar(argv[2]); 605 if (argc > 3) { 606 size_t keylen; 607 608 if (parse_size_t(argv[3], &keylen) == -1) { 609 warn("failed to parse key length"); 610 return -1; 611 } 612 p->keylen = keylen; 613 } 614 615 ret = params_filldefaults(p); 616 if (ret) 617 return ret; 618 619 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 620 if (fd == -1) 621 return -1; 622 623 p->key = bits_fget(stdin, p->keylen); 624 if (!p->key) { 625 warnx("failed to read key from stdin"); 626 return -1; 627 } 628 629 return configure_params(fd, cgdname, argv[1], p); 630 } 631 632 static int 633 opendisk_werror(const char *cgd, char *buf, size_t buflen) 634 { 635 int fd; 636 637 VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd, buf, buflen)); 638 639 /* sanity */ 640 if (!cgd || !buf) 641 return -1; 642 643 if (nflag) { 644 if (strlcpy(buf, cgd, buflen) >= buflen) 645 return -1; 646 return 0; 647 } 648 649 fd = opendisk(cgd, O_RDWR, buf, buflen, 0); 650 if (fd == -1) 651 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf); 652 653 return fd; 654 } 655 656 static int 657 configure_params(int fd, const char *cgd, const char *dev, struct params *p) 658 { 659 struct cgd_ioctl ci; 660 661 /* sanity */ 662 if (!cgd || !dev) 663 return -1; 664 665 (void)memset(&ci, 0x0, sizeof(ci)); 666 ci.ci_disk = dev; 667 ci.ci_alg = string_tocharstar(p->algorithm); 668 ci.ci_ivmethod = string_tocharstar(p->ivmeth); 669 ci.ci_key = bits_getbuf(p->key); 670 ci.ci_keylen = p->keylen; 671 ci.ci_blocksize = p->bsize; 672 673 VPRINTF(1, (" with alg %s keylen %zu blocksize %zu ivmethod %s\n", 674 string_tocharstar(p->algorithm), p->keylen, p->bsize, 675 string_tocharstar(p->ivmeth))); 676 VPRINTF(2, ("key: ")); 677 VERBOSE(2, bits_fprint(stdout, p->key)); 678 VPRINTF(2, ("\n")); 679 680 if (nflag) 681 return 0; 682 683 if (ioctl(fd, CGDIOCSET, &ci) == -1) { 684 int saved_errno = errno; 685 warn("ioctl"); 686 return saved_errno; 687 } 688 689 return 0; 690 } 691 692 /* 693 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry. 694 */ 695 696 #define SCANSIZE 8192 697 698 static int 699 verify(struct params *p, int fd) 700 { 701 702 switch (p->verify_method) { 703 case VERIFY_NONE: 704 return 0; 705 case VERIFY_DISKLABEL: 706 return verify_disklabel(fd); 707 case VERIFY_FFS: 708 return verify_ffs(fd); 709 case VERIFY_REENTER: 710 return verify_reenter(p); 711 default: 712 warnx("unimplemented verification method"); 713 return -1; 714 } 715 } 716 717 static int 718 verify_disklabel(int fd) 719 { 720 struct disklabel l; 721 ssize_t ret; 722 char buf[SCANSIZE]; 723 724 /* 725 * we simply scan the first few blocks for a disklabel, ignoring 726 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read 727 * a cgd, anyway, so it is unlikely that there will be non-native 728 * partition information. 729 */ 730 731 ret = pread(fd, buf, 8192, 0); 732 if (ret < 0) { 733 warn("can't read disklabel area"); 734 return -1; 735 } 736 737 /* now scan for the disklabel */ 738 739 return disklabel_scan(&l, buf, (size_t)ret); 740 } 741 742 static off_t sblock_try[] = SBLOCKSEARCH; 743 744 static int 745 verify_ffs(int fd) 746 { 747 size_t i; 748 749 for (i = 0; sblock_try[i] != -1; i++) { 750 union { 751 char buf[SBLOCKSIZE]; 752 struct fs fs; 753 } u; 754 ssize_t ret; 755 756 ret = pread(fd, &u, sizeof(u), sblock_try[i]); 757 if (ret < 0) { 758 warn("pread"); 759 break; 760 } else if ((size_t)ret < sizeof(u)) { 761 warnx("pread: incomplete block"); 762 break; 763 } 764 switch (u.fs.fs_magic) { 765 case FS_UFS1_MAGIC: 766 case FS_UFS2_MAGIC: 767 case FS_UFS1_MAGIC_SWAPPED: 768 case FS_UFS2_MAGIC_SWAPPED: 769 return 0; 770 default: 771 continue; 772 } 773 } 774 775 return 1; /* failure */ 776 } 777 778 static int 779 verify_reenter(struct params *p) 780 { 781 struct keygen *kg; 782 bits_t *orig_key, *key; 783 int ret; 784 785 ret = 0; 786 for (kg = p->keygen; kg && !ret; kg = kg->next) { 787 if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) && 788 (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD )) 789 continue; 790 791 orig_key = kg->kg_key; 792 kg->kg_key = NULL; 793 794 /* add a compat flag till the _OLD method goes away */ 795 key = getkey_pkcs5_pbkdf2("re-enter device", kg, 796 bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD); 797 ret = !bits_match(key, orig_key); 798 799 bits_free(key); 800 bits_free(kg->kg_key); 801 kg->kg_key = orig_key; 802 } 803 804 return ret; 805 } 806 807 static int 808 generate(struct params *p, int argc, char **argv, const char *outfile) 809 { 810 int ret; 811 812 if (argc < 1 || argc > 2) 813 usage(); 814 815 p->algorithm = string_fromcharstar(argv[0]); 816 if (argc > 1) { 817 size_t keylen; 818 819 if (parse_size_t(argv[1], &keylen) == -1) { 820 warn("Failed to parse key length"); 821 return -1; 822 } 823 p->keylen = keylen; 824 } 825 826 ret = params_filldefaults(p); 827 if (ret) 828 return ret; 829 830 if (!p->keygen) { 831 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 832 if (!p->keygen) 833 return -1; 834 } 835 836 if (keygen_filldefaults(p->keygen, p->keylen)) { 837 warnx("Failed to generate defaults for keygen"); 838 return -1; 839 } 840 841 if (!params_verify(p)) { 842 warnx("invalid parameters generated"); 843 return -1; 844 } 845 846 return params_cput(p, outfile); 847 } 848 849 static int 850 generate_convert(struct params *p, int argc, char **argv, const char *outfile) 851 { 852 struct params *oldp; 853 struct keygen *kg; 854 855 if (argc != 1) 856 usage(); 857 858 oldp = params_cget(*argv); 859 if (!oldp) 860 return -1; 861 862 /* for sanity, we ensure that none of the keygens are randomkey */ 863 for (kg=p->keygen; kg; kg=kg->next) 864 if (kg->kg_method == KEYGEN_RANDOMKEY) 865 goto bail; 866 for (kg=oldp->keygen; kg; kg=kg->next) 867 if (kg->kg_method == KEYGEN_RANDOMKEY) 868 goto bail; 869 870 if (!params_verify(oldp)) { 871 warnx("invalid old parameters file \"%s\"", *argv); 872 return -1; 873 } 874 875 oldp->key = getkey("old file", oldp->keygen, oldp->keylen); 876 877 /* we copy across the non-keygen info, here. */ 878 879 string_free(p->algorithm); 880 string_free(p->ivmeth); 881 882 p->algorithm = string_dup(oldp->algorithm); 883 p->ivmeth = string_dup(oldp->ivmeth); 884 p->keylen = oldp->keylen; 885 p->bsize = oldp->bsize; 886 if (p->verify_method == VERIFY_UNKNOWN) 887 p->verify_method = oldp->verify_method; 888 889 params_free(oldp); 890 891 if (!p->keygen) { 892 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 893 if (!p->keygen) 894 return -1; 895 } 896 (void)params_filldefaults(p); 897 (void)keygen_filldefaults(p->keygen, p->keylen); 898 p->key = getkey("new file", p->keygen, p->keylen); 899 900 kg = keygen_generate(KEYGEN_STOREDKEY); 901 kg->kg_key = bits_xor(p->key, oldp->key); 902 keygen_addlist(&p->keygen, kg); 903 904 if (!params_verify(p)) { 905 warnx("can't generate new parameters file"); 906 return -1; 907 } 908 909 return params_cput(p, outfile); 910 bail: 911 params_free(oldp); 912 return -1; 913 } 914 915 static int 916 /*ARGSUSED*/ 917 do_all(const char *cfile, int argc, char **argv, 918 int (*conf)(int, char **, struct params *, int)) 919 { 920 FILE *f; 921 size_t len; 922 size_t lineno; 923 int my_argc; 924 int ret; 925 const char *fn; 926 char *line; 927 char **my_argv; 928 929 if (argc > 0) 930 usage(); 931 932 if (!cfile[0]) 933 fn = CGDCONFIG_CFILE; 934 else 935 fn = cfile; 936 937 f = fopen(fn, "r"); 938 if (!f) { 939 warn("could not open config file \"%s\"", fn); 940 return -1; 941 } 942 943 ret = chdir(CGDCONFIG_DIR); 944 if (ret == -1) 945 warn("could not chdir to %s", CGDCONFIG_DIR); 946 947 ret = 0; 948 lineno = 0; 949 for (;;) { 950 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL); 951 if (!line) 952 break; 953 if (!*line) 954 continue; 955 956 my_argv = words(line, &my_argc); 957 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL); 958 if (ret) { 959 warnx("action failed on \"%s\" line %lu", fn, 960 (u_long)lineno); 961 break; 962 } 963 words_free(my_argv, my_argc); 964 } 965 return ret; 966 } 967 968 static void 969 eliminate_cores(void) 970 { 971 struct rlimit rlp; 972 973 rlp.rlim_cur = 0; 974 rlp.rlim_max = 0; 975 if (setrlimit(RLIMIT_CORE, &rlp) == -1) 976 err(EXIT_FAILURE, "Can't disable cores"); 977 } 978