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