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