xref: /netbsd-src/sbin/cgdconfig/cgdconfig.c (revision 50728e7823a76d5bd1a7bfa3a4eac400269b1339)
1 /* $NetBSD: cgdconfig.c,v 1.27 2008/07/24 19:07:36 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.27 2008/07/24 19:07:36 christos 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 
49 #include <sys/ioctl.h>
50 #include <sys/disklabel.h>
51 #include <sys/mman.h>
52 #include <sys/param.h>
53 #include <sys/resource.h>
54 
55 #include <dev/cgdvar.h>
56 
57 #include <ufs/ffs/fs.h>
58 
59 #include "params.h"
60 #include "pkcs5_pbkdf2.h"
61 #include "utils.h"
62 
63 #define CGDCONFIG_DIR		"/etc/cgd"
64 #define CGDCONFIG_CFILE		CGDCONFIG_DIR "/cgd.conf"
65 
66 enum action {
67 	 ACTION_DEFAULT,		/* default -> configure */
68 	 ACTION_CONFIGURE,		/* configure, with paramsfile */
69 	 ACTION_UNCONFIGURE,		/* unconfigure */
70 	 ACTION_GENERATE,		/* generate a paramsfile */
71 	 ACTION_GENERATE_CONVERT,	/* generate a ``dup'' paramsfile */
72 	 ACTION_CONFIGALL,		/* configure all from config file */
73 	 ACTION_UNCONFIGALL,		/* unconfigure all from config file */
74 	 ACTION_CONFIGSTDIN		/* configure, key from stdin */
75 };
76 
77 /* if nflag is set, do not configure/unconfigure the cgd's */
78 
79 int	nflag = 0;
80 
81 /* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */
82 
83 #define	PFLAG_GETPASS	0x01
84 #define	PFLAG_STDIN	0x02
85 int	pflag = PFLAG_GETPASS;
86 
87 static int	configure(int, char **, struct params *, int);
88 static int	configure_stdin(struct params *, int argc, char **);
89 static int	generate(struct params *, int, char **, const char *);
90 static int	generate_convert(struct params *, int, char **, const char *);
91 static int	unconfigure(int, char **, struct params *, int);
92 static int	do_all(const char *, int, char **,
93 		       int (*)(int, char **, struct params *, int));
94 
95 #define CONFIG_FLAGS_FROMALL	1	/* called from configure_all() */
96 #define CONFIG_FLAGS_FROMMAIN	2	/* called from main() */
97 
98 static int	 configure_params(int, const char *, const char *,
99 				  struct params *);
100 static void	 eliminate_cores(void);
101 static bits_t	*getkey(const char *, struct keygen *, size_t);
102 static bits_t	*getkey_storedkey(const char *, struct keygen *, size_t);
103 static bits_t	*getkey_randomkey(const char *, struct keygen *, size_t, int);
104 static bits_t	*getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t,
105 				     int);
106 static bits_t	*getkey_shell_cmd(const char *, struct keygen *, size_t);
107 static char	*maybe_getpass(char *);
108 static int	 opendisk_werror(const char *, char *, size_t);
109 static int	 unconfigure_fd(int);
110 static int	 verify(struct params *, int);
111 static int	 verify_disklabel(int);
112 static int	 verify_ffs(int);
113 static int	 verify_reenter(struct params *);
114 
115 static void	 usage(void);
116 
117 /* Verbose Framework */
118 unsigned	verbose = 0;
119 
120 #define VERBOSE(x,y)	if (verbose >= x) y
121 #define VPRINTF(x,y)	if (verbose >= x) (void)printf y
122 
123 static void
124 usage(void)
125 {
126 
127 	(void)fprintf(stderr, "usage: %s [-nv] [-V vmeth] cgd dev [paramsfile]\n",
128 	    getprogname());
129 	(void)fprintf(stderr, "       %s -C [-nv] [-f configfile]\n", getprogname());
130 	(void)fprintf(stderr, "       %s -U [-nv] [-f configfile]\n", getprogname());
131 	(void)fprintf(stderr, "       %s -G [-nv] [-i ivmeth] [-k kgmeth] "
132 	    "[-o outfile] paramsfile\n", getprogname());
133 	(void)fprintf(stderr, "       %s -g [-nv] [-i ivmeth] [-k kgmeth] "
134 	    "[-o outfile] alg [keylen]\n", getprogname());
135 	(void)fprintf(stderr, "       %s -s [-nv] [-i ivmeth] cgd dev alg "
136 	    "[keylen]\n", getprogname());
137 	(void)fprintf(stderr, "       %s -u [-nv] cgd\n", getprogname());
138 	exit(EXIT_FAILURE);
139 }
140 
141 static int
142 parse_size_t(const char *s, size_t *l)
143 {
144 	char *endptr;
145 	long v;
146 
147 	errno = 0;
148 	v = strtol(s, &endptr, 10);
149 	if ((v == LONG_MIN || v == LONG_MAX) && errno)
150 		return -1;
151 	if (v < INT_MIN || v > INT_MAX) {
152 		errno = ERANGE;
153 		return -1;
154 	}
155 	if (endptr == s) {
156 		errno = EINVAL;
157 		return -1;
158 	}
159 	*l = (size_t)v;
160 	return 0;
161 }
162 
163 static void
164 set_action(enum action *action, enum action value)
165 {
166 	if (*action != ACTION_DEFAULT)
167 		usage();
168 	*action = value;
169 }
170 
171 int
172 main(int argc, char **argv)
173 {
174 	struct params *p;
175 	struct params *tp;
176 	struct keygen *kg;
177 	enum action action = ACTION_DEFAULT;
178 	int	ch;
179 	const char	*cfile = NULL;
180 	const char	*outfile = NULL;
181 
182 	setprogname(*argv);
183 	eliminate_cores();
184 	if (mlockall(MCL_FUTURE))
185 		err(EXIT_FAILURE, "Can't lock memory");
186 	p = params_new();
187 	kg = NULL;
188 
189 	while ((ch = getopt(argc, argv, "CGUV:b:f:gi:k:no:spuv")) != -1)
190 		switch (ch) {
191 		case 'C':
192 			set_action(&action, ACTION_CONFIGALL);
193 			break;
194 		case 'G':
195 			set_action(&action, ACTION_GENERATE_CONVERT);
196 			break;
197 		case 'U':
198 			set_action(&action, ACTION_UNCONFIGALL);
199 			break;
200 		case 'V':
201 			tp = params_verify_method(string_fromcharstar(optarg));
202 			if (!tp)
203 				usage();
204 			p = params_combine(p, tp);
205 			break;
206 		case 'b':
207 			{
208 				size_t size;
209 
210 				if (parse_size_t(optarg, &size) == -1)
211 					usage();
212 				tp = params_bsize(size);
213 				if (!tp)
214 					usage();
215 				p = params_combine(p, tp);
216 			}
217 			break;
218 		case 'f':
219 			if (cfile)
220 				usage();
221 			cfile = estrdup(optarg);
222 			break;
223 		case 'g':
224 			set_action(&action, ACTION_GENERATE);
225 			break;
226 		case 'i':
227 			tp = params_ivmeth(string_fromcharstar(optarg));
228 			p = params_combine(p, tp);
229 			break;
230 		case 'k':
231 			kg = keygen_method(string_fromcharstar(optarg));
232 			if (!kg)
233 				usage();
234 			keygen_addlist(&p->keygen, kg);
235 			break;
236 		case 'n':
237 			nflag = 1;
238 			break;
239 		case 'o':
240 			if (outfile)
241 				usage();
242 			outfile = estrdup(optarg);
243 			break;
244 		case 'p':
245 			pflag = PFLAG_STDIN;
246 			break;
247 		case 's':
248 			set_action(&action, ACTION_CONFIGSTDIN);
249 			break;
250 
251 		case 'u':
252 			set_action(&action, ACTION_UNCONFIGURE);
253 			break;
254 		case 'v':
255 			verbose++;
256 			break;
257 		default:
258 			usage();
259 			/* NOTREACHED */
260 		}
261 
262 	argc -= optind;
263 	argv += optind;
264 
265 	if (!outfile)
266 		outfile = "";
267 	if (!cfile)
268 		cfile = "";
269 
270 	/* validate the consistency of the arguments */
271 
272 	switch (action) {
273 	case ACTION_DEFAULT:	/* ACTION_CONFIGURE is the default */
274 	case ACTION_CONFIGURE:
275 		return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN);
276 	case ACTION_UNCONFIGURE:
277 		return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN);
278 	case ACTION_GENERATE:
279 		return generate(p, argc, argv, outfile);
280 	case ACTION_GENERATE_CONVERT:
281 		return generate_convert(p, argc, argv, outfile);
282 	case ACTION_CONFIGALL:
283 		return do_all(cfile, argc, argv, configure);
284 	case ACTION_UNCONFIGALL:
285 		return do_all(cfile, argc, argv, unconfigure);
286 	case ACTION_CONFIGSTDIN:
287 		return configure_stdin(p, argc, argv);
288 	default:
289 		errx(EXIT_FAILURE, "undefined action");
290 		/* NOTREACHED */
291 	}
292 }
293 
294 static bits_t *
295 getkey(const char *dev, struct keygen *kg, size_t len)
296 {
297 	bits_t	*ret = NULL;
298 	bits_t	*tmp;
299 
300 	VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len));
301 	for (; kg; kg=kg->next) {
302 		switch (kg->kg_method) {
303 		case KEYGEN_STOREDKEY:
304 			tmp = getkey_storedkey(dev, kg, len);
305 			break;
306 		case KEYGEN_RANDOMKEY:
307 			tmp = getkey_randomkey(dev, kg, len, 1);
308 			break;
309 		case KEYGEN_URANDOMKEY:
310 			tmp = getkey_randomkey(dev, kg, len, 0);
311 			break;
312 		case KEYGEN_PKCS5_PBKDF2_SHA1:
313 			tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
314 			break;
315 		/* provide backwards compatibility for old config files */
316 		case KEYGEN_PKCS5_PBKDF2_OLD:
317 			tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1);
318 			break;
319 		case KEYGEN_SHELL_CMD:
320 			tmp = getkey_shell_cmd(dev, kg, len);
321 			break;
322 		default:
323 			warnx("unrecognised keygen method %d in getkey()",
324 			    kg->kg_method);
325 			if (ret)
326 				bits_free(ret);
327 			return NULL;
328 		}
329 
330 		if (ret)
331 			ret = bits_xor_d(tmp, ret);
332 		else
333 			ret = tmp;
334 	}
335 
336 	return ret;
337 }
338 
339 /*ARGSUSED*/
340 static bits_t *
341 getkey_storedkey(const char *target, struct keygen *kg, size_t keylen)
342 {
343 	return bits_dup(kg->kg_key);
344 }
345 
346 /*ARGSUSED*/
347 static bits_t *
348 getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard)
349 {
350 	return bits_getrandombits(keylen, hard);
351 }
352 
353 static char *
354 maybe_getpass(char *prompt)
355 {
356 	char	 buf[1024];
357 	char	*p = buf;
358 	char	*tmp;
359 
360 	switch (pflag) {
361 	case PFLAG_GETPASS:
362 		p = getpass(prompt);
363 		break;
364 
365 	case PFLAG_STDIN:
366 		p = fgets(buf, sizeof(buf), stdin);
367 		if (p) {
368 			tmp = strchr(p, '\n');
369 			if (tmp)
370 				*tmp = '\0';
371 		}
372 		break;
373 
374 	default:
375 		errx(EXIT_FAILURE, "pflag set inappropriately?");
376 	}
377 
378 	if (!p)
379 		err(EXIT_FAILURE, "failed to read passphrase");
380 
381 	return estrdup(p);
382 }
383 
384 /*ARGSUSED*/
385 /*
386  * XXX take, and pass through, a compat flag that indicates whether we
387  * provide backwards compatibility with a previous bug.  The previous
388  * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a
389  * non-zero compat flag. The new default, and correct keygen method is
390  * called pcks5_pbkdf2/sha1.  When the old method is removed, so will
391  * be the compat argument.
392  */
393 static bits_t *
394 getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen,
395     int compat)
396 {
397 	bits_t		*ret;
398 	char		*passp;
399 	char		 buf[1024];
400 	u_int8_t	*tmp;
401 
402 	snprintf(buf, sizeof(buf), "%s's passphrase:", target);
403 	passp = maybe_getpass(buf);
404 	if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp,
405 	    strlen(passp),
406 	    bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)),
407 	    kg->kg_iterations, compat)) {
408 		warnx("failed to generate PKCS#5 PBKDF2 key");
409 		return NULL;
410 	}
411 
412 	ret = bits_new(tmp, keylen);
413 	kg->kg_key = bits_dup(ret);
414 	memset(passp, 0, strlen(passp));
415 	free(passp);
416 	free(tmp);
417 	return ret;
418 }
419 
420 /*ARGSUSED*/
421 static bits_t *
422 getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen)
423 {
424 	FILE	*f;
425 	bits_t	*ret;
426 
427 	f = popen(string_tocharstar(kg->kg_cmd), "r");
428 	ret = bits_fget(f, keylen);
429 	pclose(f);
430 
431 	return ret;
432 }
433 
434 /*ARGSUSED*/
435 static int
436 unconfigure(int argc, char **argv, struct params *inparams, int flags)
437 {
438 	int	fd;
439 	int	ret;
440 	char	buf[MAXPATHLEN] = "";
441 
442 	/* only complain about additional arguments, if called from main() */
443 	if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
444 		usage();
445 
446 	/* if called from do_all(), then ensure that 2 or 3 args exist */
447 	if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
448 		return -1;
449 
450 	fd = opendisk(*argv, O_RDWR, buf, sizeof(buf), 1);
451 	if (fd == -1) {
452 		int saved_errno = errno;
453 
454 		warn("can't open cgd \"%s\", \"%s\"", *argv, buf);
455 
456 		/* this isn't fatal with nflag != 0 */
457 		if (!nflag)
458 			return saved_errno;
459 	}
460 
461 	VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
462 
463 	if (nflag)
464 		return 0;
465 
466 	ret = unconfigure_fd(fd);
467 	(void)close(fd);
468 	return ret;
469 }
470 
471 static int
472 unconfigure_fd(int fd)
473 {
474 	struct	cgd_ioctl ci;
475 
476 	if (ioctl(fd, CGDIOCCLR, &ci) == -1) {
477 		warn("ioctl");
478 		return -1;
479 	}
480 
481 	return 0;
482 }
483 
484 /*ARGSUSED*/
485 static int
486 configure(int argc, char **argv, struct params *inparams, int flags)
487 {
488 	struct params	*p;
489 	struct keygen	*kg;
490 	int		 fd;
491 	int		 loop = 0;
492 	int		 ret;
493 	char		 cgdname[PATH_MAX];
494 
495 	if (argc == 2) {
496 		char *pfile;
497 
498 		if (asprintf(&pfile, "%s/%s",
499 		    CGDCONFIG_DIR, basename(argv[1])) == -1)
500 			return -1;
501 
502 		p = params_cget(pfile);
503 		free(pfile);
504 	} else if (argc == 3) {
505 		p = params_cget(argv[2]);
506 	} else {
507 		/* print usage and exit, only if called from main() */
508 		if (flags == CONFIG_FLAGS_FROMMAIN) {
509 			warnx("wrong number of args");
510 			usage();
511 		}
512 		return -1;
513 	}
514 
515 	if (!p)
516 		return -1;
517 
518 	/*
519 	 * over-ride with command line specifications and fill in default
520 	 * values.
521 	 */
522 
523 	p = params_combine(p, inparams);
524 	ret = params_filldefaults(p);
525 	if (ret) {
526 		params_free(p);
527 		return ret;
528 	}
529 
530 	if (!params_verify(p)) {
531 		warnx("params invalid");
532 		return -1;
533 	}
534 
535 	/*
536 	 * loop over configuring the disk and checking to see if it
537 	 * verifies properly.  We open and close the disk device each
538 	 * time, because if the user passes us the block device we
539 	 * need to flush the buffer cache.
540 	 *
541 	 * We only loop if one of the verification methods prompts for
542 	 * a password.
543 	 */
544 
545 	for (kg = p->keygen; pflag == PFLAG_GETPASS && kg; kg = kg->next)
546 		if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) ||
547 		    (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) {
548 			loop = 1;
549 			break;
550 		}
551 
552 	for (;;) {
553 		fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
554 		if (fd == -1)
555 			return -1;
556 
557 		if (p->key)
558 			bits_free(p->key);
559 
560 		p->key = getkey(argv[1], p->keygen, p->keylen);
561 		if (!p->key)
562 			goto bail_err;
563 
564 		ret = configure_params(fd, cgdname, argv[1], p);
565 		if (ret)
566 			goto bail_err;
567 
568 		ret = verify(p, fd);
569 		if (ret == -1)
570 			goto bail_err;
571 		if (!ret)
572 			break;
573 
574 		(void)unconfigure_fd(fd);
575 		(void)close(fd);
576 
577 		if (!loop) {
578 			warnx("verification failed permanently");
579 			goto bail_err;
580 		}
581 
582 		warnx("verification failed, please reenter passphrase");
583 	}
584 
585 	params_free(p);
586 	(void)close(fd);
587 	return 0;
588 bail_err:
589 	params_free(p);
590 	(void)close(fd);
591 	return -1;
592 }
593 
594 static int
595 configure_stdin(struct params *p, int argc, char **argv)
596 {
597 	int	fd;
598 	int	ret;
599 	char	cgdname[PATH_MAX];
600 
601 	if (argc < 3 || argc > 4)
602 		usage();
603 
604 	p->algorithm = string_fromcharstar(argv[2]);
605 	if (argc > 3) {
606 		size_t keylen;
607 
608 		if (parse_size_t(argv[3], &keylen) == -1) {
609 			warn("failed to parse key length");
610 			return -1;
611 		}
612 		p->keylen = keylen;
613 	}
614 
615 	ret = params_filldefaults(p);
616 	if (ret)
617 		return ret;
618 
619 	fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
620 	if (fd == -1)
621 		return -1;
622 
623 	p->key = bits_fget(stdin, p->keylen);
624 	if (!p->key) {
625 		warnx("failed to read key from stdin");
626 		return -1;
627 	}
628 
629 	return configure_params(fd, cgdname, argv[1], p);
630 }
631 
632 static int
633 opendisk_werror(const char *cgd, char *buf, size_t buflen)
634 {
635 	int	fd;
636 
637 	VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd, buf, buflen));
638 
639 	/* sanity */
640 	if (!cgd || !buf)
641 		return -1;
642 
643 	if (nflag) {
644 		if (strlcpy(buf, cgd, buflen) >= buflen)
645 			return -1;
646 		return 0;
647 	}
648 
649 	fd = opendisk(cgd, O_RDWR, buf, buflen, 0);
650 	if (fd == -1)
651 		warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
652 
653 	return fd;
654 }
655 
656 static int
657 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
658 {
659 	struct cgd_ioctl ci;
660 
661 	/* sanity */
662 	if (!cgd || !dev)
663 		return -1;
664 
665 	(void)memset(&ci, 0x0, sizeof(ci));
666 	ci.ci_disk = dev;
667 	ci.ci_alg = string_tocharstar(p->algorithm);
668 	ci.ci_ivmethod = string_tocharstar(p->ivmeth);
669 	ci.ci_key = bits_getbuf(p->key);
670 	ci.ci_keylen = p->keylen;
671 	ci.ci_blocksize = p->bsize;
672 
673 	VPRINTF(1, ("    with alg %s keylen %zu blocksize %zu ivmethod %s\n",
674 	    string_tocharstar(p->algorithm), p->keylen, p->bsize,
675 	    string_tocharstar(p->ivmeth)));
676 	VPRINTF(2, ("key: "));
677 	VERBOSE(2, bits_fprint(stdout, p->key));
678 	VPRINTF(2, ("\n"));
679 
680 	if (nflag)
681 		return 0;
682 
683 	if (ioctl(fd, CGDIOCSET, &ci) == -1) {
684 		int saved_errno = errno;
685 		warn("ioctl");
686 		return saved_errno;
687 	}
688 
689 	return 0;
690 }
691 
692 /*
693  * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
694  */
695 
696 #define SCANSIZE	8192
697 
698 static int
699 verify(struct params *p, int fd)
700 {
701 
702 	switch (p->verify_method) {
703 	case VERIFY_NONE:
704 		return 0;
705 	case VERIFY_DISKLABEL:
706 		return verify_disklabel(fd);
707 	case VERIFY_FFS:
708 		return verify_ffs(fd);
709 	case VERIFY_REENTER:
710 		return verify_reenter(p);
711 	default:
712 		warnx("unimplemented verification method");
713 		return -1;
714 	}
715 }
716 
717 static int
718 verify_disklabel(int fd)
719 {
720 	struct	disklabel l;
721 	ssize_t	ret;
722 	char	buf[SCANSIZE];
723 
724 	/*
725 	 * we simply scan the first few blocks for a disklabel, ignoring
726 	 * any MBR/filecore sorts of logic.  MSDOS and RiscOS can't read
727 	 * a cgd, anyway, so it is unlikely that there will be non-native
728 	 * partition information.
729 	 */
730 
731 	ret = pread(fd, buf, 8192, 0);
732 	if (ret < 0) {
733 		warn("can't read disklabel area");
734 		return -1;
735 	}
736 
737 	/* now scan for the disklabel */
738 
739 	return disklabel_scan(&l, buf, (size_t)ret);
740 }
741 
742 static off_t sblock_try[] = SBLOCKSEARCH;
743 
744 static int
745 verify_ffs(int fd)
746 {
747 	size_t	i;
748 
749 	for (i = 0; sblock_try[i] != -1; i++) {
750 		union {
751 		    char	buf[SBLOCKSIZE];
752 		    struct	fs fs;
753 		} u;
754 		ssize_t ret;
755 
756 		ret = pread(fd, &u, sizeof(u), sblock_try[i]);
757 		if (ret < 0) {
758 			warn("pread");
759 			break;
760 		} else if ((size_t)ret < sizeof(u)) {
761 			warnx("pread: incomplete block");
762 			break;
763 		}
764 		switch (u.fs.fs_magic) {
765 		case FS_UFS1_MAGIC:
766 		case FS_UFS2_MAGIC:
767 		case FS_UFS1_MAGIC_SWAPPED:
768 		case FS_UFS2_MAGIC_SWAPPED:
769 			return 0;
770 		default:
771 			continue;
772 		}
773 	}
774 
775 	return 1;	/* failure */
776 }
777 
778 static int
779 verify_reenter(struct params *p)
780 {
781 	struct keygen *kg;
782 	bits_t *orig_key, *key;
783 	int ret;
784 
785 	ret = 0;
786 	for (kg = p->keygen; kg && !ret; kg = kg->next) {
787 		if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
788 		    (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
789 			continue;
790 
791 		orig_key = kg->kg_key;
792 		kg->kg_key = NULL;
793 
794 		/* add a compat flag till the _OLD method goes away */
795 		key = getkey_pkcs5_pbkdf2("re-enter device", kg,
796 			bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
797 		ret = !bits_match(key, orig_key);
798 
799 		bits_free(key);
800 		bits_free(kg->kg_key);
801 		kg->kg_key = orig_key;
802 	}
803 
804 	return ret;
805 }
806 
807 static int
808 generate(struct params *p, int argc, char **argv, const char *outfile)
809 {
810 	int	 ret;
811 
812 	if (argc < 1 || argc > 2)
813 		usage();
814 
815 	p->algorithm = string_fromcharstar(argv[0]);
816 	if (argc > 1) {
817 		size_t keylen;
818 
819 		if (parse_size_t(argv[1], &keylen) == -1) {
820 			warn("Failed to parse key length");
821 			return -1;
822 		}
823 		p->keylen = keylen;
824 	}
825 
826 	ret = params_filldefaults(p);
827 	if (ret)
828 		return ret;
829 
830 	if (!p->keygen) {
831 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
832 		if (!p->keygen)
833 			return -1;
834 	}
835 
836 	if (keygen_filldefaults(p->keygen, p->keylen)) {
837 		warnx("Failed to generate defaults for keygen");
838 		return -1;
839 	}
840 
841 	if (!params_verify(p)) {
842 		warnx("invalid parameters generated");
843 		return -1;
844 	}
845 
846 	return params_cput(p, outfile);
847 }
848 
849 static int
850 generate_convert(struct params *p, int argc, char **argv, const char *outfile)
851 {
852 	struct params	*oldp;
853 	struct keygen	*kg;
854 
855 	if (argc != 1)
856 		usage();
857 
858 	oldp = params_cget(*argv);
859 	if (!oldp)
860 		return -1;
861 
862 	/* for sanity, we ensure that none of the keygens are randomkey */
863 	for (kg=p->keygen; kg; kg=kg->next)
864 		if (kg->kg_method == KEYGEN_RANDOMKEY)
865 			goto bail;
866 	for (kg=oldp->keygen; kg; kg=kg->next)
867 		if (kg->kg_method == KEYGEN_RANDOMKEY)
868 			goto bail;
869 
870 	if (!params_verify(oldp)) {
871 		warnx("invalid old parameters file \"%s\"", *argv);
872 		return -1;
873 	}
874 
875 	oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
876 
877 	/* we copy across the non-keygen info, here. */
878 
879 	string_free(p->algorithm);
880 	string_free(p->ivmeth);
881 
882 	p->algorithm = string_dup(oldp->algorithm);
883 	p->ivmeth = string_dup(oldp->ivmeth);
884 	p->keylen = oldp->keylen;
885 	p->bsize = oldp->bsize;
886 	if (p->verify_method == VERIFY_UNKNOWN)
887 		p->verify_method = oldp->verify_method;
888 
889 	params_free(oldp);
890 
891 	if (!p->keygen) {
892 		p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
893 		if (!p->keygen)
894 			return -1;
895 	}
896 	(void)params_filldefaults(p);
897 	(void)keygen_filldefaults(p->keygen, p->keylen);
898 	p->key = getkey("new file", p->keygen, p->keylen);
899 
900 	kg = keygen_generate(KEYGEN_STOREDKEY);
901 	kg->kg_key = bits_xor(p->key, oldp->key);
902 	keygen_addlist(&p->keygen, kg);
903 
904 	if (!params_verify(p)) {
905 		warnx("can't generate new parameters file");
906 		return -1;
907 	}
908 
909 	return params_cput(p, outfile);
910 bail:
911 	params_free(oldp);
912 	return -1;
913 }
914 
915 static int
916 /*ARGSUSED*/
917 do_all(const char *cfile, int argc, char **argv,
918        int (*conf)(int, char **, struct params *, int))
919 {
920 	FILE		 *f;
921 	size_t		  len;
922 	size_t		  lineno;
923 	int		  my_argc;
924 	int		  ret;
925 	const char	 *fn;
926 	char		 *line;
927 	char		**my_argv;
928 
929 	if (argc > 0)
930 		usage();
931 
932 	if (!cfile[0])
933 		fn = CGDCONFIG_CFILE;
934 	else
935 		fn = cfile;
936 
937 	f = fopen(fn, "r");
938 	if (!f) {
939 		warn("could not open config file \"%s\"", fn);
940 		return -1;
941 	}
942 
943 	ret = chdir(CGDCONFIG_DIR);
944 	if (ret == -1)
945 		warn("could not chdir to %s", CGDCONFIG_DIR);
946 
947 	ret = 0;
948 	lineno = 0;
949 	for (;;) {
950 		line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
951 		if (!line)
952 			break;
953 		if (!*line)
954 			continue;
955 
956 		my_argv = words(line, &my_argc);
957 		ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
958 		if (ret) {
959 			warnx("action failed on \"%s\" line %lu", fn,
960 			    (u_long)lineno);
961 			break;
962 		}
963 		words_free(my_argv, my_argc);
964 	}
965 	return ret;
966 }
967 
968 static void
969 eliminate_cores(void)
970 {
971 	struct rlimit	rlp;
972 
973 	rlp.rlim_cur = 0;
974 	rlp.rlim_max = 0;
975 	if (setrlimit(RLIMIT_CORE, &rlp) == -1)
976 		err(EXIT_FAILURE, "Can't disable cores");
977 }
978