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