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