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