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