Home | History | Annotate | Line # | Download | only in cgdconfig
      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 
     90 enum 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 
    106 static int	nflag = 0;
    107 
    108 /* if Sflag is set, generate shared keys */
    109 
    110 static 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
    118 static 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 
    127 struct 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 };
    135 static LIST_HEAD(, sharedkey) sharedkeys;
    136 SLIST_HEAD(sharedkeyhits, sharedkey);
    137 
    138 static int	configure(int, char **, struct params *, int);
    139 static int	configure_stdin(struct params *, int argc, char **);
    140 static int	generate(struct params *, int, char **, const char *,
    141 		    const char *);
    142 static int	generate_convert(struct params *, int, char **, const char *,
    143 		    const char *);
    144 static int	unconfigure(int, char **, struct params *, int);
    145 static int	do_all(const char *, int, char **,
    146 		       int (*)(int, char **, struct params *, int));
    147 static int	do_list(int, char **);
    148 static int	printkey(const char *, const char *, const char *, ...)
    149 		    __printflike(3,4);
    150 static int	printkey1(int, char **, struct params *, int);
    151 static 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 
    156 static int	 configure_params(int, const char *, const char *,
    157 				  struct params *);
    158 static void	 eliminate_cores(void);
    159 static bits_t	*getkey(const char *, struct keygen *, size_t,
    160 		     struct sharedkeyhits *);
    161 static bits_t	*getkey_storedkey(const char *, struct keygen *, size_t);
    162 static bits_t	*getkey_randomkey(const char *, struct keygen *, size_t, int);
    163 #ifdef HAVE_ARGON2
    164 static bits_t	*getkey_argon2id(const char *, struct keygen *, size_t);
    165 #endif
    166 static bits_t	*getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t,
    167 				     int);
    168 static bits_t	*getkey_shell_cmd(const char *, struct keygen *, size_t);
    169 static char	*maybe_getpass(char *);
    170 static int	 opendisk_werror(const char *, char *, size_t);
    171 static int	 unconfigure_fd(int);
    172 static int	 verify(struct params *, int);
    173 static int	 verify_disklabel(int);
    174 static int	 verify_ffs(int);
    175 static int	 verify_reenter(struct params *);
    176 static int	 verify_mbr(int);
    177 static int	 verify_gpt(int);
    178 #ifdef HAVE_ZFS
    179 static int	 verify_zfs(int);
    180 #endif
    181 
    182 __dead static void	 usage(void);
    183 
    184 /* Verbose Framework */
    185 static 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 
    190 static void
    191 usage(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 
    213 static int
    214 parse_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 
    235 static void
    236 set_action(enum action *action, enum action value)
    237 {
    238 	if (*action != ACTION_DEFAULT)
    239 		usage();
    240 	*action = value;
    241 }
    242 
    243 int
    244 main(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 
    412 static bits_t *
    413 getsubkey_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 
    428 out:	free(tmp);
    429 	return ret;
    430 }
    431 
    432 static bits_t *
    433 getsubkey(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 
    445 static bits_t *
    446 getkey(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 
    523 derive:		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*/
    550 static bits_t *
    551 getkey_storedkey(const char *target, struct keygen *kg, size_t keylen)
    552 {
    553 	return bits_dup(kg->kg_key);
    554 }
    555 
    556 /*ARGSUSED*/
    557 static bits_t *
    558 getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard)
    559 {
    560 	return bits_getrandombits(keylen, hard);
    561 }
    562 
    563 static char *
    564 maybe_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  */
    611 static bits_t *
    612 getkey_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
    640 static bits_t *
    641 getkey_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*/
    674 static bits_t *
    675 getkey_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*/
    692 static int
    693 unconfigure(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 
    728 static int
    729 unconfigure_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*/
    742 static int
    743 configure(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 
    906 static int
    907 configure_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 
    952 static int
    953 opendisk_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 
    976 static int
    977 configure_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 
   1018 static int
   1019 verify(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 
   1045 static int
   1046 verify_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 
   1070 static int
   1071 verify_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 
   1095 static 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 
   1141 static uint32_t
   1142 crc32(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 
   1156 static int
   1157 verify_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 
   1205 static int
   1206 verify_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;
   1288 out:
   1289 	free(vdev_phys);
   1290 	return rv;
   1291 }
   1292 
   1293 #endif
   1294 
   1295 static off_t sblock_try[] = SBLOCKSEARCH;
   1296 
   1297 static int
   1298 verify_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 
   1333 static int
   1334 verify_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 
   1381 static int
   1382 generate(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 
   1452 static int
   1453 generate_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 
   1555 static int
   1556 /*ARGSUSED*/
   1557 do_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 
   1604 static const char *
   1605 iv_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 
   1619 static void
   1620 show(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 
   1667 static int
   1668 do_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 
   1709 static int
   1710 printkey(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 
   1750 static int
   1751 printkey1(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 
   1777 static int
   1778 do_printkey(int argc, char **argv)
   1779 {
   1780 
   1781 	if (argc != 1)
   1782 		usage();
   1783 	return printkey("key", argv[0], "");
   1784 }
   1785 
   1786 static void
   1787 eliminate_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