1 /* $NetBSD: cgdconfig.c,v 1.50 2019/04/10 06:11:37 kre 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.50 2019/04/10 06:11:37 kre 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/stat.h> 53 #include <sys/bootblock.h> 54 #include <sys/disklabel.h> 55 #include <sys/disklabel_gpt.h> 56 #include <sys/mman.h> 57 #include <sys/param.h> 58 #include <sys/resource.h> 59 #include <sys/statvfs.h> 60 #include <sys/bitops.h> 61 62 #include <dev/cgdvar.h> 63 64 #include <ufs/ffs/fs.h> 65 66 #include "params.h" 67 #include "pkcs5_pbkdf2.h" 68 #include "utils.h" 69 #include "cgdconfig.h" 70 #include "prog_ops.h" 71 72 #define CGDCONFIG_CFILE CGDCONFIG_DIR "/cgd.conf" 73 74 enum action { 75 ACTION_DEFAULT, /* default -> configure */ 76 ACTION_CONFIGURE, /* configure, with paramsfile */ 77 ACTION_UNCONFIGURE, /* unconfigure */ 78 ACTION_GENERATE, /* generate a paramsfile */ 79 ACTION_GENERATE_CONVERT, /* generate a ``dup'' paramsfile */ 80 ACTION_CONFIGALL, /* configure all from config file */ 81 ACTION_UNCONFIGALL, /* unconfigure all from config file */ 82 ACTION_CONFIGSTDIN, /* configure, key from stdin */ 83 ACTION_LIST /* list configured devices */ 84 }; 85 86 /* if nflag is set, do not configure/unconfigure the cgd's */ 87 88 int nflag = 0; 89 90 /* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */ 91 92 #define PFLAG_GETPASS 0x01 93 #define PFLAG_GETPASS_ECHO 0x02 94 #define PFLAG_GETPASS_MASK 0x03 95 #define PFLAG_STDIN 0x04 96 int pflag = PFLAG_GETPASS; 97 98 static int configure(int, char **, struct params *, int); 99 static int configure_stdin(struct params *, int argc, char **); 100 static int generate(struct params *, int, char **, const char *); 101 static int generate_convert(struct params *, int, char **, const char *); 102 static int unconfigure(int, char **, struct params *, int); 103 static int do_all(const char *, int, char **, 104 int (*)(int, char **, struct params *, int)); 105 static int do_list(int, char **); 106 107 #define CONFIG_FLAGS_FROMALL 1 /* called from configure_all() */ 108 #define CONFIG_FLAGS_FROMMAIN 2 /* called from main() */ 109 110 static int configure_params(int, const char *, const char *, 111 struct params *); 112 static void eliminate_cores(void); 113 static bits_t *getkey(const char *, struct keygen *, size_t); 114 static bits_t *getkey_storedkey(const char *, struct keygen *, size_t); 115 static bits_t *getkey_randomkey(const char *, struct keygen *, size_t, int); 116 static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t, 117 int); 118 static bits_t *getkey_shell_cmd(const char *, struct keygen *, size_t); 119 static char *maybe_getpass(char *); 120 static int opendisk_werror(const char *, char *, size_t); 121 static int unconfigure_fd(int); 122 static int verify(struct params *, int); 123 static int verify_disklabel(int); 124 static int verify_ffs(int); 125 static int verify_reenter(struct params *); 126 static int verify_mbr(int); 127 static int verify_gpt(int); 128 129 __dead static void usage(void); 130 131 /* Verbose Framework */ 132 unsigned verbose = 0; 133 134 #define VERBOSE(x,y) if (verbose >= x) y 135 #define VPRINTF(x,y) if (verbose >= x) (void)printf y 136 137 static void 138 usage(void) 139 { 140 141 (void)fprintf(stderr, "usage: %s [-enpv] [-V vmeth] cgd dev " 142 "[paramsfile]\n", getprogname()); 143 (void)fprintf(stderr, " %s -C [-enpv] [-f configfile]\n", 144 getprogname()); 145 (void)fprintf(stderr, " %s -G [-enpv] [-i ivmeth] [-k kgmeth] " 146 "[-o outfile] paramsfile\n", getprogname()); 147 (void)fprintf(stderr, " %s -g [-nv] [-i ivmeth] [-k kgmeth] " 148 "[-o outfile] alg [keylen]\n", getprogname()); 149 (void)fprintf(stderr, " %s -l [-v[v]] [cgd]\n", getprogname()); 150 (void)fprintf(stderr, " %s -s [-nv] [-i ivmeth] cgd dev alg " 151 "[keylen]\n", getprogname()); 152 (void)fprintf(stderr, " %s -U [-nv] [-f configfile]\n", 153 getprogname()); 154 (void)fprintf(stderr, " %s -u [-nv] cgd\n", getprogname()); 155 exit(EXIT_FAILURE); 156 } 157 158 static int 159 parse_size_t(const char *s, size_t *l) 160 { 161 char *endptr; 162 long v; 163 164 errno = 0; 165 v = strtol(s, &endptr, 10); 166 if ((v == LONG_MIN || v == LONG_MAX) && errno) 167 return -1; 168 if (v < INT_MIN || v > INT_MAX) { 169 errno = ERANGE; 170 return -1; 171 } 172 if (endptr == s) { 173 errno = EINVAL; 174 return -1; 175 } 176 *l = (size_t)v; 177 return 0; 178 } 179 180 static void 181 set_action(enum action *action, enum action value) 182 { 183 if (*action != ACTION_DEFAULT) 184 usage(); 185 *action = value; 186 } 187 188 int 189 main(int argc, char **argv) 190 { 191 struct params *p; 192 struct params *tp; 193 struct keygen *kg; 194 enum action action = ACTION_DEFAULT; 195 int ch; 196 const char *cfile = NULL; 197 const char *outfile = NULL; 198 199 setprogname(*argv); 200 eliminate_cores(); 201 if (mlockall(MCL_FUTURE)) 202 err(EXIT_FAILURE, "Can't lock memory"); 203 p = params_new(); 204 kg = NULL; 205 206 while ((ch = getopt(argc, argv, "CGUV:b:ef:gi:k:lno:spuv")) != -1) 207 switch (ch) { 208 case 'C': 209 set_action(&action, ACTION_CONFIGALL); 210 break; 211 case 'G': 212 set_action(&action, ACTION_GENERATE_CONVERT); 213 break; 214 case 'U': 215 set_action(&action, ACTION_UNCONFIGALL); 216 break; 217 case 'V': 218 tp = params_verify_method(string_fromcharstar(optarg)); 219 if (!tp) 220 usage(); 221 p = params_combine(p, tp); 222 break; 223 case 'b': 224 { 225 size_t size; 226 227 if (parse_size_t(optarg, &size) == -1) 228 usage(); 229 tp = params_bsize(size); 230 if (!tp) 231 usage(); 232 p = params_combine(p, tp); 233 } 234 break; 235 case 'e': 236 pflag = PFLAG_GETPASS_ECHO; 237 break; 238 case 'f': 239 if (cfile) 240 usage(); 241 cfile = estrdup(optarg); 242 break; 243 case 'g': 244 set_action(&action, ACTION_GENERATE); 245 break; 246 case 'i': 247 tp = params_ivmeth(string_fromcharstar(optarg)); 248 p = params_combine(p, tp); 249 break; 250 case 'k': 251 kg = keygen_method(string_fromcharstar(optarg)); 252 if (!kg) 253 usage(); 254 keygen_addlist(&p->keygen, kg); 255 break; 256 case 'l': 257 set_action(&action, ACTION_LIST); 258 break; 259 case 'n': 260 nflag = 1; 261 break; 262 case 'o': 263 if (outfile) 264 usage(); 265 outfile = estrdup(optarg); 266 break; 267 case 'p': 268 pflag = PFLAG_STDIN; 269 break; 270 case 's': 271 set_action(&action, ACTION_CONFIGSTDIN); 272 break; 273 274 case 'u': 275 set_action(&action, ACTION_UNCONFIGURE); 276 break; 277 case 'v': 278 verbose++; 279 break; 280 default: 281 usage(); 282 /* NOTREACHED */ 283 } 284 285 argc -= optind; 286 argv += optind; 287 288 if (!outfile) 289 outfile = ""; 290 if (!cfile) 291 cfile = ""; 292 293 if (prog_init && prog_init() == -1) 294 err(1, "init failed"); 295 296 /* validate the consistency of the arguments */ 297 298 switch (action) { 299 case ACTION_DEFAULT: /* ACTION_CONFIGURE is the default */ 300 case ACTION_CONFIGURE: 301 return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN); 302 case ACTION_UNCONFIGURE: 303 return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN); 304 case ACTION_GENERATE: 305 return generate(p, argc, argv, outfile); 306 case ACTION_GENERATE_CONVERT: 307 return generate_convert(p, argc, argv, outfile); 308 case ACTION_CONFIGALL: 309 return do_all(cfile, argc, argv, configure); 310 case ACTION_UNCONFIGALL: 311 return do_all(cfile, argc, argv, unconfigure); 312 case ACTION_CONFIGSTDIN: 313 return configure_stdin(p, argc, argv); 314 case ACTION_LIST: 315 return do_list(argc, argv); 316 default: 317 errx(EXIT_FAILURE, "undefined action"); 318 /* NOTREACHED */ 319 } 320 } 321 322 static bits_t * 323 getkey(const char *dev, struct keygen *kg, size_t len) 324 { 325 bits_t *ret = NULL; 326 bits_t *tmp; 327 328 VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len)); 329 for (; kg; kg=kg->next) { 330 switch (kg->kg_method) { 331 case KEYGEN_STOREDKEY: 332 tmp = getkey_storedkey(dev, kg, len); 333 break; 334 case KEYGEN_RANDOMKEY: 335 tmp = getkey_randomkey(dev, kg, len, 1); 336 break; 337 case KEYGEN_URANDOMKEY: 338 tmp = getkey_randomkey(dev, kg, len, 0); 339 break; 340 case KEYGEN_PKCS5_PBKDF2_SHA1: 341 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0); 342 break; 343 /* provide backwards compatibility for old config files */ 344 case KEYGEN_PKCS5_PBKDF2_OLD: 345 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1); 346 break; 347 case KEYGEN_SHELL_CMD: 348 tmp = getkey_shell_cmd(dev, kg, len); 349 break; 350 default: 351 warnx("unrecognised keygen method %d in getkey()", 352 kg->kg_method); 353 if (ret) 354 bits_free(ret); 355 return NULL; 356 } 357 358 if (ret) 359 ret = bits_xor_d(tmp, ret); 360 else 361 ret = tmp; 362 } 363 364 return ret; 365 } 366 367 /*ARGSUSED*/ 368 static bits_t * 369 getkey_storedkey(const char *target, struct keygen *kg, size_t keylen) 370 { 371 return bits_dup(kg->kg_key); 372 } 373 374 /*ARGSUSED*/ 375 static bits_t * 376 getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard) 377 { 378 return bits_getrandombits(keylen, hard); 379 } 380 381 static char * 382 maybe_getpass(char *prompt) 383 { 384 char buf[1024]; 385 char *p = NULL; 386 char *tmp, *pass; 387 388 switch (pflag) { 389 case PFLAG_GETPASS: 390 p = getpass_r(prompt, buf, sizeof(buf)); 391 break; 392 393 case PFLAG_GETPASS_ECHO: 394 p = getpassfd(prompt, buf, sizeof(buf), NULL, 395 GETPASS_ECHO|GETPASS_ECHO_NL|GETPASS_NEED_TTY, 0); 396 break; 397 398 case PFLAG_STDIN: 399 p = fgets(buf, sizeof(buf), stdin); 400 if (p) { 401 tmp = strchr(p, '\n'); 402 if (tmp) 403 *tmp = '\0'; 404 } 405 break; 406 407 default: 408 errx(EXIT_FAILURE, "pflag set inappropriately?"); 409 } 410 411 if (!p) 412 err(EXIT_FAILURE, "failed to read passphrase"); 413 414 pass = estrdup(p); 415 explicit_memset(buf, 0, sizeof(buf)); 416 417 return pass; 418 } 419 420 /*ARGSUSED*/ 421 /* 422 * XXX take, and pass through, a compat flag that indicates whether we 423 * provide backwards compatibility with a previous bug. The previous 424 * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a 425 * non-zero compat flag. The new default, and correct keygen method is 426 * called pcks5_pbkdf2/sha1. When the old method is removed, so will 427 * be the compat argument. 428 */ 429 static bits_t * 430 getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen, 431 int compat) 432 { 433 bits_t *ret; 434 char *passp; 435 char buf[1024]; 436 u_int8_t *tmp; 437 438 snprintf(buf, sizeof(buf), "%s's passphrase%s:", target, 439 pflag & PFLAG_GETPASS_ECHO ? " (echo)" : ""); 440 passp = maybe_getpass(buf); 441 if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp, 442 strlen(passp), 443 bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)), 444 kg->kg_iterations, compat)) { 445 warnx("failed to generate PKCS#5 PBKDF2 key"); 446 return NULL; 447 } 448 449 ret = bits_new(tmp, keylen); 450 kg->kg_key = bits_dup(ret); 451 explicit_memset(passp, 0, strlen(passp)); 452 free(passp); 453 free(tmp); 454 return ret; 455 } 456 457 /*ARGSUSED*/ 458 static bits_t * 459 getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen) 460 { 461 FILE *f; 462 bits_t *ret; 463 464 f = popen(string_tocharstar(kg->kg_cmd), "r"); 465 ret = bits_fget(f, keylen); 466 pclose(f); 467 468 return ret; 469 } 470 471 /*ARGSUSED*/ 472 static int 473 unconfigure(int argc, char **argv, struct params *inparams, int flags) 474 { 475 int fd; 476 int ret; 477 char buf[MAXPATHLEN] = ""; 478 479 /* only complain about additional arguments, if called from main() */ 480 if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1) 481 usage(); 482 483 /* if called from do_all(), then ensure that 2 or 3 args exist */ 484 if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3)) 485 return -1; 486 487 fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, prog_open); 488 if (fd == -1) { 489 int saved_errno = errno; 490 491 warn("can't open cgd \"%s\", \"%s\"", *argv, buf); 492 493 /* this isn't fatal with nflag != 0 */ 494 if (!nflag) 495 return saved_errno; 496 } 497 498 VPRINTF(1, ("%s (%s): clearing\n", *argv, buf)); 499 500 if (nflag) 501 return 0; 502 503 ret = unconfigure_fd(fd); 504 (void)prog_close(fd); 505 return ret; 506 } 507 508 static int 509 unconfigure_fd(int fd) 510 { 511 struct cgd_ioctl ci; 512 513 if (prog_ioctl(fd, CGDIOCCLR, &ci) == -1) { 514 warn("ioctl"); 515 return -1; 516 } 517 518 return 0; 519 } 520 521 /*ARGSUSED*/ 522 static int 523 configure(int argc, char **argv, struct params *inparams, int flags) 524 { 525 struct params *p; 526 struct keygen *kg; 527 int fd; 528 int loop = 0; 529 int ret; 530 char cgdname[PATH_MAX]; 531 char devicename[PATH_MAX]; 532 const char *dev = NULL; /* XXX: gcc */ 533 534 if (argc < 2 || argc > 3) { 535 /* print usage and exit, only if called from main() */ 536 if (flags == CONFIG_FLAGS_FROMMAIN) { 537 warnx("wrong number of args"); 538 usage(); 539 } 540 return -1; 541 } 542 543 if (( 544 fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open) 545 ) != -1) { 546 struct cgd_user cgu; 547 548 cgu.cgu_unit = -1; 549 if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) { 550 warnx("device %s already in use", *argv); 551 prog_close(fd); 552 return -1; 553 } 554 prog_close(fd); 555 } 556 557 dev = getfsspecname(devicename, sizeof(devicename), argv[1]); 558 if (dev == NULL) { 559 warnx("getfsspecname failed: %s", devicename); 560 return -1; 561 } 562 563 if (argc == 2) { 564 char pfile[MAXPATHLEN]; 565 566 /* make string writable for basename */ 567 strlcpy(pfile, dev, sizeof(pfile)); 568 p = params_cget(basename(pfile)); 569 } else 570 p = params_cget(argv[2]); 571 572 if (!p) 573 return -1; 574 575 /* 576 * over-ride with command line specifications and fill in default 577 * values. 578 */ 579 580 p = params_combine(p, inparams); 581 ret = params_filldefaults(p); 582 if (ret) { 583 params_free(p); 584 return ret; 585 } 586 587 if (!params_verify(p)) { 588 warnx("params invalid"); 589 return -1; 590 } 591 592 /* 593 * loop over configuring the disk and checking to see if it 594 * verifies properly. We open and close the disk device each 595 * time, because if the user passes us the block device we 596 * need to flush the buffer cache. 597 * 598 * We only loop if one of the verification methods prompts for 599 * a password. 600 */ 601 602 for (kg = p->keygen; 603 (pflag & PFLAG_GETPASS_MASK) && kg; 604 kg = kg->next) 605 if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) || 606 (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) { 607 loop = 1; 608 break; 609 } 610 611 for (;;) { 612 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 613 if (fd == -1) 614 return -1; 615 616 if (p->key) 617 bits_free(p->key); 618 619 p->key = getkey(argv[1], p->keygen, p->keylen); 620 if (!p->key) 621 goto bail_err; 622 623 ret = configure_params(fd, cgdname, dev, p); 624 if (ret) 625 goto bail_err; 626 627 ret = verify(p, fd); 628 if (ret == -1) { 629 (void)unconfigure_fd(fd); 630 goto bail_err; 631 } 632 if (ret == 0) /* success */ 633 break; 634 635 (void)unconfigure_fd(fd); 636 (void)prog_close(fd); 637 638 if (!loop) { 639 warnx("verification failed permanently"); 640 goto bail_err; 641 } 642 643 warnx("verification failed, please reenter passphrase"); 644 } 645 646 params_free(p); 647 (void)prog_close(fd); 648 return 0; 649 650 bail_err:; 651 params_free(p); 652 (void)prog_close(fd); 653 return -1; 654 } 655 656 static int 657 configure_stdin(struct params *p, int argc, char **argv) 658 { 659 int fd; 660 int ret; 661 char cgdname[PATH_MAX]; 662 char devicename[PATH_MAX]; 663 const char *dev; 664 665 if (argc < 3 || argc > 4) 666 usage(); 667 668 dev = getfsspecname(devicename, sizeof(devicename), argv[1]); 669 if (dev == NULL) { 670 warnx("getfsspecname failed: %s", devicename); 671 return -1; 672 } 673 674 p->algorithm = string_fromcharstar(argv[2]); 675 if (argc > 3) { 676 size_t keylen; 677 678 if (parse_size_t(argv[3], &keylen) == -1) { 679 warn("failed to parse key length"); 680 return -1; 681 } 682 p->keylen = keylen; 683 } 684 685 ret = params_filldefaults(p); 686 if (ret) 687 return ret; 688 689 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 690 if (fd == -1) 691 return -1; 692 693 p->key = bits_fget(stdin, p->keylen); 694 if (!p->key) { 695 warnx("failed to read key from stdin"); 696 return -1; 697 } 698 699 return configure_params(fd, cgdname, dev, p); 700 } 701 702 static int 703 opendisk_werror(const char *cgd, char *buf, size_t buflen) 704 { 705 int fd; 706 707 VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd,buf,buflen)); 708 709 /* sanity */ 710 if (!cgd || !buf) 711 return -1; 712 713 if (nflag) { 714 if (strlcpy(buf, cgd, buflen) >= buflen) 715 return -1; 716 return 0; 717 } 718 719 fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open); 720 if (fd == -1) 721 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf); 722 723 return fd; 724 } 725 726 static int 727 configure_params(int fd, const char *cgd, const char *dev, struct params *p) 728 { 729 struct cgd_ioctl ci; 730 731 /* sanity */ 732 if (!cgd || !dev) 733 return -1; 734 735 (void)memset(&ci, 0x0, sizeof(ci)); 736 ci.ci_disk = dev; 737 ci.ci_alg = string_tocharstar(p->algorithm); 738 ci.ci_ivmethod = string_tocharstar(p->ivmeth); 739 ci.ci_key = bits_getbuf(p->key); 740 ci.ci_keylen = p->keylen; 741 ci.ci_blocksize = p->bsize; 742 743 VPRINTF(1, (" with alg %s keylen %zu blocksize %zu ivmethod %s\n", 744 string_tocharstar(p->algorithm), p->keylen, p->bsize, 745 string_tocharstar(p->ivmeth))); 746 VPRINTF(2, ("key: ")); 747 VERBOSE(2, bits_fprint(stdout, p->key)); 748 VPRINTF(2, ("\n")); 749 750 if (nflag) 751 return 0; 752 753 if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) { 754 int saved_errno = errno; 755 warn("ioctl"); 756 return saved_errno; 757 } 758 759 return 0; 760 } 761 762 /* 763 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry. 764 */ 765 766 #define SCANSIZE 8192 767 768 static int 769 verify(struct params *p, int fd) 770 { 771 772 switch (p->verify_method) { 773 case VERIFY_NONE: 774 return 0; 775 case VERIFY_DISKLABEL: 776 return verify_disklabel(fd); 777 case VERIFY_FFS: 778 return verify_ffs(fd); 779 case VERIFY_REENTER: 780 return verify_reenter(p); 781 case VERIFY_MBR: 782 return verify_mbr(fd); 783 case VERIFY_GPT: 784 return verify_gpt(fd); 785 default: 786 warnx("unimplemented verification method"); 787 return -1; 788 } 789 } 790 791 static int 792 verify_disklabel(int fd) 793 { 794 struct disklabel l; 795 ssize_t ret; 796 char buf[SCANSIZE]; 797 798 /* 799 * we simply scan the first few blocks for a disklabel, ignoring 800 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read 801 * a cgd, anyway, so it is unlikely that there will be non-native 802 * partition information. 803 */ 804 805 ret = prog_pread(fd, buf, SCANSIZE, 0); 806 if (ret < 0) { 807 warn("can't read disklabel area"); 808 return -1; 809 } 810 811 /* now scan for the disklabel */ 812 813 return disklabel_scan(&l, buf, (size_t)ret); 814 } 815 816 static int 817 verify_mbr(int fd) 818 { 819 struct mbr_sector mbr; 820 ssize_t ret; 821 char buf[SCANSIZE]; 822 823 /* 824 * we read the first blocks to avoid sector size issues and 825 * verify the MBR in the beginning 826 */ 827 828 ret = prog_pread(fd, buf, SCANSIZE, 0); 829 if (ret < 0) { 830 warn("can't read mbr area"); 831 return -1; 832 } 833 834 memcpy(&mbr, buf, sizeof(mbr)); 835 if (le16toh(mbr.mbr_magic) != MBR_MAGIC) 836 return 1; 837 838 return 0; 839 } 840 841 static uint32_t crc32_tab[] = { 842 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 843 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 844 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 845 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 846 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 847 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 848 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 849 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 850 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 851 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 852 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 853 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 854 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 855 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 856 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 857 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 858 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 859 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 860 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 861 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 862 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 863 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 864 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 865 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 866 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 867 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 868 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 869 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 870 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 871 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 872 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 873 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 874 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 875 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 876 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 877 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 878 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 879 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 880 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 881 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 882 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 883 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 884 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 885 }; 886 887 static uint32_t 888 crc32(const void *buf, size_t size) 889 { 890 const uint8_t *p; 891 uint32_t crc; 892 893 p = buf; 894 crc = ~0U; 895 896 while (size--) 897 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 898 899 return crc ^ ~0U; 900 } 901 902 static int 903 verify_gpt(int fd) 904 { 905 struct gpt_hdr hdr; 906 ssize_t ret; 907 char buf[SCANSIZE]; 908 unsigned blksize; 909 size_t off; 910 911 /* 912 * we read the first blocks to avoid sector size issues and 913 * verify the GPT header. 914 */ 915 916 ret = prog_pread(fd, buf, SCANSIZE, 0); 917 if (ret < 0) { 918 warn("can't read gpt area"); 919 return -1; 920 } 921 922 ret = 1; 923 for (blksize = DEV_BSIZE; 924 (off = (blksize * GPT_HDR_BLKNO)) <= SCANSIZE - sizeof(hdr); 925 blksize <<= 1) { 926 927 memcpy(&hdr, &buf[off], sizeof(hdr)); 928 if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0 929 && le32toh(hdr.hdr_revision) == GPT_HDR_REVISION 930 && le32toh(hdr.hdr_size) == GPT_HDR_SIZE) { 931 932 hdr.hdr_crc_self = 0; 933 if (crc32(&hdr, sizeof(hdr))) { 934 ret = 0; 935 break; 936 } 937 } 938 } 939 940 return ret; 941 } 942 943 static off_t sblock_try[] = SBLOCKSEARCH; 944 945 static int 946 verify_ffs(int fd) 947 { 948 size_t i; 949 950 for (i = 0; sblock_try[i] != -1; i++) { 951 union { 952 char buf[SBLOCKSIZE]; 953 struct fs fs; 954 } u; 955 ssize_t ret; 956 957 ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]); 958 if (ret < 0) { 959 warn("pread"); 960 break; 961 } else if ((size_t)ret < sizeof(u)) { 962 warnx("pread: incomplete block"); 963 break; 964 } 965 switch (u.fs.fs_magic) { 966 case FS_UFS1_MAGIC: 967 case FS_UFS2_MAGIC: 968 case FS_UFS1_MAGIC_SWAPPED: 969 case FS_UFS2_MAGIC_SWAPPED: 970 return 0; 971 default: 972 continue; 973 } 974 } 975 976 return 1; /* failure */ 977 } 978 979 static int 980 verify_reenter(struct params *p) 981 { 982 struct keygen *kg; 983 bits_t *orig_key, *key; 984 int ret; 985 986 ret = 0; 987 for (kg = p->keygen; kg && !ret; kg = kg->next) { 988 if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) && 989 (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD )) 990 continue; 991 992 orig_key = kg->kg_key; 993 kg->kg_key = NULL; 994 995 /* add a compat flag till the _OLD method goes away */ 996 key = getkey_pkcs5_pbkdf2("re-enter device", kg, 997 bits_len(orig_key), 998 kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD); 999 1000 ret = !bits_match(key, orig_key); 1001 1002 bits_free(key); 1003 bits_free(kg->kg_key); 1004 kg->kg_key = orig_key; 1005 } 1006 1007 return ret; 1008 } 1009 1010 static int 1011 generate(struct params *p, int argc, char **argv, const char *outfile) 1012 { 1013 int ret; 1014 1015 if (argc < 1 || argc > 2) 1016 usage(); 1017 1018 p->algorithm = string_fromcharstar(argv[0]); 1019 if (argc > 1) { 1020 size_t keylen; 1021 1022 if (parse_size_t(argv[1], &keylen) == -1) { 1023 warn("Failed to parse key length"); 1024 return -1; 1025 } 1026 p->keylen = keylen; 1027 } 1028 1029 ret = params_filldefaults(p); 1030 if (ret) 1031 return ret; 1032 1033 if (!p->keygen) { 1034 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 1035 if (!p->keygen) 1036 return -1; 1037 } 1038 1039 if (keygen_filldefaults(p->keygen, p->keylen)) { 1040 warnx("Failed to generate defaults for keygen"); 1041 return -1; 1042 } 1043 1044 if (!params_verify(p)) { 1045 warnx("invalid parameters generated"); 1046 return -1; 1047 } 1048 1049 return params_cput(p, outfile); 1050 } 1051 1052 static int 1053 generate_convert(struct params *p, int argc, char **argv, const char *outfile) 1054 { 1055 struct params *oldp; 1056 struct keygen *kg; 1057 1058 if (argc != 1) 1059 usage(); 1060 1061 oldp = params_cget(*argv); 1062 if (!oldp) 1063 return -1; 1064 1065 /* for sanity, we ensure that none of the keygens are randomkey */ 1066 for (kg=p->keygen; kg; kg=kg->next) 1067 if ((kg->kg_method == KEYGEN_RANDOMKEY) || 1068 (kg->kg_method == KEYGEN_URANDOMKEY)) { 1069 warnx("can't preserve randomly generated key"); 1070 goto bail; 1071 } 1072 for (kg=oldp->keygen; kg; kg=kg->next) 1073 if ((kg->kg_method == KEYGEN_RANDOMKEY) || 1074 (kg->kg_method == KEYGEN_URANDOMKEY)) { 1075 warnx("can't preserve randomly generated key"); 1076 goto bail; 1077 } 1078 1079 if (!params_verify(oldp)) { 1080 warnx("invalid old parameters file \"%s\"", *argv); 1081 return -1; 1082 } 1083 1084 oldp->key = getkey("old file", oldp->keygen, oldp->keylen); 1085 1086 /* we copy across the non-keygen info, here. */ 1087 1088 string_free(p->algorithm); 1089 string_free(p->ivmeth); 1090 1091 p->algorithm = string_dup(oldp->algorithm); 1092 p->ivmeth = string_dup(oldp->ivmeth); 1093 p->keylen = oldp->keylen; 1094 p->bsize = oldp->bsize; 1095 if (p->verify_method == VERIFY_UNKNOWN) 1096 p->verify_method = oldp->verify_method; 1097 1098 params_free(oldp); 1099 1100 if (!p->keygen) { 1101 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 1102 if (!p->keygen) 1103 return -1; 1104 } 1105 (void)params_filldefaults(p); 1106 (void)keygen_filldefaults(p->keygen, p->keylen); 1107 p->key = getkey("new file", p->keygen, p->keylen); 1108 1109 kg = keygen_generate(KEYGEN_STOREDKEY); 1110 kg->kg_key = bits_xor(p->key, oldp->key); 1111 keygen_addlist(&p->keygen, kg); 1112 1113 if (!params_verify(p)) { 1114 warnx("can't generate new parameters file"); 1115 return -1; 1116 } 1117 1118 return params_cput(p, outfile); 1119 bail:; 1120 params_free(oldp); 1121 return -1; 1122 } 1123 1124 static int 1125 /*ARGSUSED*/ 1126 do_all(const char *cfile, int argc, char **argv, 1127 int (*conf)(int, char **, struct params *, int)) 1128 { 1129 FILE *f; 1130 size_t len; 1131 size_t lineno; 1132 int my_argc; 1133 int ret; 1134 const char *fn; 1135 char *line; 1136 char **my_argv; 1137 1138 if (argc > 0) 1139 usage(); 1140 1141 if (!cfile[0]) 1142 fn = CGDCONFIG_CFILE; 1143 else 1144 fn = cfile; 1145 1146 f = fopen(fn, "r"); 1147 if (f == NULL) { 1148 warn("could not open config file \"%s\"", fn); 1149 return -1; 1150 } 1151 1152 ret = 0; 1153 lineno = 0; 1154 for (;;) { 1155 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL); 1156 if (!line) 1157 break; 1158 if (!*line) 1159 continue; 1160 1161 my_argv = words(line, &my_argc); 1162 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL); 1163 if (ret) { 1164 warnx("action failed on \"%s\" line %lu", fn, 1165 (u_long)lineno); 1166 break; 1167 } 1168 words_free(my_argv, my_argc); 1169 } 1170 return ret; 1171 } 1172 1173 static const char * 1174 iv_method(int mode) 1175 { 1176 1177 switch (mode) { 1178 case CGD_CIPHER_CBC_ENCBLKNO8: 1179 return "encblkno8"; 1180 case CGD_CIPHER_CBC_ENCBLKNO1: 1181 return "encblkno1"; 1182 default: 1183 return "unknown"; 1184 } 1185 } 1186 1187 1188 static void 1189 show(const char *dev) { 1190 char path[64]; 1191 struct cgd_user cgu; 1192 int fd; 1193 1194 fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0); 1195 if (fd == -1) { 1196 warn("open: %s", dev); 1197 return; 1198 } 1199 1200 cgu.cgu_unit = -1; 1201 if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) { 1202 close(fd); 1203 err(1, "CGDIOCGET"); 1204 } 1205 1206 printf("%s: ", dev); 1207 1208 if (cgu.cgu_dev == 0) { 1209 printf("not in use"); 1210 goto out; 1211 } 1212 1213 dev = devname(cgu.cgu_dev, S_IFBLK); 1214 if (dev != NULL) 1215 printf("%s ", dev); 1216 else 1217 printf("dev %llu,%llu ", (unsigned long long)major(cgu.cgu_dev), 1218 (unsigned long long)minor(cgu.cgu_dev)); 1219 1220 if (verbose) 1221 printf("%s ", cgu.cgu_alg); 1222 if (verbose > 1) { 1223 printf("keylen %d ", cgu.cgu_keylen); 1224 printf("blksize %zd ", cgu.cgu_blocksize); 1225 printf("%s ", iv_method(cgu.cgu_mode)); 1226 } 1227 1228 out:; 1229 putchar('\n'); 1230 close(fd); 1231 } 1232 1233 static int 1234 do_list(int argc, char **argv) 1235 { 1236 1237 if (argc != 0 && argc != 1) 1238 usage(); 1239 1240 if (argc) { 1241 show(argv[0]); 1242 return 0; 1243 } 1244 1245 DIR *dirp; 1246 struct dirent *dp; 1247 __BITMAP_TYPE(, uint32_t, 65536) bm; 1248 1249 __BITMAP_ZERO(&bm); 1250 1251 if ((dirp = opendir(_PATH_DEV)) == NULL) 1252 err(1, "opendir: %s", _PATH_DEV); 1253 1254 while ((dp = readdir(dirp)) != NULL) { 1255 char *ep; 1256 if (strncmp(dp->d_name, "rcgd", 4) != 0) 1257 continue; 1258 errno = 0; 1259 int n = (int)strtol(dp->d_name + 4, &ep, 0); 1260 if (ep == dp->d_name + 4 || errno != 0) { 1261 warnx("bad name %s", dp->d_name); 1262 continue; 1263 } 1264 *ep = '\0'; 1265 if (__BITMAP_ISSET(n, &bm)) 1266 continue; 1267 __BITMAP_SET(n, &bm); 1268 show(dp->d_name + 1); 1269 } 1270 1271 closedir(dirp); 1272 return 0; 1273 } 1274 1275 static void 1276 eliminate_cores(void) 1277 { 1278 struct rlimit rlp; 1279 1280 rlp.rlim_cur = 0; 1281 rlp.rlim_max = 0; 1282 if (setrlimit(RLIMIT_CORE, &rlp) == -1) 1283 err(EXIT_FAILURE, "Can't disable cores"); 1284 } 1285