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