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