1/* $NetBSD: cgdconfig.c,v 1.63 2024/05/12 18:02:16 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.63 2024/05/12 18:02:16 christos Exp $"); 37#endif 38 39#ifdef HAVE_ARGON2 40#include <argon2.h> 41#endif 42#include <assert.h> 43#include <err.h> 44#include <errno.h> 45#include <fcntl.h> 46#include <libgen.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <unistd.h> 51#include <util.h> 52#include <paths.h> 53#include <dirent.h> 54 55/* base64 gunk */ 56#include <netinet/in.h> 57#include <arpa/nameser.h> 58#include <resolv.h> 59 60#include <sys/ioctl.h> 61#include <sys/stat.h> 62#include <sys/bootblock.h> 63#include <sys/disklabel.h> 64#include <sys/disklabel_gpt.h> 65#include <sys/mman.h> 66#include <sys/param.h> 67#include <sys/resource.h> 68#include <sys/statvfs.h> 69#include <sys/bitops.h> 70#include <sys/queue.h> 71 72#include <dev/cgdvar.h> 73 74#include <ufs/ffs/fs.h> 75 76#ifdef HAVE_ZFS 77#include <sys/vdev_impl.h> 78#include <sha2.h> 79#endif 80 81#include "params.h" 82#include "pkcs5_pbkdf2.h" 83#include "utils.h" 84#include "cgdconfig.h" 85#include "prog_ops.h" 86#include "hkdf_hmac_sha256.h" 87 88#define CGDCONFIG_CFILE CGDCONFIG_DIR "/cgd.conf" 89 90enum action { 91 ACTION_DEFAULT, /* default -> configure */ 92 ACTION_CONFIGURE, /* configure, with paramsfile */ 93 ACTION_UNCONFIGURE, /* unconfigure */ 94 ACTION_GENERATE, /* generate a paramsfile */ 95 ACTION_GENERATE_CONVERT, /* generate a ``dup'' paramsfile */ 96 ACTION_CONFIGALL, /* configure all from config file */ 97 ACTION_UNCONFIGALL, /* unconfigure all from config file */ 98 ACTION_CONFIGSTDIN, /* configure, key from stdin */ 99 ACTION_LIST, /* list configured devices */ 100 ACTION_PRINTKEY, /* print key to stdout */ 101 ACTION_PRINTALLKEYS, /* print all keys to stdout */ 102}; 103 104/* if nflag is set, do not configure/unconfigure the cgd's */ 105 106static int nflag = 0; 107 108/* if Sflag is set, generate shared keys */ 109 110static int Sflag = 0; 111 112/* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */ 113 114#define PFLAG_GETPASS 0x01 115#define PFLAG_GETPASS_ECHO 0x02 116#define PFLAG_GETPASS_MASK 0x03 117#define PFLAG_STDIN 0x04 118static int pflag = PFLAG_GETPASS; 119 120/* 121 * When configuring all cgds, save a cache of shared keys for key 122 * derivation. If the _first_ verification with a shared key fails, we 123 * chuck it and start over; if _subsequent_ verifications fail, we 124 * assume the disk is wrong and give up on it immediately. 125 */ 126 127struct sharedkey { 128 int alg; 129 string_t *id; 130 bits_t *key; 131 LIST_ENTRY(sharedkey) list; 132 SLIST_ENTRY(sharedkey) used; 133 int verified; 134}; 135static LIST_HEAD(, sharedkey) sharedkeys; 136SLIST_HEAD(sharedkeyhits, sharedkey); 137 138static int configure(int, char **, struct params *, int); 139static int configure_stdin(struct params *, int argc, char **); 140static int generate(struct params *, int, char **, const char *, 141 const char *); 142static int generate_convert(struct params *, int, char **, const char *, 143 const char *); 144static int unconfigure(int, char **, struct params *, int); 145static int do_all(const char *, int, char **, 146 int (*)(int, char **, struct params *, int)); 147static int do_list(int, char **); 148static int printkey(const char *, const char *, const char *, ...) 149 __printflike(3,4); 150static int printkey1(int, char **, struct params *, int); 151static int do_printkey(int, char **); 152 153#define CONFIG_FLAGS_FROMALL 1 /* called from configure_all() */ 154#define CONFIG_FLAGS_FROMMAIN 2 /* called from main() */ 155 156static int configure_params(int, const char *, const char *, 157 struct params *); 158static void eliminate_cores(void); 159static bits_t *getkey(const char *, struct keygen *, size_t, 160 struct sharedkeyhits *); 161static bits_t *getkey_storedkey(const char *, struct keygen *, size_t); 162static bits_t *getkey_randomkey(const char *, struct keygen *, size_t, int); 163#ifdef HAVE_ARGON2 164static bits_t *getkey_argon2id(const char *, struct keygen *, size_t); 165#endif 166static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t, 167 int); 168static bits_t *getkey_shell_cmd(const char *, struct keygen *, size_t); 169static char *maybe_getpass(char *); 170static int opendisk_werror(const char *, char *, size_t); 171static int unconfigure_fd(int); 172static int verify(struct params *, int); 173static int verify_disklabel(int); 174static int verify_ffs(int); 175static int verify_reenter(struct params *); 176static int verify_mbr(int); 177static int verify_gpt(int); 178#ifdef HAVE_ZFS 179static int verify_zfs(int); 180#endif 181 182__dead static void usage(void); 183 184/* Verbose Framework */ 185static unsigned verbose = 0; 186 187#define VERBOSE(x,y) if (verbose >= x) y 188#define VPRINTF(x,y) if (verbose >= x) (void)printf y 189 190static void 191usage(void) 192{ 193 194 (void)fprintf(stderr, "usage: %s [-enpv] [-V vmeth] cgd dev " 195 "[paramsfile]\n", getprogname()); 196 (void)fprintf(stderr, " %s -C [-enpv] [-f configfile]\n", 197 getprogname()); 198 (void)fprintf(stderr, " %s -G [-enpSv] [-i ivmeth] [-k kgmeth] " 199 "[-P paramsfile] [-o outfile] paramsfile\n", getprogname()); 200 (void)fprintf(stderr, " %s -g [-Sv] [-i ivmeth] [-k kgmeth] " 201 "[-P paramsfile] [-o outfile] alg [keylen]\n", getprogname()); 202 (void)fprintf(stderr, " %s -l [-v[v]] [cgd]\n", getprogname()); 203 (void)fprintf(stderr, " %s -s [-nv] [-i ivmeth] cgd dev alg " 204 "[keylen]\n", getprogname()); 205 (void)fprintf(stderr, " %s -t paramsfile\n", getprogname()); 206 (void)fprintf(stderr, " %s -T [-f configfile]\n", getprogname()); 207 (void)fprintf(stderr, " %s -U [-nv] [-f configfile]\n", 208 getprogname()); 209 (void)fprintf(stderr, " %s -u [-nv] cgd\n", getprogname()); 210 exit(EXIT_FAILURE); 211} 212 213static int 214parse_size_t(const char *s, size_t *l) 215{ 216 char *endptr; 217 long v; 218 219 errno = 0; 220 v = strtol(s, &endptr, 10); 221 if ((v == LONG_MIN || v == LONG_MAX) && errno) 222 return -1; 223 if (v < INT_MIN || v > INT_MAX) { 224 errno = ERANGE; 225 return -1; 226 } 227 if (endptr == s) { 228 errno = EINVAL; 229 return -1; 230 } 231 *l = (size_t)v; 232 return 0; 233} 234 235static void 236set_action(enum action *action, enum action value) 237{ 238 if (*action != ACTION_DEFAULT) 239 usage(); 240 *action = value; 241} 242 243int 244main(int argc, char **argv) 245{ 246 struct params *p; 247 struct params *tp; 248 struct keygen *kg; 249 enum action action = ACTION_DEFAULT; 250 int ch; 251 const char *cfile = NULL; 252 const char *outfile = NULL; 253 const char *Pfile = NULL; 254 255 setprogname(*argv); 256 if (hkdf_hmac_sha256_selftest()) 257 err(EXIT_FAILURE, "Crypto self-test failed"); 258 eliminate_cores(); 259 if (mlockall(MCL_FUTURE)) 260 err(EXIT_FAILURE, "Can't lock memory"); 261 p = params_new(); 262 kg = NULL; 263 264 while ((ch = getopt(argc, argv, "CGP:STUV:b:ef:gi:k:lno:sptuv")) != -1) 265 switch (ch) { 266 case 'C': 267 set_action(&action, ACTION_CONFIGALL); 268 break; 269 case 'G': 270 set_action(&action, ACTION_GENERATE_CONVERT); 271 break; 272 case 'P': 273 if (Pfile) 274 usage(); 275 Pfile = estrdup(optarg); 276 break; 277 case 'S': 278 Sflag = 1; 279 break; 280 case 'T': 281 set_action(&action, ACTION_PRINTALLKEYS); 282 break; 283 case 'U': 284 set_action(&action, ACTION_UNCONFIGALL); 285 break; 286 case 'V': 287 tp = params_verify_method(string_fromcharstar(optarg)); 288 if (!tp) 289 usage(); 290 p = params_combine(p, tp); 291 break; 292 case 'b': 293 { 294 size_t size; 295 296 if (parse_size_t(optarg, &size) == -1) 297 usage(); 298 tp = params_bsize(size); 299 if (!tp) 300 usage(); 301 p = params_combine(p, tp); 302 } 303 break; 304 case 'e': 305 pflag = PFLAG_GETPASS_ECHO; 306 break; 307 case 'f': 308 if (cfile) 309 usage(); 310 cfile = estrdup(optarg); 311 break; 312 case 'g': 313 set_action(&action, ACTION_GENERATE); 314 break; 315 case 'i': 316 tp = params_ivmeth(string_fromcharstar(optarg)); 317 p = params_combine(p, tp); 318 break; 319 case 'k': 320 kg = keygen_method(string_fromcharstar(optarg)); 321 if (!kg) 322 usage(); 323 keygen_addlist(&p->keygen, kg); 324 break; 325 case 'l': 326 set_action(&action, ACTION_LIST); 327 break; 328 case 'n': 329 nflag = 1; 330 break; 331 case 'o': 332 if (outfile) 333 usage(); 334 outfile = estrdup(optarg); 335 break; 336 case 'p': 337 pflag = PFLAG_STDIN; 338 break; 339 case 's': 340 set_action(&action, ACTION_CONFIGSTDIN); 341 break; 342 case 't': 343 set_action(&action, ACTION_PRINTKEY); 344 break; 345 case 'u': 346 set_action(&action, ACTION_UNCONFIGURE); 347 break; 348 case 'v': 349 verbose++; 350 break; 351 default: 352 usage(); 353 /* NOTREACHED */ 354 } 355 356 argc -= optind; 357 argv += optind; 358 359 if (!outfile) 360 outfile = ""; 361 if (!cfile) 362 cfile = ""; 363 364 if (prog_init && prog_init() == -1) 365 err(1, "init failed"); 366 367 /* validate the consistency of the arguments */ 368 if (Pfile != NULL && 369 action != ACTION_GENERATE && 370 action != ACTION_GENERATE_CONVERT) { 371 warnx("-P is only for use with -g/-G action"); 372 usage(); 373 } 374 if (Pfile != NULL && !Sflag) { 375 warnx("-P only makes sense with -S flag"); 376 } 377 if (Sflag && 378 action != ACTION_GENERATE && 379 action != ACTION_GENERATE_CONVERT) { 380 warnx("-S is only for use with -g/-G action"); 381 usage(); 382 } 383 384 switch (action) { 385 case ACTION_DEFAULT: /* ACTION_CONFIGURE is the default */ 386 case ACTION_CONFIGURE: 387 return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN); 388 case ACTION_UNCONFIGURE: 389 return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN); 390 case ACTION_GENERATE: 391 return generate(p, argc, argv, outfile, Pfile); 392 case ACTION_GENERATE_CONVERT: 393 return generate_convert(p, argc, argv, outfile, Pfile); 394 case ACTION_CONFIGALL: 395 return do_all(cfile, argc, argv, configure); 396 case ACTION_UNCONFIGALL: 397 return do_all(cfile, argc, argv, unconfigure); 398 case ACTION_CONFIGSTDIN: 399 return configure_stdin(p, argc, argv); 400 case ACTION_LIST: 401 return do_list(argc, argv); 402 case ACTION_PRINTKEY: 403 return do_printkey(argc, argv); 404 case ACTION_PRINTALLKEYS: 405 return do_all(cfile, argc, argv, printkey1); 406 default: 407 errx(EXIT_FAILURE, "undefined action"); 408 /* NOTREACHED */ 409 } 410} 411 412static bits_t * 413getsubkey_hkdf_hmac_sha256(bits_t *key, bits_t *info, size_t subkeylen) 414{ 415 bits_t *ret = NULL; 416 uint8_t *tmp; 417 418 tmp = emalloc(BITS2BYTES(subkeylen)); 419 if (hkdf_hmac_sha256(tmp, BITS2BYTES(subkeylen), 420 bits_getbuf(key), BITS2BYTES(bits_len(key)), 421 bits_getbuf(info), BITS2BYTES(bits_len(info)))) { 422 warnx("failed to derive HKDF-HMAC-SHA256 subkey"); 423 goto out; 424 } 425 426 ret = bits_new(tmp, subkeylen); 427 428out: free(tmp); 429 return ret; 430} 431 432static bits_t * 433getsubkey(int alg, bits_t *key, bits_t *info, size_t subkeylen) 434{ 435 436 switch (alg) { 437 case SHARED_ALG_HKDF_HMAC_SHA256: 438 return getsubkey_hkdf_hmac_sha256(key, info, subkeylen); 439 default: 440 warnx("unrecognised shared key derivation method %d", alg); 441 return NULL; 442 } 443} 444 445static bits_t * 446getkey(const char *dev, struct keygen *kg, size_t len0, 447 struct sharedkeyhits *skh) 448{ 449 bits_t *ret = NULL; 450 bits_t *tmp; 451 452 VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len0)); 453 for (; kg; kg=kg->next) { 454 struct sharedkey *sk = NULL; 455 size_t len = len0; 456 457 /* 458 * If shared, determine the shared key's length and 459 * probe the cache of shared keys. 460 */ 461 if (kg->kg_sharedid) { 462 const char *id = string_tocharstar(kg->kg_sharedid); 463 464 len = kg->kg_sharedlen; 465 LIST_FOREACH(sk, &sharedkeys, list) { 466 if (kg->kg_sharedalg == sk->alg && 467 kg->kg_sharedlen == bits_len(sk->key) && 468 strcmp(id, string_tocharstar(sk->id)) == 0) 469 break; 470 } 471 if (sk) { 472 tmp = sk->key; 473 goto derive; 474 } 475 } 476 477 switch (kg->kg_method) { 478 case KEYGEN_STOREDKEY: 479 tmp = getkey_storedkey(dev, kg, len); 480 break; 481 case KEYGEN_RANDOMKEY: 482 tmp = getkey_randomkey(dev, kg, len, 1); 483 break; 484 case KEYGEN_URANDOMKEY: 485 tmp = getkey_randomkey(dev, kg, len, 0); 486 break; 487#ifdef HAVE_ARGON2 488 case KEYGEN_ARGON2ID: 489 tmp = getkey_argon2id(dev, kg, len); 490 break; 491#endif 492 case KEYGEN_PKCS5_PBKDF2_SHA1: 493 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0); 494 break; 495 /* provide backwards compatibility for old config files */ 496 case KEYGEN_PKCS5_PBKDF2_OLD: 497 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1); 498 break; 499 case KEYGEN_SHELL_CMD: 500 tmp = getkey_shell_cmd(dev, kg, len); 501 break; 502 default: 503 warnx("unrecognised keygen method %d in getkey()", 504 kg->kg_method); 505 if (ret) 506 bits_free(ret); 507 return NULL; 508 } 509 510 /* 511 * If shared, cache the key. 512 */ 513 if (kg->kg_sharedid) { 514 assert(sk == NULL); 515 sk = ecalloc(1, sizeof(*sk)); 516 sk->alg = kg->kg_sharedalg; 517 sk->id = string_dup(kg->kg_sharedid); 518 sk->key = tmp; 519 LIST_INSERT_HEAD(&sharedkeys, sk, list); 520 sk->verified = 0; 521 } 522 523derive: if (kg->kg_sharedid) { 524 assert(sk != NULL); 525 /* 526 * tmp holds the master key, owned by the 527 * struct sharedkey record; replace it by the 528 * derived subkey. 529 */ 530 tmp = getsubkey(kg->kg_sharedalg, tmp, 531 kg->kg_sharedinfo, len0); 532 if (tmp == NULL) { 533 if (ret) 534 bits_free(ret); 535 return NULL; 536 } 537 if (skh) 538 SLIST_INSERT_HEAD(skh, sk, used); 539 } 540 if (ret) 541 ret = bits_xor_d(tmp, ret); 542 else 543 ret = tmp; 544 } 545 546 return ret; 547} 548 549/*ARGSUSED*/ 550static bits_t * 551getkey_storedkey(const char *target, struct keygen *kg, size_t keylen) 552{ 553 return bits_dup(kg->kg_key); 554} 555 556/*ARGSUSED*/ 557static bits_t * 558getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard) 559{ 560 return bits_getrandombits(keylen, hard); 561} 562 563static char * 564maybe_getpass(char *prompt) 565{ 566 char buf[1024]; 567 char *p = NULL; 568 char *tmp, *pass; 569 570 switch (pflag) { 571 case PFLAG_GETPASS: 572 p = getpass_r(prompt, buf, sizeof(buf)); 573 break; 574 575 case PFLAG_GETPASS_ECHO: 576 p = getpassfd(prompt, buf, sizeof(buf), NULL, 577 GETPASS_ECHO|GETPASS_ECHO_NL|GETPASS_NEED_TTY, 0); 578 break; 579 580 case PFLAG_STDIN: 581 p = fgets(buf, sizeof(buf), stdin); 582 if (p) { 583 tmp = strchr(p, '\n'); 584 if (tmp) 585 *tmp = '\0'; 586 } 587 break; 588 589 default: 590 errx(EXIT_FAILURE, "pflag set inappropriately?"); 591 } 592 593 if (!p) 594 err(EXIT_FAILURE, "failed to read passphrase"); 595 596 pass = estrdup(p); 597 explicit_memset(buf, 0, sizeof(buf)); 598 599 return pass; 600} 601 602/*ARGSUSED*/ 603/* 604 * XXX take, and pass through, a compat flag that indicates whether we 605 * provide backwards compatibility with a previous bug. The previous 606 * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a 607 * non-zero compat flag. The new default, and correct keygen method is 608 * called pcks5_pbkdf2/sha1. When the old method is removed, so will 609 * be the compat argument. 610 */ 611static bits_t * 612getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen, 613 int compat) 614{ 615 bits_t *ret; 616 char *passp; 617 char buf[1024]; 618 u_int8_t *tmp; 619 620 snprintf(buf, sizeof(buf), "%s's passphrase%s:", target, 621 pflag & PFLAG_GETPASS_ECHO ? " (echo)" : ""); 622 passp = maybe_getpass(buf); 623 if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp, 624 strlen(passp), 625 bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)), 626 kg->kg_iterations, compat)) { 627 warnx("failed to generate PKCS#5 PBKDF2 key"); 628 return NULL; 629 } 630 631 ret = bits_new(tmp, keylen); 632 kg->kg_key = bits_dup(ret); 633 explicit_memset(passp, 0, strlen(passp)); 634 free(passp); 635 free(tmp); 636 return ret; 637} 638 639#ifdef HAVE_ARGON2 640static bits_t * 641getkey_argon2id(const char *target, struct keygen *kg, size_t keylen) 642{ 643 bits_t *ret; 644 char *passp; 645 char buf[1024]; 646 uint8_t raw[256]; 647 int error; 648 649 snprintf(buf, sizeof(buf), "%s's passphrase%s:", target, 650 pflag & PFLAG_GETPASS_ECHO ? " (echo)" : ""); 651 passp = maybe_getpass(buf); 652 if ((error = argon2_hash(kg->kg_iterations, kg->kg_memory, 653 kg->kg_parallelism, 654 passp, strlen(passp), 655 bits_getbuf(kg->kg_salt), 656 BITS2BYTES(bits_len(kg->kg_salt)), 657 raw, sizeof(raw), 658 NULL, 0, 659 Argon2_id, kg->kg_version)) != ARGON2_OK) { 660 warnx("failed to generate Argon2id key, error code %d", error); 661 return NULL; 662 } 663 664 ret = bits_new(raw, keylen); 665 kg->kg_key = bits_dup(ret); 666 explicit_memset(passp, 0, strlen(passp)); 667 explicit_memset(raw, 0, sizeof(raw)); 668 free(passp); 669 return ret; 670} 671#endif 672 673/*ARGSUSED*/ 674static bits_t * 675getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen) 676{ 677 FILE *f; 678 bits_t *ret; 679 int status; 680 681 if ((f = popen(string_tocharstar(kg->kg_cmd), "r")) == NULL) 682 errx(1, "command failed"); 683 if ((ret = bits_fget(f, keylen)) == NULL) 684 errx(1, "command output too short"); 685 if ((status = pclose(f)) != 0) 686 err(1, "command failed with status %d", status); 687 688 return ret; 689} 690 691/*ARGSUSED*/ 692static int 693unconfigure(int argc, char **argv, struct params *inparams, int flags) 694{ 695 int fd; 696 int ret; 697 char buf[MAXPATHLEN] = ""; 698 699 /* only complain about additional arguments, if called from main() */ 700 if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1) 701 usage(); 702 703 /* if called from do_all(), then ensure that 2 or 3 args exist */ 704 if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3)) 705 return -1; 706 707 fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, prog_open); 708 if (fd == -1) { 709 int saved_errno = errno; 710 711 warn("can't open cgd \"%s\", \"%s\"", *argv, buf); 712 713 /* this isn't fatal with nflag != 0 */ 714 if (!nflag) 715 return saved_errno; 716 } 717 718 VPRINTF(1, ("%s (%s): clearing\n", *argv, buf)); 719 720 if (nflag) 721 return 0; 722 723 ret = unconfigure_fd(fd); 724 (void)prog_close(fd); 725 return ret; 726} 727 728static int 729unconfigure_fd(int fd) 730{ 731 struct cgd_ioctl ci; 732 733 if (prog_ioctl(fd, CGDIOCCLR, &ci) == -1) { 734 warn("ioctl"); 735 return -1; 736 } 737 738 return 0; 739} 740 741/*ARGSUSED*/ 742static int 743configure(int argc, char **argv, struct params *inparams, int flags) 744{ 745 struct params *p; 746 struct keygen *kg; 747 int fd; 748 int loop = 0; 749 int ret; 750 char cgdname[PATH_MAX]; 751 char devicename[PATH_MAX]; 752 const char *dev = NULL; /* XXX: gcc */ 753 754 if (argc < 2 || argc > 3) { 755 /* print usage and exit, only if called from main() */ 756 if (flags == CONFIG_FLAGS_FROMMAIN) { 757 warnx("wrong number of args"); 758 usage(); 759 } 760 return -1; 761 } 762 763 if (( 764 fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open) 765 ) != -1) { 766 struct cgd_user cgu; 767 768 cgu.cgu_unit = -1; 769 if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) { 770 warnx("device %s already in use", *argv); 771 prog_close(fd); 772 return -1; 773 } 774 prog_close(fd); 775 } 776 777 dev = getfsspecname(devicename, sizeof(devicename), argv[1]); 778 if (dev == NULL) { 779 warnx("getfsspecname failed: %s", devicename); 780 return -1; 781 } 782 783 if (argc == 2) { 784 char pfile[MAXPATHLEN]; 785 786 /* make string writable for basename */ 787 strlcpy(pfile, dev, sizeof(pfile)); 788 p = params_cget(basename(pfile)); 789 } else 790 p = params_cget(argv[2]); 791 792 if (!p) 793 return -1; 794 795 /* 796 * over-ride with command line specifications and fill in default 797 * values. 798 */ 799 800 p = params_combine(p, inparams); 801 ret = params_filldefaults(p); 802 if (ret) { 803 params_free(p); 804 return ret; 805 } 806 807 if (!params_verify(p)) { 808 warnx("params invalid"); 809 return -1; 810 } 811 812 /* 813 * loop over configuring the disk and checking to see if it 814 * verifies properly. We open and close the disk device each 815 * time, because if the user passes us the block device we 816 * need to flush the buffer cache. 817 * 818 * We only loop if one of the verification methods prompts for 819 * a password. 820 */ 821 822 for (kg = p->keygen; 823 (pflag & PFLAG_GETPASS_MASK) && kg; 824 kg = kg->next) 825 if (kg->kg_method == KEYGEN_ARGON2ID || 826 kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1 || 827 kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD) { 828 loop = 1; 829 break; 830 } 831 832 for (;;) { 833 struct sharedkeyhits skh; 834 struct sharedkey *sk, *sk1; 835 int all_verified; 836 837 SLIST_INIT(&skh); 838 839 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 840 if (fd == -1) 841 return -1; 842 843 if (p->key) 844 bits_free(p->key); 845 846 p->key = getkey(argv[1], p->keygen, p->keylen, &skh); 847 if (!p->key) 848 goto bail_err; 849 850 ret = configure_params(fd, cgdname, dev, p); 851 if (ret) 852 goto bail_err; 853 854 ret = verify(p, fd); 855 if (ret == -1) { 856 (void)unconfigure_fd(fd); 857 goto bail_err; 858 } 859 if (ret == 0) { /* success */ 860 SLIST_FOREACH(sk, &skh, used) 861 sk->verified = 1; 862 break; 863 } 864 865 (void)unconfigure_fd(fd); 866 (void)prog_close(fd); 867 868 /* 869 * For shared keys: If the shared keys were all 870 * verified already, assume something is wrong with the 871 * disk and give up. If not, flush the cache of the 872 * ones that have not been verified in case we can try 873 * again with passphrase re-entry. 874 */ 875 if (!SLIST_EMPTY(&skh)) { 876 all_verified = 1; 877 SLIST_FOREACH_SAFE(sk, &skh, used, sk1) { 878 all_verified &= sk->verified; 879 if (!sk->verified) { 880 LIST_REMOVE(sk, list); 881 free(sk); 882 } 883 } 884 if (all_verified) 885 loop = 0; 886 } 887 888 if (!loop) { 889 warnx("verification failed permanently"); 890 goto bail_err; 891 } 892 893 warnx("verification failed, please reenter passphrase"); 894 } 895 896 params_free(p); 897 (void)prog_close(fd); 898 return 0; 899 900 bail_err:; 901 params_free(p); 902 (void)prog_close(fd); 903 return -1; 904} 905 906static int 907configure_stdin(struct params *p, int argc, char **argv) 908{ 909 int fd; 910 int ret; 911 char cgdname[PATH_MAX]; 912 char devicename[PATH_MAX]; 913 const char *dev; 914 915 if (argc < 3 || argc > 4) 916 usage(); 917 918 dev = getfsspecname(devicename, sizeof(devicename), argv[1]); 919 if (dev == NULL) { 920 warnx("getfsspecname failed: %s", devicename); 921 return -1; 922 } 923 924 p->algorithm = string_fromcharstar(argv[2]); 925 if (argc > 3) { 926 size_t keylen; 927 928 if (parse_size_t(argv[3], &keylen) == -1) { 929 warn("failed to parse key length"); 930 return -1; 931 } 932 p->keylen = keylen; 933 } 934 935 ret = params_filldefaults(p); 936 if (ret) 937 return ret; 938 939 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname)); 940 if (fd == -1) 941 return -1; 942 943 p->key = bits_fget(stdin, p->keylen); 944 if (!p->key) { 945 warnx("failed to read key from stdin"); 946 return -1; 947 } 948 949 return configure_params(fd, cgdname, dev, p); 950} 951 952static int 953opendisk_werror(const char *cgd, char *buf, size_t buflen) 954{ 955 int fd; 956 957 VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd,buf,buflen)); 958 959 /* sanity */ 960 if (!cgd || !buf) 961 return -1; 962 963 if (nflag) { 964 if (strlcpy(buf, cgd, buflen) >= buflen) 965 return -1; 966 return 0; 967 } 968 969 fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open); 970 if (fd == -1) 971 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf); 972 973 return fd; 974} 975 976static int 977configure_params(int fd, const char *cgd, const char *dev, struct params *p) 978{ 979 struct cgd_ioctl ci; 980 981 /* sanity */ 982 if (!cgd || !dev) 983 return -1; 984 985 (void)memset(&ci, 0x0, sizeof(ci)); 986 ci.ci_disk = dev; 987 ci.ci_alg = string_tocharstar(p->algorithm); 988 ci.ci_ivmethod = string_tocharstar(p->ivmeth); 989 ci.ci_key = bits_getbuf(p->key); 990 ci.ci_keylen = p->keylen; 991 ci.ci_blocksize = p->bsize; 992 993 VPRINTF(1, (" with alg %s keylen %zu blocksize %zu ivmethod %s\n", 994 string_tocharstar(p->algorithm), p->keylen, p->bsize, 995 string_tocharstar(p->ivmeth))); 996 VPRINTF(2, ("key: ")); 997 VERBOSE(2, bits_fprint(stdout, p->key)); 998 VPRINTF(2, ("\n")); 999 1000 if (nflag) 1001 return 0; 1002 1003 if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) { 1004 int saved_errno = errno; 1005 warn("ioctl"); 1006 return saved_errno; 1007 } 1008 1009 return 0; 1010} 1011 1012/* 1013 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry. 1014 */ 1015 1016#define SCANSIZE 8192 1017 1018static int 1019verify(struct params *p, int fd) 1020{ 1021 1022 switch (p->verify_method) { 1023 case VERIFY_NONE: 1024 return 0; 1025 case VERIFY_DISKLABEL: 1026 return verify_disklabel(fd); 1027 case VERIFY_FFS: 1028 return verify_ffs(fd); 1029 case VERIFY_REENTER: 1030 return verify_reenter(p); 1031 case VERIFY_MBR: 1032 return verify_mbr(fd); 1033 case VERIFY_GPT: 1034 return verify_gpt(fd); 1035#ifdef HAVE_ZFS 1036 case VERIFY_ZFS: 1037 return verify_zfs(fd); 1038#endif 1039 default: 1040 warnx("unimplemented verification method"); 1041 return -1; 1042 } 1043} 1044 1045static int 1046verify_disklabel(int fd) 1047{ 1048 struct disklabel l; 1049 ssize_t ret; 1050 char buf[SCANSIZE]; 1051 1052 /* 1053 * we simply scan the first few blocks for a disklabel, ignoring 1054 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read 1055 * a cgd, anyway, so it is unlikely that there will be non-native 1056 * partition information. 1057 */ 1058 1059 ret = prog_pread(fd, buf, SCANSIZE, 0); 1060 if (ret < 0) { 1061 warn("can't read disklabel area"); 1062 return -1; 1063 } 1064 1065 /* now scan for the disklabel */ 1066 1067 return disklabel_scan(&l, buf, (size_t)ret); 1068} 1069 1070static int 1071verify_mbr(int fd) 1072{ 1073 struct mbr_sector mbr; 1074 ssize_t ret; 1075 char buf[SCANSIZE]; 1076 1077 /* 1078 * we read the first blocks to avoid sector size issues and 1079 * verify the MBR in the beginning 1080 */ 1081 1082 ret = prog_pread(fd, buf, SCANSIZE, 0); 1083 if (ret < 0) { 1084 warn("can't read mbr area"); 1085 return -1; 1086 } 1087 1088 memcpy(&mbr, buf, sizeof(mbr)); 1089 if (le16toh(mbr.mbr_magic) != MBR_MAGIC) 1090 return 1; 1091 1092 return 0; 1093} 1094 1095static uint32_t crc32_tab[] = { 1096 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 1097 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 1098 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 1099 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 1100 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 1101 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 1102 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 1103 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 1104 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 1105 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 1106 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 1107 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 1108 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 1109 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 1110 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 1111 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 1112 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 1113 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 1114 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 1115 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 1116 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 1117 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 1118 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 1119 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 1120 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 1121 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 1122 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 1123 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 1124 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 1125 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 1126 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 1127 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 1128 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 1129 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 1130 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 1131 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 1132 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 1133 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 1134 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 1135 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 1136 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 1137 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 1138 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 1139}; 1140 1141static uint32_t 1142crc32(const void *buf, size_t size) 1143{ 1144 const uint8_t *p; 1145 uint32_t crc; 1146 1147 p = buf; 1148 crc = ~0U; 1149 1150 while (size--) 1151 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 1152 1153 return crc ^ ~0U; 1154} 1155 1156static int 1157verify_gpt(int fd) 1158{ 1159 struct gpt_hdr hdr; 1160 ssize_t ret; 1161 char buf[SCANSIZE]; 1162 unsigned blksize; 1163 size_t off; 1164 1165 /* 1166 * we read the first blocks to avoid sector size issues and 1167 * verify the GPT header. 1168 */ 1169 1170 ret = prog_pread(fd, buf, SCANSIZE, 0); 1171 if (ret < 0) { 1172 warn("can't read gpt area"); 1173 return -1; 1174 } 1175 1176 for (blksize = DEV_BSIZE; 1177 (off = (blksize * GPT_HDR_BLKNO)) <= SCANSIZE - sizeof(hdr); 1178 blksize <<= 1) { 1179 1180 memcpy(&hdr, &buf[off], sizeof(hdr)); 1181 if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0 1182 && le32toh(hdr.hdr_revision) == GPT_HDR_REVISION 1183 && le32toh(hdr.hdr_size) == GPT_HDR_SIZE) { 1184 1185 hdr.hdr_crc_self = 0; 1186 if (crc32(&hdr, sizeof(hdr))) { 1187 return 0; 1188 } 1189 } 1190 } 1191 1192 return 1; 1193} 1194 1195#ifdef HAVE_ZFS 1196 1197#define ZIO_CHECKSUM_BE(zcp) \ 1198{ \ 1199 (zcp)->zc_word[0] = BE_64((zcp)->zc_word[0]); \ 1200 (zcp)->zc_word[1] = BE_64((zcp)->zc_word[1]); \ 1201 (zcp)->zc_word[2] = BE_64((zcp)->zc_word[2]); \ 1202 (zcp)->zc_word[3] = BE_64((zcp)->zc_word[3]); \ 1203} 1204 1205static int 1206verify_zfs(int fd) 1207{ 1208 off_t vdev_size; 1209 int rv = 1; 1210 1211 if (prog_ioctl(fd, DIOCGMEDIASIZE, &vdev_size) == -1) { 1212 warn("%s: ioctl", __func__); 1213 return rv; 1214 } 1215 1216 vdev_phys_t *vdev_phys = emalloc(sizeof(*vdev_phys)); 1217 for (size_t i = 0; i < VDEV_LABELS; i++) { 1218 off_t vdev_phys_off = (i < VDEV_LABELS / 2 ? 1219 i * sizeof(vdev_label_t) : 1220 vdev_size - (VDEV_LABELS - i) * sizeof(vdev_label_t)) 1221 + offsetof(vdev_label_t, vl_vdev_phys); 1222 1223 ssize_t ret = prog_pread(fd, vdev_phys, sizeof(*vdev_phys), 1224 vdev_phys_off); 1225 if (ret == -1) { 1226 warn("%s: read failed", __func__); 1227 goto out; 1228 } 1229 if ((size_t)ret < sizeof(*vdev_phys)) { 1230 warnx("%s: incomplete block", __func__); 1231 goto out; 1232 } 1233 1234 bool byteswap; 1235 switch (vdev_phys->vp_zbt.zec_magic) { 1236 case BSWAP_64(ZEC_MAGIC): 1237 byteswap = true; 1238 break; 1239 case ZEC_MAGIC: 1240 byteswap = false; 1241 break; 1242 default: 1243 goto out; 1244 } 1245 1246 zio_cksum_t cksum_found = vdev_phys->vp_zbt.zec_cksum; 1247 if (byteswap) { 1248 ZIO_CHECKSUM_BSWAP(&cksum_found); 1249 } 1250 1251 ZIO_SET_CHECKSUM(&vdev_phys->vp_zbt.zec_cksum, 1252 vdev_phys_off, 0, 0, 0); 1253 if (byteswap) { 1254 ZIO_CHECKSUM_BSWAP(&vdev_phys->vp_zbt.zec_cksum); 1255 } 1256 1257 SHA256_CTX ctx; 1258 zio_cksum_t cksum_real; 1259 1260 SHA256Init(&ctx); 1261 SHA256Update(&ctx, (uint8_t *)vdev_phys, sizeof *vdev_phys); 1262 SHA256Final(&cksum_real, &ctx); 1263 1264 /* 1265 * For historical reasons the on-disk sha256 checksums are 1266 * always in big endian format. 1267 * (see cddl/osnet/dist/uts/common/fs/zfs/sha256.c) 1268 */ 1269 ZIO_CHECKSUM_BE(&cksum_real); 1270 1271 if (!ZIO_CHECKSUM_EQUAL(cksum_found, cksum_real)) { 1272 warnx("%s: checksum mismatch on vdev label %zu", 1273 __func__, i); 1274 warnx("%s: found %#jx, %#jx, %#jx, %#jx", __func__, 1275 (uintmax_t)cksum_found.zc_word[0], 1276 (uintmax_t)cksum_found.zc_word[1], 1277 (uintmax_t)cksum_found.zc_word[2], 1278 (uintmax_t)cksum_found.zc_word[3]); 1279 warnx("%s: expected %#jx, %#jx, %#jx, %#jx", __func__, 1280 (uintmax_t)cksum_real.zc_word[0], 1281 (uintmax_t)cksum_real.zc_word[1], 1282 (uintmax_t)cksum_real.zc_word[2], 1283 (uintmax_t)cksum_real.zc_word[3]); 1284 goto out; 1285 } 1286 } 1287 rv = 0; 1288out: 1289 free(vdev_phys); 1290 return rv; 1291} 1292 1293#endif 1294 1295static off_t sblock_try[] = SBLOCKSEARCH; 1296 1297static int 1298verify_ffs(int fd) 1299{ 1300 size_t i; 1301 1302 for (i = 0; sblock_try[i] != -1; i++) { 1303 union { 1304 char buf[SBLOCKSIZE]; 1305 struct fs fs; 1306 } u; 1307 ssize_t ret; 1308 1309 ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]); 1310 if (ret < 0) { 1311 warn("pread"); 1312 break; 1313 } else if ((size_t)ret < sizeof(u)) { 1314 warnx("pread: incomplete block"); 1315 break; 1316 } 1317 switch (u.fs.fs_magic) { 1318 case FS_UFS1_MAGIC: 1319 case FS_UFS2_MAGIC: 1320 case FS_UFS2EA_MAGIC: 1321 case FS_UFS1_MAGIC_SWAPPED: 1322 case FS_UFS2_MAGIC_SWAPPED: 1323 case FS_UFS2EA_MAGIC_SWAPPED: 1324 return 0; 1325 default: 1326 continue; 1327 } 1328 } 1329 1330 return 1; /* failure */ 1331} 1332 1333static int 1334verify_reenter(struct params *p) 1335{ 1336 struct keygen *kg; 1337 bits_t *orig_key, *key = NULL; 1338 int ret; 1339 1340 ret = 0; 1341 for (kg = p->keygen; kg && !ret; kg = kg->next) { 1342 if (kg->kg_method != KEYGEN_ARGON2ID && 1343 kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1 && 1344 kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD) 1345 continue; 1346 1347 orig_key = kg->kg_key; 1348 kg->kg_key = NULL; 1349 1350 switch (kg->kg_method) { 1351#ifdef HAVE_ARGON2 1352 case KEYGEN_ARGON2ID: 1353 key = getkey_argon2id("re-enter device", kg, 1354 bits_len(orig_key)); 1355 break; 1356#endif 1357 case KEYGEN_PKCS5_PBKDF2_SHA1: 1358 key = getkey_pkcs5_pbkdf2("re-enter device", kg, 1359 bits_len(orig_key), 0); 1360 break; 1361 case KEYGEN_PKCS5_PBKDF2_OLD: 1362 key = getkey_pkcs5_pbkdf2("re-enter device", kg, 1363 bits_len(orig_key), 1); 1364 break; 1365 default: 1366 warnx("unsupported keygen method"); 1367 kg->kg_key = orig_key; 1368 return -1; 1369 } 1370 1371 ret = !bits_match(key, orig_key); 1372 1373 bits_free(key); 1374 bits_free(kg->kg_key); 1375 kg->kg_key = orig_key; 1376 } 1377 1378 return ret; 1379} 1380 1381static int 1382generate(struct params *p, int argc, char **argv, const char *outfile, 1383 const char *Pfile) 1384{ 1385 int ret; 1386 1387 if (argc < 1 || argc > 2) 1388 usage(); 1389 1390 p->algorithm = string_fromcharstar(argv[0]); 1391 if (argc > 1) { 1392 size_t keylen; 1393 1394 if (parse_size_t(argv[1], &keylen) == -1) { 1395 warn("Failed to parse key length"); 1396 return -1; 1397 } 1398 p->keylen = keylen; 1399 } 1400 1401 ret = params_filldefaults(p); 1402 if (ret) 1403 return ret; 1404 1405 if (Pfile) { 1406 struct params *pp; 1407 1408 pp = params_cget(Pfile); 1409 if (pp == NULL) 1410 return -1; 1411 if (!params_verify(pp)) { 1412 params_free(pp); 1413 warnx("invalid parameters file \"%s\"", Pfile); 1414 return -1; 1415 } 1416 p = params_combine(pp, p); 1417 keygen_stripstored(&p->keygen); 1418 if (!p->keygen) { 1419 warnx("no keygen in parameters file \"%s\"", Pfile); 1420 return -1; 1421 } 1422 } else { 1423 if (!p->keygen) { 1424 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 1425 if (!p->keygen) 1426 return -1; 1427 } 1428 1429 if (keygen_filldefaults(p->keygen, p->keylen)) { 1430 warnx("Failed to generate defaults for keygen"); 1431 return -1; 1432 } 1433 } 1434 1435 if (Sflag) { 1436 if (Pfile) 1437 ret = keygen_tweakshared(p->keygen); 1438 else 1439 ret = keygen_makeshared(p->keygen); 1440 if (ret) 1441 return ret; 1442 } 1443 1444 if (!params_verify(p)) { 1445 warnx("invalid parameters generated"); 1446 return -1; 1447 } 1448 1449 return params_cput(p, outfile); 1450} 1451 1452static int 1453generate_convert(struct params *p, int argc, char **argv, const char *outfile, 1454 const char *Pfile) 1455{ 1456 struct params *oldp; 1457 struct keygen *kg; 1458 int ret; 1459 1460 if (argc != 1) 1461 usage(); 1462 1463 oldp = params_cget(*argv); 1464 if (!oldp) 1465 return -1; 1466 1467 /* for sanity, we ensure that none of the keygens are randomkey */ 1468 for (kg=p->keygen; kg; kg=kg->next) 1469 if ((kg->kg_method == KEYGEN_RANDOMKEY) || 1470 (kg->kg_method == KEYGEN_URANDOMKEY)) { 1471 warnx("can't preserve randomly generated key"); 1472 goto bail; 1473 } 1474 for (kg=oldp->keygen; kg; kg=kg->next) 1475 if ((kg->kg_method == KEYGEN_RANDOMKEY) || 1476 (kg->kg_method == KEYGEN_URANDOMKEY)) { 1477 warnx("can't preserve randomly generated key"); 1478 goto bail; 1479 } 1480 1481 if (!params_verify(oldp)) { 1482 warnx("invalid old parameters file \"%s\"", *argv); 1483 return -1; 1484 } 1485 1486 oldp->key = getkey("old file", oldp->keygen, oldp->keylen, NULL); 1487 1488 /* we copy across the non-keygen info, here. */ 1489 1490 string_free(p->algorithm); 1491 string_free(p->ivmeth); 1492 1493 p->algorithm = string_dup(oldp->algorithm); 1494 p->ivmeth = string_dup(oldp->ivmeth); 1495 p->keylen = oldp->keylen; 1496 p->bsize = oldp->bsize; 1497 if (p->verify_method == VERIFY_UNKNOWN) 1498 p->verify_method = oldp->verify_method; 1499 1500 params_free(oldp); 1501 1502 if (Pfile) { 1503 struct params *pp; 1504 1505 pp = params_cget(Pfile); 1506 if (pp == NULL) 1507 return -1; 1508 if (!params_verify(pp)) { 1509 params_free(pp); 1510 warnx("invalid parameters file \"%s\"", Pfile); 1511 return -1; 1512 } 1513 p = params_combine(pp, p); 1514 keygen_stripstored(&p->keygen); 1515 if (!p->keygen) { 1516 warnx("no keygen in parameters file \"%s\"", Pfile); 1517 return -1; 1518 } 1519 } else { 1520 if (!p->keygen) { 1521 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1); 1522 if (!p->keygen) 1523 return -1; 1524 } 1525 (void)params_filldefaults(p); 1526 (void)keygen_filldefaults(p->keygen, p->keylen); 1527 } 1528 1529 if (Sflag) { 1530 if (Pfile) 1531 ret = keygen_tweakshared(p->keygen); 1532 else 1533 ret = keygen_makeshared(p->keygen); 1534 if (ret) 1535 return ret; 1536 } 1537 1538 p->key = getkey("new file", p->keygen, p->keylen, NULL); 1539 1540 kg = keygen_generate(KEYGEN_STOREDKEY); 1541 kg->kg_key = bits_xor(p->key, oldp->key); 1542 keygen_addlist(&p->keygen, kg); 1543 1544 if (!params_verify(p)) { 1545 warnx("can't generate new parameters file"); 1546 return -1; 1547 } 1548 1549 return params_cput(p, outfile); 1550 bail:; 1551 params_free(oldp); 1552 return -1; 1553} 1554 1555static int 1556/*ARGSUSED*/ 1557do_all(const char *cfile, int argc, char **argv, 1558 int (*conf)(int, char **, struct params *, int)) 1559{ 1560 FILE *f; 1561 size_t len; 1562 size_t lineno; 1563 int my_argc; 1564 int ret; 1565 const char *fn; 1566 char *line; 1567 char **my_argv; 1568 1569 if (argc > 0) 1570 usage(); 1571 1572 if (!cfile[0]) 1573 fn = CGDCONFIG_CFILE; 1574 else 1575 fn = cfile; 1576 1577 f = fopen(fn, "r"); 1578 if (f == NULL) { 1579 warn("could not open config file \"%s\"", fn); 1580 return -1; 1581 } 1582 1583 ret = 0; 1584 lineno = 0; 1585 for (;;) { 1586 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL); 1587 if (!line) 1588 break; 1589 if (!*line) 1590 continue; 1591 1592 my_argv = words(line, &my_argc); 1593 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL); 1594 if (ret) { 1595 warnx("action failed on \"%s\" line %lu", fn, 1596 (u_long)lineno); 1597 break; 1598 } 1599 words_free(my_argv, my_argc); 1600 } 1601 return ret; 1602} 1603 1604static const char * 1605iv_method(int mode) 1606{ 1607 1608 switch (mode) { 1609 case CGD_CIPHER_CBC_ENCBLKNO8: 1610 return "encblkno8"; 1611 case CGD_CIPHER_CBC_ENCBLKNO1: 1612 return "encblkno1"; 1613 default: 1614 return "unknown"; 1615 } 1616} 1617 1618 1619static void 1620show(const char *dev) 1621{ 1622 char path[64]; 1623 struct cgd_user cgu; 1624 int fd; 1625 1626 fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0); 1627 if (fd == -1) { 1628 warn("open: %s", dev); 1629 return; 1630 } 1631 1632 cgu.cgu_unit = -1; 1633 if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) { 1634 close(fd); 1635 err(1, "CGDIOCGET"); 1636 } 1637 1638 printf("%s: ", dev); 1639 1640 if (cgu.cgu_dev == 0) { 1641 printf("not in use"); 1642 goto out; 1643 } 1644 1645 dev = devname(cgu.cgu_dev, S_IFBLK); 1646 if (dev != NULL) { 1647 printf("%s ", dev); 1648 } else { 1649 printf("dev %llu,%llu ", 1650 (unsigned long long)major(cgu.cgu_dev), 1651 (unsigned long long)minor(cgu.cgu_dev)); 1652 } 1653 1654 if (verbose) 1655 printf("%s ", cgu.cgu_alg); 1656 if (verbose > 1) { 1657 printf("keylen %d ", cgu.cgu_keylen); 1658 printf("blksize %zd ", cgu.cgu_blocksize); 1659 printf("%s ", iv_method(cgu.cgu_mode)); 1660 } 1661 1662 out:; 1663 putchar('\n'); 1664 close(fd); 1665} 1666 1667static int 1668do_list(int argc, char **argv) 1669{ 1670 1671 if (argc != 0 && argc != 1) 1672 usage(); 1673 1674 if (argc) { 1675 show(argv[0]); 1676 return 0; 1677 } 1678 1679 DIR *dirp; 1680 struct dirent *dp; 1681 __BITMAP_TYPE(, uint32_t, 65536) bm; 1682 1683 __BITMAP_ZERO(&bm); 1684 1685 if ((dirp = opendir(_PATH_DEV)) == NULL) 1686 err(1, "opendir: %s", _PATH_DEV); 1687 1688 while ((dp = readdir(dirp)) != NULL) { 1689 char *ep; 1690 if (strncmp(dp->d_name, "rcgd", 4) != 0) 1691 continue; 1692 errno = 0; 1693 int n = (int)strtol(dp->d_name + 4, &ep, 0); 1694 if (ep == dp->d_name + 4 || errno != 0) { 1695 warnx("bad name %s", dp->d_name); 1696 continue; 1697 } 1698 *ep = '\0'; 1699 if (__BITMAP_ISSET(n, &bm)) 1700 continue; 1701 __BITMAP_SET(n, &bm); 1702 show(dp->d_name + 1); 1703 } 1704 1705 closedir(dirp); 1706 return 0; 1707} 1708 1709static int 1710printkey(const char *dev, const char *paramsfile, const char *fmt, ...) 1711{ 1712 va_list va; 1713 struct params *p; 1714 const uint8_t *raw; 1715 size_t nbits, nbytes; 1716 size_t nb64; 1717 char *b64; 1718 int ret; 1719 1720 p = params_cget(paramsfile); 1721 if (p == NULL) 1722 return -1; 1723 if (!params_verify(p)) { 1724 warnx("invalid parameters file \"%s\"", paramsfile); 1725 return -1; 1726 } 1727 p->key = getkey(dev, p->keygen, p->keylen, NULL); 1728 raw = bits_getbuf(p->key); 1729 nbits = bits_len(p->key); 1730 assert(nbits <= INT_MAX - 7); 1731 nbytes = BITS2BYTES(nbits); 1732 assert(nbytes <= 3*(INT_MAX/4) - 2); 1733 1734 nb64 = 4*((nbytes + 2)/3); 1735 b64 = emalloc(nb64 + 2); 1736 ret = __b64_ntop(raw, nbytes, b64, nb64 + 1); 1737 assert(ret == (int)nb64); 1738 b64[nb64] = '\n'; 1739 b64[nb64 + 1] = '\0'; 1740 1741 va_start(va, fmt); 1742 vprintf(fmt, va); 1743 va_end(va); 1744 if (fwrite(b64, nb64 + 1, 1, stdout) != 1) 1745 err(1, "fwrite"); 1746 fflush(stdout); 1747 return ferror(stdout); 1748} 1749 1750static int 1751printkey1(int argc, char **argv, struct params *inparams, int flags) 1752{ 1753 char devicename[PATH_MAX], paramsfilebuf[PATH_MAX]; 1754 const char *dev, *paramsfile; 1755 1756 assert(flags == CONFIG_FLAGS_FROMALL); 1757 1758 if (argc < 2 || argc > 3) 1759 return -1; 1760 1761 dev = getfsspecname(devicename, sizeof(devicename), argv[1]); 1762 if (dev == NULL) { 1763 warnx("getfsspecname failed: %s", devicename); 1764 return -1; 1765 } 1766 1767 if (argc == 2) { 1768 strlcpy(paramsfilebuf, dev, sizeof(paramsfilebuf)); 1769 paramsfile = basename(paramsfilebuf); 1770 } else { 1771 paramsfile = argv[2]; 1772 } 1773 1774 return printkey(dev, paramsfile, "%s: ", dev); 1775} 1776 1777static int 1778do_printkey(int argc, char **argv) 1779{ 1780 1781 if (argc != 1) 1782 usage(); 1783 return printkey("key", argv[0], ""); 1784} 1785 1786static void 1787eliminate_cores(void) 1788{ 1789 struct rlimit rlp; 1790 1791 rlp.rlim_cur = 0; 1792 rlp.rlim_max = 0; 1793 if (setrlimit(RLIMIT_CORE, &rlp) == -1) 1794 err(EXIT_FAILURE, "Can't disable cores"); 1795} 1796