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