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