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