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