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