Home | History | Annotate | Line # | Download | only in cgdconfig
cgdconfig.c revision 1.50
      1 /* $NetBSD: cgdconfig.c,v 1.50 2019/04/10 06:11:37 kre 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.50 2019/04/10 06:11:37 kre 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 [-nv] [-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 
    464 	f = popen(string_tocharstar(kg->kg_cmd), "r");
    465 	ret = bits_fget(f, keylen);
    466 	pclose(f);
    467 
    468 	return ret;
    469 }
    470 
    471 /*ARGSUSED*/
    472 static int
    473 unconfigure(int argc, char **argv, struct params *inparams, int flags)
    474 {
    475 	int	fd;
    476 	int	ret;
    477 	char	buf[MAXPATHLEN] = "";
    478 
    479 	/* only complain about additional arguments, if called from main() */
    480 	if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
    481 		usage();
    482 
    483 	/* if called from do_all(), then ensure that 2 or 3 args exist */
    484 	if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
    485 		return -1;
    486 
    487 	fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, prog_open);
    488 	if (fd == -1) {
    489 		int saved_errno = errno;
    490 
    491 		warn("can't open cgd \"%s\", \"%s\"", *argv, buf);
    492 
    493 		/* this isn't fatal with nflag != 0 */
    494 		if (!nflag)
    495 			return saved_errno;
    496 	}
    497 
    498 	VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
    499 
    500 	if (nflag)
    501 		return 0;
    502 
    503 	ret = unconfigure_fd(fd);
    504 	(void)prog_close(fd);
    505 	return ret;
    506 }
    507 
    508 static int
    509 unconfigure_fd(int fd)
    510 {
    511 	struct	cgd_ioctl ci;
    512 
    513 	if (prog_ioctl(fd, CGDIOCCLR, &ci) == -1) {
    514 		warn("ioctl");
    515 		return -1;
    516 	}
    517 
    518 	return 0;
    519 }
    520 
    521 /*ARGSUSED*/
    522 static int
    523 configure(int argc, char **argv, struct params *inparams, int flags)
    524 {
    525 	struct params	*p;
    526 	struct keygen	*kg;
    527 	int		 fd;
    528 	int		 loop = 0;
    529 	int		 ret;
    530 	char		 cgdname[PATH_MAX];
    531 	char		 devicename[PATH_MAX];
    532 	const char	*dev = NULL;	/* XXX: gcc */
    533 
    534 	if (argc < 2 || argc > 3) {
    535 		/* print usage and exit, only if called from main() */
    536 		if (flags == CONFIG_FLAGS_FROMMAIN) {
    537 			warnx("wrong number of args");
    538 			usage();
    539 		}
    540 		return -1;
    541 	}
    542 
    543 	if ((
    544 	  fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open)
    545 	    ) != -1) {
    546 		struct cgd_user cgu;
    547 
    548 		cgu.cgu_unit = -1;
    549 		if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) {
    550 			warnx("device %s already in use", *argv);
    551 			prog_close(fd);
    552 			return -1;
    553 		}
    554 		prog_close(fd);
    555 	}
    556 
    557 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    558 	if (dev == NULL) {
    559 		warnx("getfsspecname failed: %s", devicename);
    560 		return -1;
    561 	}
    562 
    563 	if (argc == 2) {
    564 		char pfile[MAXPATHLEN];
    565 
    566 		/* make string writable for basename */
    567 		strlcpy(pfile, dev, sizeof(pfile));
    568 		p = params_cget(basename(pfile));
    569 	} else
    570 		p = params_cget(argv[2]);
    571 
    572 	if (!p)
    573 		return -1;
    574 
    575 	/*
    576 	 * over-ride with command line specifications and fill in default
    577 	 * values.
    578 	 */
    579 
    580 	p = params_combine(p, inparams);
    581 	ret = params_filldefaults(p);
    582 	if (ret) {
    583 		params_free(p);
    584 		return ret;
    585 	}
    586 
    587 	if (!params_verify(p)) {
    588 		warnx("params invalid");
    589 		return -1;
    590 	}
    591 
    592 	/*
    593 	 * loop over configuring the disk and checking to see if it
    594 	 * verifies properly.  We open and close the disk device each
    595 	 * time, because if the user passes us the block device we
    596 	 * need to flush the buffer cache.
    597 	 *
    598 	 * We only loop if one of the verification methods prompts for
    599 	 * a password.
    600 	 */
    601 
    602 	for (kg = p->keygen;
    603 	    (pflag & PFLAG_GETPASS_MASK) && kg;
    604 	    kg = kg->next)
    605 		if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) ||
    606 		    (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) {
    607 			loop = 1;
    608 			break;
    609 		}
    610 
    611 	for (;;) {
    612 		fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    613 		if (fd == -1)
    614 			return -1;
    615 
    616 		if (p->key)
    617 			bits_free(p->key);
    618 
    619 		p->key = getkey(argv[1], p->keygen, p->keylen);
    620 		if (!p->key)
    621 			goto bail_err;
    622 
    623 		ret = configure_params(fd, cgdname, dev, p);
    624 		if (ret)
    625 			goto bail_err;
    626 
    627 		ret = verify(p, fd);
    628 		if (ret == -1) {
    629 			(void)unconfigure_fd(fd);
    630 			goto bail_err;
    631 		}
    632 		if (ret == 0)		/* success */
    633 			break;
    634 
    635 		(void)unconfigure_fd(fd);
    636 		(void)prog_close(fd);
    637 
    638 		if (!loop) {
    639 			warnx("verification failed permanently");
    640 			goto bail_err;
    641 		}
    642 
    643 		warnx("verification failed, please reenter passphrase");
    644 	}
    645 
    646 	params_free(p);
    647 	(void)prog_close(fd);
    648 	return 0;
    649 
    650  bail_err:;
    651 	params_free(p);
    652 	(void)prog_close(fd);
    653 	return -1;
    654 }
    655 
    656 static int
    657 configure_stdin(struct params *p, int argc, char **argv)
    658 {
    659 	int		 fd;
    660 	int		 ret;
    661 	char		 cgdname[PATH_MAX];
    662 	char		 devicename[PATH_MAX];
    663 	const char	*dev;
    664 
    665 	if (argc < 3 || argc > 4)
    666 		usage();
    667 
    668 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    669 	if (dev == NULL) {
    670 		warnx("getfsspecname failed: %s", devicename);
    671 		return -1;
    672 	}
    673 
    674 	p->algorithm = string_fromcharstar(argv[2]);
    675 	if (argc > 3) {
    676 		size_t keylen;
    677 
    678 		if (parse_size_t(argv[3], &keylen) == -1) {
    679 			warn("failed to parse key length");
    680 			return -1;
    681 		}
    682 		p->keylen = keylen;
    683 	}
    684 
    685 	ret = params_filldefaults(p);
    686 	if (ret)
    687 		return ret;
    688 
    689 	fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    690 	if (fd == -1)
    691 		return -1;
    692 
    693 	p->key = bits_fget(stdin, p->keylen);
    694 	if (!p->key) {
    695 		warnx("failed to read key from stdin");
    696 		return -1;
    697 	}
    698 
    699 	return configure_params(fd, cgdname, dev, p);
    700 }
    701 
    702 static int
    703 opendisk_werror(const char *cgd, char *buf, size_t buflen)
    704 {
    705 	int	fd;
    706 
    707 	VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd,buf,buflen));
    708 
    709 	/* sanity */
    710 	if (!cgd || !buf)
    711 		return -1;
    712 
    713 	if (nflag) {
    714 		if (strlcpy(buf, cgd, buflen) >= buflen)
    715 			return -1;
    716 		return 0;
    717 	}
    718 
    719 	fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open);
    720 	if (fd == -1)
    721 		warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
    722 
    723 	return fd;
    724 }
    725 
    726 static int
    727 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
    728 {
    729 	struct cgd_ioctl ci;
    730 
    731 	/* sanity */
    732 	if (!cgd || !dev)
    733 		return -1;
    734 
    735 	(void)memset(&ci, 0x0, sizeof(ci));
    736 	ci.ci_disk = dev;
    737 	ci.ci_alg = string_tocharstar(p->algorithm);
    738 	ci.ci_ivmethod = string_tocharstar(p->ivmeth);
    739 	ci.ci_key = bits_getbuf(p->key);
    740 	ci.ci_keylen = p->keylen;
    741 	ci.ci_blocksize = p->bsize;
    742 
    743 	VPRINTF(1, ("    with alg %s keylen %zu blocksize %zu ivmethod %s\n",
    744 	    string_tocharstar(p->algorithm), p->keylen, p->bsize,
    745 	    string_tocharstar(p->ivmeth)));
    746 	VPRINTF(2, ("key: "));
    747 	VERBOSE(2, bits_fprint(stdout, p->key));
    748 	VPRINTF(2, ("\n"));
    749 
    750 	if (nflag)
    751 		return 0;
    752 
    753 	if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) {
    754 		int saved_errno = errno;
    755 		warn("ioctl");
    756 		return saved_errno;
    757 	}
    758 
    759 	return 0;
    760 }
    761 
    762 /*
    763  * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
    764  */
    765 
    766 #define SCANSIZE	8192
    767 
    768 static int
    769 verify(struct params *p, int fd)
    770 {
    771 
    772 	switch (p->verify_method) {
    773 	case VERIFY_NONE:
    774 		return 0;
    775 	case VERIFY_DISKLABEL:
    776 		return verify_disklabel(fd);
    777 	case VERIFY_FFS:
    778 		return verify_ffs(fd);
    779 	case VERIFY_REENTER:
    780 		return verify_reenter(p);
    781 	case VERIFY_MBR:
    782 		return verify_mbr(fd);
    783 	case VERIFY_GPT:
    784 		return verify_gpt(fd);
    785 	default:
    786 		warnx("unimplemented verification method");
    787 		return -1;
    788 	}
    789 }
    790 
    791 static int
    792 verify_disklabel(int fd)
    793 {
    794 	struct	disklabel l;
    795 	ssize_t	ret;
    796 	char	buf[SCANSIZE];
    797 
    798 	/*
    799 	 * we simply scan the first few blocks for a disklabel, ignoring
    800 	 * any MBR/filecore sorts of logic.  MSDOS and RiscOS can't read
    801 	 * a cgd, anyway, so it is unlikely that there will be non-native
    802 	 * partition information.
    803 	 */
    804 
    805 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    806 	if (ret < 0) {
    807 		warn("can't read disklabel area");
    808 		return -1;
    809 	}
    810 
    811 	/* now scan for the disklabel */
    812 
    813 	return disklabel_scan(&l, buf, (size_t)ret);
    814 }
    815 
    816 static int
    817 verify_mbr(int fd)
    818 {
    819 	struct mbr_sector mbr;
    820 	ssize_t	ret;
    821 	char	buf[SCANSIZE];
    822 
    823 	/*
    824 	 * we read the first blocks to avoid sector size issues and
    825 	 * verify the MBR in the beginning
    826 	 */
    827 
    828 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    829 	if (ret < 0) {
    830 		warn("can't read mbr area");
    831 		return -1;
    832 	}
    833 
    834 	memcpy(&mbr, buf, sizeof(mbr));
    835 	if (le16toh(mbr.mbr_magic) != MBR_MAGIC)
    836 		return 1;
    837 
    838 	return 0;
    839 }
    840 
    841 static uint32_t crc32_tab[] = {
    842 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    843 	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    844 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    845 	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    846 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    847 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    848 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    849 	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    850 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    851 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    852 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    853 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    854 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    855 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    856 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    857 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    858 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    859 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    860 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    861 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    862 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    863 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    864 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    865 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    866 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    867 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    868 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    869 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    870 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    871 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    872 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    873 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    874 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    875 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    876 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    877 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    878 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    879 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    880 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    881 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    882 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    883 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    884 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    885 };
    886 
    887 static uint32_t
    888 crc32(const void *buf, size_t size)
    889 {
    890 	const uint8_t *p;
    891 	uint32_t crc;
    892 
    893 	p = buf;
    894 	crc = ~0U;
    895 
    896 	while (size--)
    897 		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
    898 
    899 	return crc ^ ~0U;
    900 }
    901 
    902 static int
    903 verify_gpt(int fd)
    904 {
    905 	struct	 gpt_hdr hdr;
    906 	ssize_t	 ret;
    907 	char	 buf[SCANSIZE];
    908 	unsigned blksize;
    909 	size_t	 off;
    910 
    911 	/*
    912 	 * we read the first blocks to avoid sector size issues and
    913 	 * verify the GPT header.
    914 	 */
    915 
    916 	ret = prog_pread(fd, buf, SCANSIZE, 0);
    917 	if (ret < 0) {
    918 		warn("can't read gpt area");
    919 		return -1;
    920 	}
    921 
    922 	ret = 1;
    923 	for (blksize = DEV_BSIZE;
    924              (off = (blksize * GPT_HDR_BLKNO)) <= SCANSIZE - sizeof(hdr);
    925              blksize <<= 1) {
    926 
    927 		memcpy(&hdr, &buf[off], sizeof(hdr));
    928 		if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0
    929 		    && le32toh(hdr.hdr_revision) == GPT_HDR_REVISION
    930 		    && le32toh(hdr.hdr_size) == GPT_HDR_SIZE) {
    931 
    932 			hdr.hdr_crc_self = 0;
    933 			if (crc32(&hdr, sizeof(hdr))) {
    934 				ret = 0;
    935 				break;
    936 			}
    937 		}
    938 	}
    939 
    940 	return ret;
    941 }
    942 
    943 static off_t sblock_try[] = SBLOCKSEARCH;
    944 
    945 static int
    946 verify_ffs(int fd)
    947 {
    948 	size_t	i;
    949 
    950 	for (i = 0; sblock_try[i] != -1; i++) {
    951 		union {
    952 		    char	buf[SBLOCKSIZE];
    953 		    struct	fs fs;
    954 		} u;
    955 		ssize_t ret;
    956 
    957 		ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]);
    958 		if (ret < 0) {
    959 			warn("pread");
    960 			break;
    961 		} else if ((size_t)ret < sizeof(u)) {
    962 			warnx("pread: incomplete block");
    963 			break;
    964 		}
    965 		switch (u.fs.fs_magic) {
    966 		case FS_UFS1_MAGIC:
    967 		case FS_UFS2_MAGIC:
    968 		case FS_UFS1_MAGIC_SWAPPED:
    969 		case FS_UFS2_MAGIC_SWAPPED:
    970 			return 0;
    971 		default:
    972 			continue;
    973 		}
    974 	}
    975 
    976 	return 1;	/* failure */
    977 }
    978 
    979 static int
    980 verify_reenter(struct params *p)
    981 {
    982 	struct keygen *kg;
    983 	bits_t *orig_key, *key;
    984 	int ret;
    985 
    986 	ret = 0;
    987 	for (kg = p->keygen; kg && !ret; kg = kg->next) {
    988 		if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
    989 		    (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
    990 			continue;
    991 
    992 		orig_key = kg->kg_key;
    993 		kg->kg_key = NULL;
    994 
    995 		/* add a compat flag till the _OLD method goes away */
    996 		key = getkey_pkcs5_pbkdf2("re-enter device", kg,
    997 			bits_len(orig_key),
    998 			kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
    999 
   1000 		ret = !bits_match(key, orig_key);
   1001 
   1002 		bits_free(key);
   1003 		bits_free(kg->kg_key);
   1004 		kg->kg_key = orig_key;
   1005 	}
   1006 
   1007 	return ret;
   1008 }
   1009 
   1010 static int
   1011 generate(struct params *p, int argc, char **argv, const char *outfile)
   1012 {
   1013 	int	 ret;
   1014 
   1015 	if (argc < 1 || argc > 2)
   1016 		usage();
   1017 
   1018 	p->algorithm = string_fromcharstar(argv[0]);
   1019 	if (argc > 1) {
   1020 		size_t keylen;
   1021 
   1022 		if (parse_size_t(argv[1], &keylen) == -1) {
   1023 			warn("Failed to parse key length");
   1024 			return -1;
   1025 		}
   1026 		p->keylen = keylen;
   1027 	}
   1028 
   1029 	ret = params_filldefaults(p);
   1030 	if (ret)
   1031 		return ret;
   1032 
   1033 	if (!p->keygen) {
   1034 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1035 		if (!p->keygen)
   1036 			return -1;
   1037 	}
   1038 
   1039 	if (keygen_filldefaults(p->keygen, p->keylen)) {
   1040 		warnx("Failed to generate defaults for keygen");
   1041 		return -1;
   1042 	}
   1043 
   1044 	if (!params_verify(p)) {
   1045 		warnx("invalid parameters generated");
   1046 		return -1;
   1047 	}
   1048 
   1049 	return params_cput(p, outfile);
   1050 }
   1051 
   1052 static int
   1053 generate_convert(struct params *p, int argc, char **argv, const char *outfile)
   1054 {
   1055 	struct params	*oldp;
   1056 	struct keygen	*kg;
   1057 
   1058 	if (argc != 1)
   1059 		usage();
   1060 
   1061 	oldp = params_cget(*argv);
   1062 	if (!oldp)
   1063 		return -1;
   1064 
   1065 	/* for sanity, we ensure that none of the keygens are randomkey */
   1066 	for (kg=p->keygen; kg; kg=kg->next)
   1067 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1068 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1069 			warnx("can't preserve randomly generated key");
   1070 			goto bail;
   1071 		}
   1072 	for (kg=oldp->keygen; kg; kg=kg->next)
   1073 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1074 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1075 			warnx("can't preserve randomly generated key");
   1076 			goto bail;
   1077 		}
   1078 
   1079 	if (!params_verify(oldp)) {
   1080 		warnx("invalid old parameters file \"%s\"", *argv);
   1081 		return -1;
   1082 	}
   1083 
   1084 	oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
   1085 
   1086 	/* we copy across the non-keygen info, here. */
   1087 
   1088 	string_free(p->algorithm);
   1089 	string_free(p->ivmeth);
   1090 
   1091 	p->algorithm = string_dup(oldp->algorithm);
   1092 	p->ivmeth = string_dup(oldp->ivmeth);
   1093 	p->keylen = oldp->keylen;
   1094 	p->bsize = oldp->bsize;
   1095 	if (p->verify_method == VERIFY_UNKNOWN)
   1096 		p->verify_method = oldp->verify_method;
   1097 
   1098 	params_free(oldp);
   1099 
   1100 	if (!p->keygen) {
   1101 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1102 		if (!p->keygen)
   1103 			return -1;
   1104 	}
   1105 	(void)params_filldefaults(p);
   1106 	(void)keygen_filldefaults(p->keygen, p->keylen);
   1107 	p->key = getkey("new file", p->keygen, p->keylen);
   1108 
   1109 	kg = keygen_generate(KEYGEN_STOREDKEY);
   1110 	kg->kg_key = bits_xor(p->key, oldp->key);
   1111 	keygen_addlist(&p->keygen, kg);
   1112 
   1113 	if (!params_verify(p)) {
   1114 		warnx("can't generate new parameters file");
   1115 		return -1;
   1116 	}
   1117 
   1118 	return params_cput(p, outfile);
   1119  bail:;
   1120 	params_free(oldp);
   1121 	return -1;
   1122 }
   1123 
   1124 static int
   1125 /*ARGSUSED*/
   1126 do_all(const char *cfile, int argc, char **argv,
   1127        int (*conf)(int, char **, struct params *, int))
   1128 {
   1129 	FILE		 *f;
   1130 	size_t		  len;
   1131 	size_t		  lineno;
   1132 	int		  my_argc;
   1133 	int		  ret;
   1134 	const char	 *fn;
   1135 	char		 *line;
   1136 	char		**my_argv;
   1137 
   1138 	if (argc > 0)
   1139 		usage();
   1140 
   1141 	if (!cfile[0])
   1142 		fn = CGDCONFIG_CFILE;
   1143 	else
   1144 		fn = cfile;
   1145 
   1146 	f = fopen(fn, "r");
   1147 	if (f == NULL) {
   1148 		warn("could not open config file \"%s\"", fn);
   1149 		return -1;
   1150 	}
   1151 
   1152 	ret = 0;
   1153 	lineno = 0;
   1154 	for (;;) {
   1155 		line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
   1156 		if (!line)
   1157 			break;
   1158 		if (!*line)
   1159 			continue;
   1160 
   1161 		my_argv = words(line, &my_argc);
   1162 		ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
   1163 		if (ret) {
   1164 			warnx("action failed on \"%s\" line %lu", fn,
   1165 			    (u_long)lineno);
   1166 			break;
   1167 		}
   1168 		words_free(my_argv, my_argc);
   1169 	}
   1170 	return ret;
   1171 }
   1172 
   1173 static const char *
   1174 iv_method(int mode)
   1175 {
   1176 
   1177 	switch (mode) {
   1178 	case CGD_CIPHER_CBC_ENCBLKNO8:
   1179 		return "encblkno8";
   1180 	case CGD_CIPHER_CBC_ENCBLKNO1:
   1181 		return "encblkno1";
   1182 	default:
   1183 		return "unknown";
   1184 	}
   1185 }
   1186 
   1187 
   1188 static void
   1189 show(const char *dev) {
   1190 	char path[64];
   1191 	struct cgd_user cgu;
   1192 	int fd;
   1193 
   1194 	fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0);
   1195 	if (fd == -1) {
   1196 		warn("open: %s", dev);
   1197 		return;
   1198 	}
   1199 
   1200 	cgu.cgu_unit = -1;
   1201 	if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) {
   1202 		close(fd);
   1203 		err(1, "CGDIOCGET");
   1204 	}
   1205 
   1206 	printf("%s: ", dev);
   1207 
   1208 	if (cgu.cgu_dev == 0) {
   1209 		printf("not in use");
   1210 		goto out;
   1211 	}
   1212 
   1213 	dev = devname(cgu.cgu_dev, S_IFBLK);
   1214 	if (dev != NULL)
   1215 		printf("%s ", dev);
   1216 	else
   1217 		printf("dev %llu,%llu ", (unsigned long long)major(cgu.cgu_dev),
   1218 		    (unsigned long long)minor(cgu.cgu_dev));
   1219 
   1220 	if (verbose)
   1221 		printf("%s ", cgu.cgu_alg);
   1222 	if (verbose > 1) {
   1223 		printf("keylen %d ", cgu.cgu_keylen);
   1224 		printf("blksize %zd ", cgu.cgu_blocksize);
   1225 		printf("%s ", iv_method(cgu.cgu_mode));
   1226 	}
   1227 
   1228  out:;
   1229 	putchar('\n');
   1230 	close(fd);
   1231 }
   1232 
   1233 static int
   1234 do_list(int argc, char **argv)
   1235 {
   1236 
   1237 	if (argc != 0 && argc != 1)
   1238 		usage();
   1239 
   1240 	if (argc) {
   1241 		show(argv[0]);
   1242 		return 0;
   1243 	}
   1244 
   1245 	DIR *dirp;
   1246 	struct dirent *dp;
   1247 	__BITMAP_TYPE(, uint32_t, 65536) bm;
   1248 
   1249 	__BITMAP_ZERO(&bm);
   1250 
   1251 	if ((dirp = opendir(_PATH_DEV)) == NULL)
   1252 		err(1, "opendir: %s", _PATH_DEV);
   1253 
   1254 	while ((dp = readdir(dirp)) != NULL) {
   1255 		char *ep;
   1256 		if (strncmp(dp->d_name, "rcgd", 4) != 0)
   1257 			continue;
   1258 		errno = 0;
   1259 		int n = (int)strtol(dp->d_name + 4, &ep, 0);
   1260 		if (ep == dp->d_name + 4 || errno != 0) {
   1261 			warnx("bad name %s", dp->d_name);
   1262 			continue;
   1263 		}
   1264 		*ep = '\0';
   1265 		if (__BITMAP_ISSET(n, &bm))
   1266 			continue;
   1267 		__BITMAP_SET(n, &bm);
   1268 		show(dp->d_name + 1);
   1269 	}
   1270 
   1271 	closedir(dirp);
   1272 	return 0;
   1273 }
   1274 
   1275 static void
   1276 eliminate_cores(void)
   1277 {
   1278 	struct rlimit	rlp;
   1279 
   1280 	rlp.rlim_cur = 0;
   1281 	rlp.rlim_max = 0;
   1282 	if (setrlimit(RLIMIT_CORE, &rlp) == -1)
   1283 		err(EXIT_FAILURE, "Can't disable cores");
   1284 }
   1285