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