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