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