cgdconfig.c revision 1.43 1 /* $NetBSD: cgdconfig.c,v 1.43 2018/05/06 20:55:42 kre 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.43 2018/05/06 20:55:42 kre 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_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 devicename[PATH_MAX];
516 const char *dev = NULL; /* XXX: gcc */
517
518 if ((
519 fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open)
520 ) != -1) {
521 struct cgd_user cgu;
522
523 cgu.cgu_unit = -1;
524 if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) {
525 warnx("device %s already in use", *argv);
526 prog_close(fd);
527 return -1;
528 }
529 prog_close(fd);
530 }
531
532 if (argc == 2 || argc == 3) {
533 dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
534 if (dev == NULL) {
535 warnx("getfsspecname failed: %s", devicename);
536 return -1;
537 }
538 }
539
540 if (argc == 2) {
541 char pfile[MAXPATHLEN];
542
543 /* make string writable for basename */
544 strlcpy(pfile, dev, sizeof(pfile));
545 p = params_cget(basename(pfile));
546 } else if (argc == 3) {
547 p = params_cget(argv[2]);
548 } else {
549 /* print usage and exit, only if called from main() */
550 if (flags == CONFIG_FLAGS_FROMMAIN) {
551 warnx("wrong number of args");
552 usage();
553 }
554 return -1;
555 }
556
557 if (!p)
558 return -1;
559
560 /*
561 * over-ride with command line specifications and fill in default
562 * values.
563 */
564
565 p = params_combine(p, inparams);
566 ret = params_filldefaults(p);
567 if (ret) {
568 params_free(p);
569 return ret;
570 }
571
572 if (!params_verify(p)) {
573 warnx("params invalid");
574 return -1;
575 }
576
577 /*
578 * loop over configuring the disk and checking to see if it
579 * verifies properly. We open and close the disk device each
580 * time, because if the user passes us the block device we
581 * need to flush the buffer cache.
582 *
583 * We only loop if one of the verification methods prompts for
584 * a password.
585 */
586
587 for (kg = p->keygen; pflag == PFLAG_GETPASS && kg; kg = kg->next)
588 if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) ||
589 (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) {
590 loop = 1;
591 break;
592 }
593
594 for (;;) {
595 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
596 if (fd == -1)
597 return -1;
598
599 if (p->key)
600 bits_free(p->key);
601
602 p->key = getkey(argv[1], p->keygen, p->keylen);
603 if (!p->key)
604 goto bail_err;
605
606 ret = configure_params(fd, cgdname, dev, p);
607 if (ret)
608 goto bail_err;
609
610 ret = verify(p, fd);
611 if (ret == -1)
612 goto bail_err;
613 if (!ret)
614 break;
615
616 (void)unconfigure_fd(fd);
617 (void)prog_close(fd);
618
619 if (!loop) {
620 warnx("verification failed permanently");
621 goto bail_err;
622 }
623
624 warnx("verification failed, please reenter passphrase");
625 }
626
627 params_free(p);
628 (void)prog_close(fd);
629 return 0;
630 bail_err:
631 params_free(p);
632 (void)prog_close(fd);
633 return -1;
634 }
635
636 static int
637 configure_stdin(struct params *p, int argc, char **argv)
638 {
639 int fd;
640 int ret;
641 char cgdname[PATH_MAX];
642 char devicename[PATH_MAX];
643 const char *dev;
644
645 if (argc < 3 || argc > 4)
646 usage();
647
648 dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
649 if (dev == NULL) {
650 warnx("getfsspecname failed: %s", devicename);
651 return -1;
652 }
653
654 p->algorithm = string_fromcharstar(argv[2]);
655 if (argc > 3) {
656 size_t keylen;
657
658 if (parse_size_t(argv[3], &keylen) == -1) {
659 warn("failed to parse key length");
660 return -1;
661 }
662 p->keylen = keylen;
663 }
664
665 ret = params_filldefaults(p);
666 if (ret)
667 return ret;
668
669 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
670 if (fd == -1)
671 return -1;
672
673 p->key = bits_fget(stdin, p->keylen);
674 if (!p->key) {
675 warnx("failed to read key from stdin");
676 return -1;
677 }
678
679 return configure_params(fd, cgdname, dev, p);
680 }
681
682 static int
683 opendisk_werror(const char *cgd, char *buf, size_t buflen)
684 {
685 int fd;
686
687 VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd, buf, buflen));
688
689 /* sanity */
690 if (!cgd || !buf)
691 return -1;
692
693 if (nflag) {
694 if (strlcpy(buf, cgd, buflen) >= buflen)
695 return -1;
696 return 0;
697 }
698
699 fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open);
700 if (fd == -1)
701 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
702
703 return fd;
704 }
705
706 static int
707 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
708 {
709 struct cgd_ioctl ci;
710
711 /* sanity */
712 if (!cgd || !dev)
713 return -1;
714
715 (void)memset(&ci, 0x0, sizeof(ci));
716 ci.ci_disk = dev;
717 ci.ci_alg = string_tocharstar(p->algorithm);
718 ci.ci_ivmethod = string_tocharstar(p->ivmeth);
719 ci.ci_key = bits_getbuf(p->key);
720 ci.ci_keylen = p->keylen;
721 ci.ci_blocksize = p->bsize;
722
723 VPRINTF(1, (" with alg %s keylen %zu blocksize %zu ivmethod %s\n",
724 string_tocharstar(p->algorithm), p->keylen, p->bsize,
725 string_tocharstar(p->ivmeth)));
726 VPRINTF(2, ("key: "));
727 VERBOSE(2, bits_fprint(stdout, p->key));
728 VPRINTF(2, ("\n"));
729
730 if (nflag)
731 return 0;
732
733 if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) {
734 int saved_errno = errno;
735 warn("ioctl");
736 return saved_errno;
737 }
738
739 return 0;
740 }
741
742 /*
743 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
744 */
745
746 #define SCANSIZE 8192
747
748 static int
749 verify(struct params *p, int fd)
750 {
751
752 switch (p->verify_method) {
753 case VERIFY_NONE:
754 return 0;
755 case VERIFY_DISKLABEL:
756 return verify_disklabel(fd);
757 case VERIFY_FFS:
758 return verify_ffs(fd);
759 case VERIFY_REENTER:
760 return verify_reenter(p);
761 case VERIFY_MBR:
762 return verify_mbr(fd);
763 case VERIFY_GPT:
764 return verify_gpt(fd);
765 default:
766 warnx("unimplemented verification method");
767 return -1;
768 }
769 }
770
771 static int
772 verify_disklabel(int fd)
773 {
774 struct disklabel l;
775 ssize_t ret;
776 char buf[SCANSIZE];
777
778 /*
779 * we simply scan the first few blocks for a disklabel, ignoring
780 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read
781 * a cgd, anyway, so it is unlikely that there will be non-native
782 * partition information.
783 */
784
785 ret = prog_pread(fd, buf, SCANSIZE, 0);
786 if (ret < 0) {
787 warn("can't read disklabel area");
788 return -1;
789 }
790
791 /* now scan for the disklabel */
792
793 return disklabel_scan(&l, buf, (size_t)ret);
794 }
795
796 static int
797 verify_mbr(int fd)
798 {
799 struct mbr_sector mbr;
800 ssize_t ret;
801 char buf[SCANSIZE];
802
803 /*
804 * we read the first blocks to avoid sector size issues and
805 * verify the MBR in the beginning
806 */
807
808 ret = prog_pread(fd, buf, SCANSIZE, 0);
809 if (ret < 0) {
810 warn("can't read mbr area");
811 return -1;
812 }
813
814 memcpy(&mbr, buf, sizeof(mbr));
815 if (le16toh(mbr.mbr_magic) != MBR_MAGIC)
816 return -1;
817
818 return 0;
819 }
820
821 static uint32_t crc32_tab[] = {
822 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
823 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
824 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
825 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
826 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
827 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
828 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
829 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
830 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
831 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
832 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
833 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
834 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
835 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
836 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
837 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
838 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
839 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
840 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
841 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
842 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
843 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
844 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
845 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
846 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
847 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
848 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
849 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
850 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
851 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
852 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
853 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
854 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
855 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
856 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
857 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
858 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
859 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
860 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
861 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
862 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
863 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
864 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
865 };
866
867 static uint32_t
868 crc32(const void *buf, size_t size)
869 {
870 const uint8_t *p;
871 uint32_t crc;
872
873 p = buf;
874 crc = ~0U;
875
876 while (size--)
877 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
878
879 return crc ^ ~0U;
880 }
881
882 static int
883 verify_gpt(int fd)
884 {
885 struct gpt_hdr hdr;
886 ssize_t ret;
887 char buf[SCANSIZE];
888 unsigned blksize;
889 size_t off;
890
891 /*
892 * we read the first blocks to avoid sector size issues and
893 * verify the GPT header.
894 */
895
896 ret = prog_pread(fd, buf, SCANSIZE, 0);
897 if (ret < 0) {
898 warn("can't read gpt area");
899 return -1;
900 }
901
902 ret = -1;
903 for (blksize=DEV_BSIZE;
904 (off = blksize * GPT_HDR_BLKNO) <= SCANSIZE - sizeof(hdr);
905 blksize <<= 1) {
906
907 memcpy(&hdr, &buf[off], sizeof(hdr));
908 if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0 &&
909 le32toh(hdr.hdr_revision) == GPT_HDR_REVISION &&
910 le32toh(hdr.hdr_size) == GPT_HDR_SIZE) {
911
912 hdr.hdr_crc_self = 0;
913 if (crc32(&hdr, sizeof(hdr))) {
914 ret = 0;
915 break;
916 }
917 }
918 }
919
920 return ret;
921 }
922
923 static off_t sblock_try[] = SBLOCKSEARCH;
924
925 static int
926 verify_ffs(int fd)
927 {
928 size_t i;
929
930 for (i = 0; sblock_try[i] != -1; i++) {
931 union {
932 char buf[SBLOCKSIZE];
933 struct fs fs;
934 } u;
935 ssize_t ret;
936
937 ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]);
938 if (ret < 0) {
939 warn("pread");
940 break;
941 } else if ((size_t)ret < sizeof(u)) {
942 warnx("pread: incomplete block");
943 break;
944 }
945 switch (u.fs.fs_magic) {
946 case FS_UFS1_MAGIC:
947 case FS_UFS2_MAGIC:
948 case FS_UFS1_MAGIC_SWAPPED:
949 case FS_UFS2_MAGIC_SWAPPED:
950 return 0;
951 default:
952 continue;
953 }
954 }
955
956 return 1; /* failure */
957 }
958
959 static int
960 verify_reenter(struct params *p)
961 {
962 struct keygen *kg;
963 bits_t *orig_key, *key;
964 int ret;
965
966 ret = 0;
967 for (kg = p->keygen; kg && !ret; kg = kg->next) {
968 if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
969 (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
970 continue;
971
972 orig_key = kg->kg_key;
973 kg->kg_key = NULL;
974
975 /* add a compat flag till the _OLD method goes away */
976 key = getkey_pkcs5_pbkdf2("re-enter device", kg,
977 bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
978 ret = !bits_match(key, orig_key);
979
980 bits_free(key);
981 bits_free(kg->kg_key);
982 kg->kg_key = orig_key;
983 }
984
985 return ret;
986 }
987
988 static int
989 generate(struct params *p, int argc, char **argv, const char *outfile)
990 {
991 int ret;
992
993 if (argc < 1 || argc > 2)
994 usage();
995
996 p->algorithm = string_fromcharstar(argv[0]);
997 if (argc > 1) {
998 size_t keylen;
999
1000 if (parse_size_t(argv[1], &keylen) == -1) {
1001 warn("Failed to parse key length");
1002 return -1;
1003 }
1004 p->keylen = keylen;
1005 }
1006
1007 ret = params_filldefaults(p);
1008 if (ret)
1009 return ret;
1010
1011 if (!p->keygen) {
1012 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
1013 if (!p->keygen)
1014 return -1;
1015 }
1016
1017 if (keygen_filldefaults(p->keygen, p->keylen)) {
1018 warnx("Failed to generate defaults for keygen");
1019 return -1;
1020 }
1021
1022 if (!params_verify(p)) {
1023 warnx("invalid parameters generated");
1024 return -1;
1025 }
1026
1027 return params_cput(p, outfile);
1028 }
1029
1030 static int
1031 generate_convert(struct params *p, int argc, char **argv, const char *outfile)
1032 {
1033 struct params *oldp;
1034 struct keygen *kg;
1035
1036 if (argc != 1)
1037 usage();
1038
1039 oldp = params_cget(*argv);
1040 if (!oldp)
1041 return -1;
1042
1043 /* for sanity, we ensure that none of the keygens are randomkey */
1044 for (kg=p->keygen; kg; kg=kg->next)
1045 if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
1046 (kg->kg_method == KEYGEN_URANDOMKEY)) {
1047 warnx("can't preserve randomly generated key");
1048 goto bail;
1049 }
1050 for (kg=oldp->keygen; kg; kg=kg->next)
1051 if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
1052 (kg->kg_method == KEYGEN_URANDOMKEY)) {
1053 warnx("can't preserve randomly generated key");
1054 goto bail;
1055 }
1056
1057 if (!params_verify(oldp)) {
1058 warnx("invalid old parameters file \"%s\"", *argv);
1059 return -1;
1060 }
1061
1062 oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
1063
1064 /* we copy across the non-keygen info, here. */
1065
1066 string_free(p->algorithm);
1067 string_free(p->ivmeth);
1068
1069 p->algorithm = string_dup(oldp->algorithm);
1070 p->ivmeth = string_dup(oldp->ivmeth);
1071 p->keylen = oldp->keylen;
1072 p->bsize = oldp->bsize;
1073 if (p->verify_method == VERIFY_UNKNOWN)
1074 p->verify_method = oldp->verify_method;
1075
1076 params_free(oldp);
1077
1078 if (!p->keygen) {
1079 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
1080 if (!p->keygen)
1081 return -1;
1082 }
1083 (void)params_filldefaults(p);
1084 (void)keygen_filldefaults(p->keygen, p->keylen);
1085 p->key = getkey("new file", p->keygen, p->keylen);
1086
1087 kg = keygen_generate(KEYGEN_STOREDKEY);
1088 kg->kg_key = bits_xor(p->key, oldp->key);
1089 keygen_addlist(&p->keygen, kg);
1090
1091 if (!params_verify(p)) {
1092 warnx("can't generate new parameters file");
1093 return -1;
1094 }
1095
1096 return params_cput(p, outfile);
1097 bail:
1098 params_free(oldp);
1099 return -1;
1100 }
1101
1102 static int
1103 /*ARGSUSED*/
1104 do_all(const char *cfile, int argc, char **argv,
1105 int (*conf)(int, char **, struct params *, int))
1106 {
1107 FILE *f;
1108 size_t len;
1109 size_t lineno;
1110 int my_argc;
1111 int ret;
1112 const char *fn;
1113 char *line;
1114 char **my_argv;
1115
1116 if (argc > 0)
1117 usage();
1118
1119 if (!cfile[0])
1120 fn = CGDCONFIG_CFILE;
1121 else
1122 fn = cfile;
1123
1124 f = fopen(fn, "r");
1125 if (!f) {
1126 warn("could not open config file \"%s\"", fn);
1127 return -1;
1128 }
1129
1130 ret = 0;
1131 lineno = 0;
1132 for (;;) {
1133 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
1134 if (!line)
1135 break;
1136 if (!*line)
1137 continue;
1138
1139 my_argv = words(line, &my_argc);
1140 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
1141 if (ret) {
1142 warnx("action failed on \"%s\" line %lu", fn,
1143 (u_long)lineno);
1144 break;
1145 }
1146 words_free(my_argv, my_argc);
1147 }
1148 return ret;
1149 }
1150
1151 static const char *
1152 iv_method(int mode)
1153 {
1154
1155 switch (mode) {
1156 case CGD_CIPHER_CBC_ENCBLKNO8:
1157 return "encblkno8";
1158 case CGD_CIPHER_CBC_ENCBLKNO1:
1159 return "encblkno1";
1160 default:
1161 return "unknown";
1162 }
1163 }
1164
1165
1166 static void
1167 show(const char *dev) {
1168 char path[64];
1169 struct cgd_user cgu;
1170 int fd;
1171
1172 fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0);
1173 if (fd == -1) {
1174 warn("open: %s", dev);
1175 return;
1176 }
1177
1178 cgu.cgu_unit = -1;
1179 if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) {
1180 close(fd);
1181 err(1, "CGDIOCGET");
1182 }
1183
1184 printf("%s: ", dev);
1185
1186 if (cgu.cgu_dev == 0) {
1187 printf("not in use");
1188 goto out;
1189 }
1190
1191 dev = devname(cgu.cgu_dev, S_IFBLK);
1192 if (dev != NULL)
1193 printf("%s ", dev);
1194 else
1195 printf("dev %llu,%llu ", (unsigned long long)major(cgu.cgu_dev),
1196 (unsigned long long)minor(cgu.cgu_dev));
1197
1198 if (verbose)
1199 printf("%s ", cgu.cgu_alg);
1200 if (verbose > 1) {
1201 printf("keylen %d ", cgu.cgu_keylen);
1202 printf("blksize %zd ", cgu.cgu_blocksize);
1203 printf("%s ", iv_method(cgu.cgu_mode));
1204 }
1205
1206 out:
1207 putchar('\n');
1208 close(fd);
1209 }
1210
1211 static int
1212 do_list(int argc, char **argv)
1213 {
1214
1215 if (argc != 0 && argc != 1)
1216 usage();
1217
1218 if (argc) {
1219 show(argv[0]);
1220 return 0;
1221 }
1222
1223 DIR *dirp;
1224 struct dirent *dp;
1225 __BITMAP_TYPE(, uint32_t, 65536) bm;
1226
1227 __BITMAP_ZERO(&bm);
1228
1229 if ((dirp = opendir(_PATH_DEV)) == NULL)
1230 err(1, "opendir: %s", _PATH_DEV);
1231
1232 while ((dp = readdir(dirp)) != NULL) {
1233 char *ep;
1234 if (strncmp(dp->d_name, "rcgd", 4) != 0)
1235 continue;
1236 errno = 0;
1237 int n = (int)strtol(dp->d_name + 4, &ep, 0);
1238 if (ep == dp->d_name + 4 || errno != 0) {
1239 warnx("bad name %s", dp->d_name);
1240 continue;
1241 }
1242 *ep = '\0';
1243 if (__BITMAP_ISSET(n, &bm))
1244 continue;
1245 __BITMAP_SET(n, &bm);
1246 show(dp->d_name + 1);
1247 }
1248
1249 closedir(dirp);
1250 return 0;
1251 }
1252
1253 static void
1254 eliminate_cores(void)
1255 {
1256 struct rlimit rlp;
1257
1258 rlp.rlim_cur = 0;
1259 rlp.rlim_max = 0;
1260 if (setrlimit(RLIMIT_CORE, &rlp) == -1)
1261 err(EXIT_FAILURE, "Can't disable cores");
1262 }
1263