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