1 /* $NetBSD: cgdconfig.c,v 1.52 2021/06/16 23:22:08 riastradh 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.52 2021/06/16 23:22:08 riastradh 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 [-v] [-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 int status; 464 465 if ((f = popen(string_tocharstar(kg->kg_cmd), "r")) == NULL) 466 errx(1, "command failed"); 467 if ((ret = bits_fget(f, keylen)) == NULL) 468 errx(1, "command output too short"); 469 if ((status = pclose(f)) != 0) 470 err(1, "command failed with status %d", status); 471 472 return ret; 473 } 474 475 /*ARGSUSED*/ 476 static int 477 unconfigure(int argc, char **argv, struct params *inparams, int flags) 478 { 479 int fd; 480 int ret; 481 char buf[MAXPATHLEN] = ""; 482 483 /* only complain about additional arguments, if called from main() */ 484 if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1) 485 usage(); 486 487 /* if called from do_all(), then ensure that 2 or 3 args exist */ 488 if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3)) 489 return -1; 490 491 fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, prog_open); 492 if (fd == -1) { 493 int saved_errno = errno; 494 495 warn("can't open cgd \"%s\", \"%s\"", *argv, buf); 496 497 /* this isn't fatal with nflag != 0 */ 498 if (!nflag) 499 return saved_errno; 500 } 501 502 VPRINTF(1, ("%s (%s): clearing\n", *argv, buf)); 503 504 if (nflag) 505 return 0; 506 507 ret = unconfigure_fd(fd); 508 (void)prog_close(fd); 509 return ret; 510 } 511 512 static int 513 unconfigure_fd(int fd) 514 { 515 struct cgd_ioctl ci; 516 517 if (prog_ioctl(fd, CGDIOCCLR, &ci) == -1) { 518 warn("ioctl"); 519 return -1; 520 } 521 522 return 0; 523 } 524 525 /*ARGSUSED*/ 526 static int 527 configure(int argc, char **argv, struct params *inparams, int flags) 528 { 529 struct params *p; 530 struct keygen *kg; 531 int fd; 532 int loop = 0; 533 int ret; 534 char cgdname[PATH_MAX]; 535 char devicename[PATH_MAX]; 536 const char *dev = NULL; /* XXX: gcc */ 537 538 if (argc < 2 || argc > 3) { 539 /* print usage and exit, only if called from main() */ 540 if (flags == CONFIG_FLAGS_FROMMAIN) { 541 warnx("wrong number of args"); 542 usage(); 543 } 544 return -1; 545 } 546 547 if (( 548 fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open) 549 ) != -1) { 550 struct cgd_user cgu; 551 552 cgu.cgu_unit = -1; 553 if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) { 554 warnx("device %s already in use", *argv); 555 prog_close(fd); 556 return -1; 557 } 558 prog_close(fd); 559 } 560 561 dev = getfsspecname(devicename, sizeof(devicename), argv[1]); 562 if (dev == NULL) { 563 warnx("getfsspecname failed: %s", devicename); 564 return -1; 565 } 566 567 if (argc == 2) { 568 char pfile[MAXPATHLEN]; 569 570 /* make string writable for basename */ 571 strlcpy(pfile, dev, sizeof(pfile)); 572 p = params_cget(basename(pfile)); 573 } else 574 p = params_cget(argv[2]); 575 576 if (!p) 577 return -1; 578 579 /* 580 * over-ride with command line specifications and fill in default 581 * values. 582 */ 583 584 p = params_combine(p, inparams); 585 ret = params_filldefaults(p); 586 if (ret) { 587 params_free(p); 588 return ret; 589 } 590 591 if (!params_verify(p)) { 592 warnx("params invalid"); 593 return -1; 594 } 595 596 /* 597 * loop over configuring the disk and checking to see if it 598 * verifies properly. We open and close the disk device each 599 * time, because if the user passes us the block device we 600 * need to flush the buffer cache. 601 * 602 * We only loop if one of the verification methods prompts for 603 * a password. 604 */ 605 606 for (kg = p->keygen; 607 (pflag & PFLAG_GETPASS_MASK) && kg; 608 kg = kg->next) 609 if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) || 610 (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) { 611 loop = 1; 612 break; 613 } 614 615 for (;;) { 616 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 617 if (fd == -1) 618 return -1; 619 620 if (p->key) 621 bits_free(p->key); 622 623 p->key = getkey(argv[1], p->keygen, p->keylen); 624 if (!p->key) 625 goto bail_err; 626 627 ret = configure_params(fd, cgdname, dev, p); 628 if (ret) 629 goto bail_err; 630 631 ret = verify(p, fd); 632 if (ret == -1) { 633 (void)unconfigure_fd(fd); 634 goto bail_err; 635 } 636 if (ret == 0) /* success */ 637 break; 638 639 (void)unconfigure_fd(fd); 640 (void)prog_close(fd); 641 642 if (!loop) { 643 warnx("verification failed permanently"); 644 goto bail_err; 645 } 646 647 warnx("verification failed, please reenter passphrase"); 648 } 649 650 params_free(p); 651 (void)prog_close(fd); 652 return 0; 653 654 bail_err:; 655 params_free(p); 656 (void)prog_close(fd); 657 return -1; 658 } 659 660 static int 661 configure_stdin(struct params *p, int argc, char **argv) 662 { 663 int fd; 664 int ret; 665 char cgdname[PATH_MAX]; 666 char devicename[PATH_MAX]; 667 const char *dev; 668 669 if (argc < 3 || argc > 4) 670 usage(); 671 672 dev = getfsspecname(devicename, sizeof(devicename), argv[1]); 673 if (dev == NULL) { 674 warnx("getfsspecname failed: %s", devicename); 675 return -1; 676 } 677 678 p->algorithm = string_fromcharstar(argv[2]); 679 if (argc > 3) { 680 size_t keylen; 681 682 if (parse_size_t(argv[3], &keylen) == -1) { 683 warn("failed to parse key length"); 684 return -1; 685 } 686 p->keylen = keylen; 687 } 688 689 ret = params_filldefaults(p); 690 if (ret) 691 return ret; 692 693 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 694 if (fd == -1) 695 return -1; 696 697 p->key = bits_fget(stdin, p->keylen); 698 if (!p->key) { 699 warnx("failed to read key from stdin"); 700 return -1; 701 } 702 703 return configure_params(fd, cgdname, dev, p); 704 } 705 706 static int 707 opendisk_werror(const char *cgd, char *buf, size_t buflen) 708 { 709 int fd; 710 711 VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd,buf,buflen)); 712 713 /* sanity */ 714 if (!cgd || !buf) 715 return -1; 716 717 if (nflag) { 718 if (strlcpy(buf, cgd, buflen) >= buflen) 719 return -1; 720 return 0; 721 } 722 723 fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open); 724 if (fd == -1) 725 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf); 726 727 return fd; 728 } 729 730 static int 731 configure_params(int fd, const char *cgd, const char *dev, struct params *p) 732 { 733 struct cgd_ioctl ci; 734 735 /* sanity */ 736 if (!cgd || !dev) 737 return -1; 738 739 (void)memset(&ci, 0x0, sizeof(ci)); 740 ci.ci_disk = dev; 741 ci.ci_alg = string_tocharstar(p->algorithm); 742 ci.ci_ivmethod = string_tocharstar(p->ivmeth); 743 ci.ci_key = bits_getbuf(p->key); 744 ci.ci_keylen = p->keylen; 745 ci.ci_blocksize = p->bsize; 746 747 VPRINTF(1, (" with alg %s keylen %zu blocksize %zu ivmethod %s\n", 748 string_tocharstar(p->algorithm), p->keylen, p->bsize, 749 string_tocharstar(p->ivmeth))); 750 VPRINTF(2, ("key: ")); 751 VERBOSE(2, bits_fprint(stdout, p->key)); 752 VPRINTF(2, ("\n")); 753 754 if (nflag) 755 return 0; 756 757 if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) { 758 int saved_errno = errno; 759 warn("ioctl"); 760 return saved_errno; 761 } 762 763 return 0; 764 } 765 766 /* 767 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry. 768 */ 769 770 #define SCANSIZE 8192 771 772 static int 773 verify(struct params *p, int fd) 774 { 775 776 switch (p->verify_method) { 777 case VERIFY_NONE: 778 return 0; 779 case VERIFY_DISKLABEL: 780 return verify_disklabel(fd); 781 case VERIFY_FFS: 782 return verify_ffs(fd); 783 case VERIFY_REENTER: 784 return verify_reenter(p); 785 case VERIFY_MBR: 786 return verify_mbr(fd); 787 case VERIFY_GPT: 788 return verify_gpt(fd); 789 default: 790 warnx("unimplemented verification method"); 791 return -1; 792 } 793 } 794 795 static int 796 verify_disklabel(int fd) 797 { 798 struct disklabel l; 799 ssize_t ret; 800 char buf[SCANSIZE]; 801 802 /* 803 * we simply scan the first few blocks for a disklabel, ignoring 804 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read 805 * a cgd, anyway, so it is unlikely that there will be non-native 806 * partition information. 807 */ 808 809 ret = prog_pread(fd, buf, SCANSIZE, 0); 810 if (ret < 0) { 811 warn("can't read disklabel area"); 812 return -1; 813 } 814 815 /* now scan for the disklabel */ 816 817 return disklabel_scan(&l, buf, (size_t)ret); 818 } 819 820 static int 821 verify_mbr(int fd) 822 { 823 struct mbr_sector mbr; 824 ssize_t ret; 825 char buf[SCANSIZE]; 826 827 /* 828 * we read the first blocks to avoid sector size issues and 829 * verify the MBR in the beginning 830 */ 831 832 ret = prog_pread(fd, buf, SCANSIZE, 0); 833 if (ret < 0) { 834 warn("can't read mbr area"); 835 return -1; 836 } 837 838 memcpy(&mbr, buf, sizeof(mbr)); 839 if (le16toh(mbr.mbr_magic) != MBR_MAGIC) 840 return 1; 841 842 return 0; 843 } 844 845 static uint32_t crc32_tab[] = { 846 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 847 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 848 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 849 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 850 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 851 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 852 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 853 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 854 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 855 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 856 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 857 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 858 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 859 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 860 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 861 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 862 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 863 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 864 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 865 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 866 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 867 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 868 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 869 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 870 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 871 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 872 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 873 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 874 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 875 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 876 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 877 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 878 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 879 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 880 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 881 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 882 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 883 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 884 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 885 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 886 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 887 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 888 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 889 }; 890 891 static uint32_t 892 crc32(const void *buf, size_t size) 893 { 894 const uint8_t *p; 895 uint32_t crc; 896 897 p = buf; 898 crc = ~0U; 899 900 while (size--) 901 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 902 903 return crc ^ ~0U; 904 } 905 906 static int 907 verify_gpt(int fd) 908 { 909 struct gpt_hdr hdr; 910 ssize_t ret; 911 char buf[SCANSIZE]; 912 unsigned blksize; 913 size_t off; 914 915 /* 916 * we read the first blocks to avoid sector size issues and 917 * verify the GPT header. 918 */ 919 920 ret = prog_pread(fd, buf, SCANSIZE, 0); 921 if (ret < 0) { 922 warn("can't read gpt area"); 923 return -1; 924 } 925 926 ret = 1; 927 for (blksize = DEV_BSIZE; 928 (off = (blksize * GPT_HDR_BLKNO)) <= SCANSIZE - sizeof(hdr); 929 blksize <<= 1) { 930 931 memcpy(&hdr, &buf[off], sizeof(hdr)); 932 if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0 933 && le32toh(hdr.hdr_revision) == GPT_HDR_REVISION 934 && le32toh(hdr.hdr_size) == GPT_HDR_SIZE) { 935 936 hdr.hdr_crc_self = 0; 937 if (crc32(&hdr, sizeof(hdr))) { 938 ret = 0; 939 break; 940 } 941 } 942 } 943 944 return ret; 945 } 946 947 static off_t sblock_try[] = SBLOCKSEARCH; 948 949 static int 950 verify_ffs(int fd) 951 { 952 size_t i; 953 954 for (i = 0; sblock_try[i] != -1; i++) { 955 union { 956 char buf[SBLOCKSIZE]; 957 struct fs fs; 958 } u; 959 ssize_t ret; 960 961 ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]); 962 if (ret < 0) { 963 warn("pread"); 964 break; 965 } else if ((size_t)ret < sizeof(u)) { 966 warnx("pread: incomplete block"); 967 break; 968 } 969 switch (u.fs.fs_magic) { 970 case FS_UFS1_MAGIC: 971 case FS_UFS2_MAGIC: 972 case FS_UFS1_MAGIC_SWAPPED: 973 case FS_UFS2_MAGIC_SWAPPED: 974 return 0; 975 default: 976 continue; 977 } 978 } 979 980 return 1; /* failure */ 981 } 982 983 static int 984 verify_reenter(struct params *p) 985 { 986 struct keygen *kg; 987 bits_t *orig_key, *key; 988 int ret; 989 990 ret = 0; 991 for (kg = p->keygen; kg && !ret; kg = kg->next) { 992 if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) && 993 (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD )) 994 continue; 995 996 orig_key = kg->kg_key; 997 kg->kg_key = NULL; 998 999 /* add a compat flag till the _OLD method goes away */ 1000 key = getkey_pkcs5_pbkdf2("re-enter device", kg, 1001 bits_len(orig_key), 1002 kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD); 1003 1004 ret = !bits_match(key, orig_key); 1005 1006 bits_free(key); 1007 bits_free(kg->kg_key); 1008 kg->kg_key = orig_key; 1009 } 1010 1011 return ret; 1012 } 1013 1014 static int 1015 generate(struct params *p, int argc, char **argv, const char *outfile) 1016 { 1017 int ret; 1018 1019 if (argc < 1 || argc > 2) 1020 usage(); 1021 1022 p->algorithm = string_fromcharstar(argv[0]); 1023 if (argc > 1) { 1024 size_t keylen; 1025 1026 if (parse_size_t(argv[1], &keylen) == -1) { 1027 warn("Failed to parse key length"); 1028 return -1; 1029 } 1030 p->keylen = keylen; 1031 } 1032 1033 ret = params_filldefaults(p); 1034 if (ret) 1035 return ret; 1036 1037 if (!p->keygen) { 1038 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 1039 if (!p->keygen) 1040 return -1; 1041 } 1042 1043 if (keygen_filldefaults(p->keygen, p->keylen)) { 1044 warnx("Failed to generate defaults for keygen"); 1045 return -1; 1046 } 1047 1048 if (!params_verify(p)) { 1049 warnx("invalid parameters generated"); 1050 return -1; 1051 } 1052 1053 return params_cput(p, outfile); 1054 } 1055 1056 static int 1057 generate_convert(struct params *p, int argc, char **argv, const char *outfile) 1058 { 1059 struct params *oldp; 1060 struct keygen *kg; 1061 1062 if (argc != 1) 1063 usage(); 1064 1065 oldp = params_cget(*argv); 1066 if (!oldp) 1067 return -1; 1068 1069 /* for sanity, we ensure that none of the keygens are randomkey */ 1070 for (kg=p->keygen; kg; kg=kg->next) 1071 if ((kg->kg_method == KEYGEN_RANDOMKEY) || 1072 (kg->kg_method == KEYGEN_URANDOMKEY)) { 1073 warnx("can't preserve randomly generated key"); 1074 goto bail; 1075 } 1076 for (kg=oldp->keygen; kg; kg=kg->next) 1077 if ((kg->kg_method == KEYGEN_RANDOMKEY) || 1078 (kg->kg_method == KEYGEN_URANDOMKEY)) { 1079 warnx("can't preserve randomly generated key"); 1080 goto bail; 1081 } 1082 1083 if (!params_verify(oldp)) { 1084 warnx("invalid old parameters file \"%s\"", *argv); 1085 return -1; 1086 } 1087 1088 oldp->key = getkey("old file", oldp->keygen, oldp->keylen); 1089 1090 /* we copy across the non-keygen info, here. */ 1091 1092 string_free(p->algorithm); 1093 string_free(p->ivmeth); 1094 1095 p->algorithm = string_dup(oldp->algorithm); 1096 p->ivmeth = string_dup(oldp->ivmeth); 1097 p->keylen = oldp->keylen; 1098 p->bsize = oldp->bsize; 1099 if (p->verify_method == VERIFY_UNKNOWN) 1100 p->verify_method = oldp->verify_method; 1101 1102 params_free(oldp); 1103 1104 if (!p->keygen) { 1105 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 1106 if (!p->keygen) 1107 return -1; 1108 } 1109 (void)params_filldefaults(p); 1110 (void)keygen_filldefaults(p->keygen, p->keylen); 1111 p->key = getkey("new file", p->keygen, p->keylen); 1112 1113 kg = keygen_generate(KEYGEN_STOREDKEY); 1114 kg->kg_key = bits_xor(p->key, oldp->key); 1115 keygen_addlist(&p->keygen, kg); 1116 1117 if (!params_verify(p)) { 1118 warnx("can't generate new parameters file"); 1119 return -1; 1120 } 1121 1122 return params_cput(p, outfile); 1123 bail:; 1124 params_free(oldp); 1125 return -1; 1126 } 1127 1128 static int 1129 /*ARGSUSED*/ 1130 do_all(const char *cfile, int argc, char **argv, 1131 int (*conf)(int, char **, struct params *, int)) 1132 { 1133 FILE *f; 1134 size_t len; 1135 size_t lineno; 1136 int my_argc; 1137 int ret; 1138 const char *fn; 1139 char *line; 1140 char **my_argv; 1141 1142 if (argc > 0) 1143 usage(); 1144 1145 if (!cfile[0]) 1146 fn = CGDCONFIG_CFILE; 1147 else 1148 fn = cfile; 1149 1150 f = fopen(fn, "r"); 1151 if (f == NULL) { 1152 warn("could not open config file \"%s\"", fn); 1153 return -1; 1154 } 1155 1156 ret = 0; 1157 lineno = 0; 1158 for (;;) { 1159 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL); 1160 if (!line) 1161 break; 1162 if (!*line) 1163 continue; 1164 1165 my_argv = words(line, &my_argc); 1166 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL); 1167 if (ret) { 1168 warnx("action failed on \"%s\" line %lu", fn, 1169 (u_long)lineno); 1170 break; 1171 } 1172 words_free(my_argv, my_argc); 1173 } 1174 return ret; 1175 } 1176 1177 static const char * 1178 iv_method(int mode) 1179 { 1180 1181 switch (mode) { 1182 case CGD_CIPHER_CBC_ENCBLKNO8: 1183 return "encblkno8"; 1184 case CGD_CIPHER_CBC_ENCBLKNO1: 1185 return "encblkno1"; 1186 default: 1187 return "unknown"; 1188 } 1189 } 1190 1191 1192 static void 1193 show(const char *dev) { 1194 char path[64]; 1195 struct cgd_user cgu; 1196 int fd; 1197 1198 fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0); 1199 if (fd == -1) { 1200 warn("open: %s", dev); 1201 return; 1202 } 1203 1204 cgu.cgu_unit = -1; 1205 if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) { 1206 close(fd); 1207 err(1, "CGDIOCGET"); 1208 } 1209 1210 printf("%s: ", dev); 1211 1212 if (cgu.cgu_dev == 0) { 1213 printf("not in use"); 1214 goto out; 1215 } 1216 1217 dev = devname(cgu.cgu_dev, S_IFBLK); 1218 if (dev != NULL) 1219 printf("%s ", dev); 1220 else 1221 printf("dev %llu,%llu ", (unsigned long long)major(cgu.cgu_dev), 1222 (unsigned long long)minor(cgu.cgu_dev)); 1223 1224 if (verbose) 1225 printf("%s ", cgu.cgu_alg); 1226 if (verbose > 1) { 1227 printf("keylen %d ", cgu.cgu_keylen); 1228 printf("blksize %zd ", cgu.cgu_blocksize); 1229 printf("%s ", iv_method(cgu.cgu_mode)); 1230 } 1231 1232 out:; 1233 putchar('\n'); 1234 close(fd); 1235 } 1236 1237 static int 1238 do_list(int argc, char **argv) 1239 { 1240 1241 if (argc != 0 && argc != 1) 1242 usage(); 1243 1244 if (argc) { 1245 show(argv[0]); 1246 return 0; 1247 } 1248 1249 DIR *dirp; 1250 struct dirent *dp; 1251 __BITMAP_TYPE(, uint32_t, 65536) bm; 1252 1253 __BITMAP_ZERO(&bm); 1254 1255 if ((dirp = opendir(_PATH_DEV)) == NULL) 1256 err(1, "opendir: %s", _PATH_DEV); 1257 1258 while ((dp = readdir(dirp)) != NULL) { 1259 char *ep; 1260 if (strncmp(dp->d_name, "rcgd", 4) != 0) 1261 continue; 1262 errno = 0; 1263 int n = (int)strtol(dp->d_name + 4, &ep, 0); 1264 if (ep == dp->d_name + 4 || errno != 0) { 1265 warnx("bad name %s", dp->d_name); 1266 continue; 1267 } 1268 *ep = '\0'; 1269 if (__BITMAP_ISSET(n, &bm)) 1270 continue; 1271 __BITMAP_SET(n, &bm); 1272 show(dp->d_name + 1); 1273 } 1274 1275 closedir(dirp); 1276 return 0; 1277 } 1278 1279 static void 1280 eliminate_cores(void) 1281 { 1282 struct rlimit rlp; 1283 1284 rlp.rlim_cur = 0; 1285 rlp.rlim_max = 0; 1286 if (setrlimit(RLIMIT_CORE, &rlp) == -1) 1287 err(EXIT_FAILURE, "Can't disable cores"); 1288 } 1289