cgdconfig.c revision 1.58 1 /* $NetBSD: cgdconfig.c,v 1.58 2022/08/12 10:49:47 riastradh 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.58 2022/08/12 10:49:47 riastradh Exp $");
37 #endif
38
39 #ifdef HAVE_ARGON2
40 #include <argon2.h>
41 #endif
42 #include <assert.h>
43 #include <err.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <libgen.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <util.h>
52 #include <paths.h>
53 #include <dirent.h>
54
55 /* base64 gunk */
56 #include <netinet/in.h>
57 #include <arpa/nameser.h>
58 #include <resolv.h>
59
60 #include <sys/ioctl.h>
61 #include <sys/stat.h>
62 #include <sys/bootblock.h>
63 #include <sys/disklabel.h>
64 #include <sys/disklabel_gpt.h>
65 #include <sys/mman.h>
66 #include <sys/param.h>
67 #include <sys/resource.h>
68 #include <sys/statvfs.h>
69 #include <sys/bitops.h>
70 #include <sys/queue.h>
71
72 #include <dev/cgdvar.h>
73
74 #include <ufs/ffs/fs.h>
75
76 #include "params.h"
77 #include "pkcs5_pbkdf2.h"
78 #include "utils.h"
79 #include "cgdconfig.h"
80 #include "prog_ops.h"
81 #include "hkdf_hmac_sha256.h"
82
83 #define CGDCONFIG_CFILE CGDCONFIG_DIR "/cgd.conf"
84
85 enum action {
86 ACTION_DEFAULT, /* default -> configure */
87 ACTION_CONFIGURE, /* configure, with paramsfile */
88 ACTION_UNCONFIGURE, /* unconfigure */
89 ACTION_GENERATE, /* generate a paramsfile */
90 ACTION_GENERATE_CONVERT, /* generate a ``dup'' paramsfile */
91 ACTION_CONFIGALL, /* configure all from config file */
92 ACTION_UNCONFIGALL, /* unconfigure all from config file */
93 ACTION_CONFIGSTDIN, /* configure, key from stdin */
94 ACTION_LIST, /* list configured devices */
95 ACTION_PRINTKEY, /* print key to stdout */
96 ACTION_PRINTALLKEYS, /* print all keys to stdout */
97 };
98
99 /* if nflag is set, do not configure/unconfigure the cgd's */
100
101 int nflag = 0;
102
103 /* if Sflag is set, generate shared keys */
104
105 int Sflag = 0;
106
107 /* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */
108
109 #define PFLAG_GETPASS 0x01
110 #define PFLAG_GETPASS_ECHO 0x02
111 #define PFLAG_GETPASS_MASK 0x03
112 #define PFLAG_STDIN 0x04
113 int pflag = PFLAG_GETPASS;
114
115 /*
116 * When configuring all cgds, save a cache of shared keys for key
117 * derivation.
118 */
119
120 struct sharedkey {
121 int alg;
122 string_t *id;
123 bits_t *key;
124 LIST_ENTRY(sharedkey) list;
125 };
126 LIST_HEAD(, sharedkey) sharedkeys;
127
128 static int configure(int, char **, struct params *, int);
129 static int configure_stdin(struct params *, int argc, char **);
130 static int generate(struct params *, int, char **, const char *,
131 const char *);
132 static int generate_convert(struct params *, int, char **, const char *,
133 const char *);
134 static int unconfigure(int, char **, struct params *, int);
135 static int do_all(const char *, int, char **,
136 int (*)(int, char **, struct params *, int));
137 static int do_list(int, char **);
138 static int printkey(const char *, const char *, const char *, ...)
139 __printflike(3,4);
140 static int printkey1(int, char **, struct params *, int);
141 static int do_printkey(int, char **);
142
143 #define CONFIG_FLAGS_FROMALL 1 /* called from configure_all() */
144 #define CONFIG_FLAGS_FROMMAIN 2 /* called from main() */
145
146 static int configure_params(int, const char *, const char *,
147 struct params *);
148 static void eliminate_cores(void);
149 static bits_t *getkey(const char *, struct keygen *, size_t);
150 static bits_t *getkey_storedkey(const char *, struct keygen *, size_t);
151 static bits_t *getkey_randomkey(const char *, struct keygen *, size_t, int);
152 #ifdef HAVE_ARGON2
153 static bits_t *getkey_argon2id(const char *, struct keygen *, size_t);
154 #endif
155 static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t,
156 int);
157 static bits_t *getkey_shell_cmd(const char *, struct keygen *, size_t);
158 static char *maybe_getpass(char *);
159 static int opendisk_werror(const char *, char *, size_t);
160 static int unconfigure_fd(int);
161 static int verify(struct params *, int);
162 static int verify_disklabel(int);
163 static int verify_ffs(int);
164 static int verify_reenter(struct params *);
165 static int verify_mbr(int);
166 static int verify_gpt(int);
167
168 __dead static void usage(void);
169
170 /* Verbose Framework */
171 unsigned verbose = 0;
172
173 #define VERBOSE(x,y) if (verbose >= x) y
174 #define VPRINTF(x,y) if (verbose >= x) (void)printf y
175
176 static void
177 usage(void)
178 {
179
180 (void)fprintf(stderr, "usage: %s [-enpv] [-V vmeth] cgd dev "
181 "[paramsfile]\n", getprogname());
182 (void)fprintf(stderr, " %s -C [-enpv] [-f configfile]\n",
183 getprogname());
184 (void)fprintf(stderr, " %s -G [-enpSv] [-i ivmeth] [-k kgmeth] "
185 "[-P paramsfile] [-o outfile] paramsfile\n", getprogname());
186 (void)fprintf(stderr, " %s -g [-Sv] [-i ivmeth] [-k kgmeth] "
187 "[-P paramsfile] [-o outfile] alg [keylen]\n", getprogname());
188 (void)fprintf(stderr, " %s -l [-v[v]] [cgd]\n", getprogname());
189 (void)fprintf(stderr, " %s -s [-nv] [-i ivmeth] cgd dev alg "
190 "[keylen]\n", getprogname());
191 (void)fprintf(stderr, " %s -t paramsfile\n", getprogname());
192 (void)fprintf(stderr, " %s -T [-f configfile]\n", getprogname());
193 (void)fprintf(stderr, " %s -U [-nv] [-f configfile]\n",
194 getprogname());
195 (void)fprintf(stderr, " %s -u [-nv] cgd\n", getprogname());
196 exit(EXIT_FAILURE);
197 }
198
199 static int
200 parse_size_t(const char *s, size_t *l)
201 {
202 char *endptr;
203 long v;
204
205 errno = 0;
206 v = strtol(s, &endptr, 10);
207 if ((v == LONG_MIN || v == LONG_MAX) && errno)
208 return -1;
209 if (v < INT_MIN || v > INT_MAX) {
210 errno = ERANGE;
211 return -1;
212 }
213 if (endptr == s) {
214 errno = EINVAL;
215 return -1;
216 }
217 *l = (size_t)v;
218 return 0;
219 }
220
221 static void
222 set_action(enum action *action, enum action value)
223 {
224 if (*action != ACTION_DEFAULT)
225 usage();
226 *action = value;
227 }
228
229 int
230 main(int argc, char **argv)
231 {
232 struct params *p;
233 struct params *tp;
234 struct keygen *kg;
235 enum action action = ACTION_DEFAULT;
236 int ch;
237 const char *cfile = NULL;
238 const char *outfile = NULL;
239 const char *Pfile = NULL;
240
241 setprogname(*argv);
242 if (hkdf_hmac_sha256_selftest())
243 err(EXIT_FAILURE, "Crypto self-test failed");
244 eliminate_cores();
245 if (mlockall(MCL_FUTURE))
246 err(EXIT_FAILURE, "Can't lock memory");
247 p = params_new();
248 kg = NULL;
249
250 while ((ch = getopt(argc, argv, "CGP:STUV:b:ef:gi:k:lno:sptuv")) != -1)
251 switch (ch) {
252 case 'C':
253 set_action(&action, ACTION_CONFIGALL);
254 break;
255 case 'G':
256 set_action(&action, ACTION_GENERATE_CONVERT);
257 break;
258 case 'P':
259 if (Pfile)
260 usage();
261 Pfile = estrdup(optarg);
262 break;
263 case 'S':
264 Sflag = 1;
265 break;
266 case 'T':
267 set_action(&action, ACTION_PRINTALLKEYS);
268 break;
269 case 'U':
270 set_action(&action, ACTION_UNCONFIGALL);
271 break;
272 case 'V':
273 tp = params_verify_method(string_fromcharstar(optarg));
274 if (!tp)
275 usage();
276 p = params_combine(p, tp);
277 break;
278 case 'b':
279 {
280 size_t size;
281
282 if (parse_size_t(optarg, &size) == -1)
283 usage();
284 tp = params_bsize(size);
285 if (!tp)
286 usage();
287 p = params_combine(p, tp);
288 }
289 break;
290 case 'e':
291 pflag = PFLAG_GETPASS_ECHO;
292 break;
293 case 'f':
294 if (cfile)
295 usage();
296 cfile = estrdup(optarg);
297 break;
298 case 'g':
299 set_action(&action, ACTION_GENERATE);
300 break;
301 case 'i':
302 tp = params_ivmeth(string_fromcharstar(optarg));
303 p = params_combine(p, tp);
304 break;
305 case 'k':
306 kg = keygen_method(string_fromcharstar(optarg));
307 if (!kg)
308 usage();
309 keygen_addlist(&p->keygen, kg);
310 break;
311 case 'l':
312 set_action(&action, ACTION_LIST);
313 break;
314 case 'n':
315 nflag = 1;
316 break;
317 case 'o':
318 if (outfile)
319 usage();
320 outfile = estrdup(optarg);
321 break;
322 case 'p':
323 pflag = PFLAG_STDIN;
324 break;
325 case 's':
326 set_action(&action, ACTION_CONFIGSTDIN);
327 break;
328 case 't':
329 set_action(&action, ACTION_PRINTKEY);
330 break;
331 case 'u':
332 set_action(&action, ACTION_UNCONFIGURE);
333 break;
334 case 'v':
335 verbose++;
336 break;
337 default:
338 usage();
339 /* NOTREACHED */
340 }
341
342 argc -= optind;
343 argv += optind;
344
345 if (!outfile)
346 outfile = "";
347 if (!cfile)
348 cfile = "";
349
350 if (prog_init && prog_init() == -1)
351 err(1, "init failed");
352
353 /* validate the consistency of the arguments */
354 if (Pfile != NULL &&
355 action != ACTION_GENERATE &&
356 action != ACTION_GENERATE_CONVERT) {
357 warnx("-P is only for use with -g/-G action");
358 usage();
359 }
360 if (Pfile != NULL && !Sflag) {
361 warnx("-P only makes sense with -S flag");
362 }
363 if (Sflag &&
364 action != ACTION_GENERATE &&
365 action != ACTION_GENERATE_CONVERT) {
366 warnx("-S is only for use with -g/-G action");
367 usage();
368 }
369
370 switch (action) {
371 case ACTION_DEFAULT: /* ACTION_CONFIGURE is the default */
372 case ACTION_CONFIGURE:
373 return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN);
374 case ACTION_UNCONFIGURE:
375 return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN);
376 case ACTION_GENERATE:
377 return generate(p, argc, argv, outfile, Pfile);
378 case ACTION_GENERATE_CONVERT:
379 return generate_convert(p, argc, argv, outfile, Pfile);
380 case ACTION_CONFIGALL:
381 return do_all(cfile, argc, argv, configure);
382 case ACTION_UNCONFIGALL:
383 return do_all(cfile, argc, argv, unconfigure);
384 case ACTION_CONFIGSTDIN:
385 return configure_stdin(p, argc, argv);
386 case ACTION_LIST:
387 return do_list(argc, argv);
388 case ACTION_PRINTKEY:
389 return do_printkey(argc, argv);
390 case ACTION_PRINTALLKEYS:
391 return do_all(cfile, argc, argv, printkey1);
392 default:
393 errx(EXIT_FAILURE, "undefined action");
394 /* NOTREACHED */
395 }
396 }
397
398 static bits_t *
399 getsubkey_hkdf_hmac_sha256(bits_t *key, bits_t *info, size_t subkeylen)
400 {
401 bits_t *ret = NULL;
402 uint8_t *tmp;
403
404 tmp = emalloc(BITS2BYTES(subkeylen));
405 if (hkdf_hmac_sha256(tmp, BITS2BYTES(subkeylen),
406 bits_getbuf(key), BITS2BYTES(bits_len(key)),
407 bits_getbuf(info), BITS2BYTES(bits_len(info)))) {
408 warnx("failed to derive HKDF-HMAC-SHA256 subkey");
409 goto out;
410 }
411
412 ret = bits_new(tmp, subkeylen);
413
414 out: free(tmp);
415 return ret;
416 }
417
418 static bits_t *
419 getsubkey(int alg, bits_t *key, bits_t *info, size_t subkeylen)
420 {
421
422 switch (alg) {
423 case SHARED_ALG_HKDF_HMAC_SHA256:
424 return getsubkey_hkdf_hmac_sha256(key, info, subkeylen);
425 default:
426 warnx("unrecognised shared key derivation method %d", alg);
427 return NULL;
428 }
429 }
430
431 static bits_t *
432 getkey(const char *dev, struct keygen *kg, size_t len0)
433 {
434 bits_t *ret = NULL;
435 bits_t *tmp;
436
437 VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len0));
438 for (; kg; kg=kg->next) {
439 struct sharedkey *sk = NULL;
440 size_t len = len0;
441
442 /*
443 * If shared, determine the shared key's length and
444 * probe the cache of shared keys.
445 */
446 if (kg->kg_sharedid) {
447 const char *id = string_tocharstar(kg->kg_sharedid);
448
449 len = kg->kg_sharedlen;
450 LIST_FOREACH(sk, &sharedkeys, list) {
451 if (kg->kg_sharedalg == sk->alg &&
452 kg->kg_sharedlen == bits_len(sk->key) &&
453 strcmp(id, string_tocharstar(sk->id)) == 0)
454 break;
455 }
456 if (sk) {
457 tmp = sk->key;
458 goto derive;
459 }
460 }
461
462 switch (kg->kg_method) {
463 case KEYGEN_STOREDKEY:
464 tmp = getkey_storedkey(dev, kg, len);
465 break;
466 case KEYGEN_RANDOMKEY:
467 tmp = getkey_randomkey(dev, kg, len, 1);
468 break;
469 case KEYGEN_URANDOMKEY:
470 tmp = getkey_randomkey(dev, kg, len, 0);
471 break;
472 #ifdef HAVE_ARGON2
473 case KEYGEN_ARGON2ID:
474 tmp = getkey_argon2id(dev, kg, len);
475 break;
476 #endif
477 case KEYGEN_PKCS5_PBKDF2_SHA1:
478 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
479 break;
480 /* provide backwards compatibility for old config files */
481 case KEYGEN_PKCS5_PBKDF2_OLD:
482 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1);
483 break;
484 case KEYGEN_SHELL_CMD:
485 tmp = getkey_shell_cmd(dev, kg, len);
486 break;
487 default:
488 warnx("unrecognised keygen method %d in getkey()",
489 kg->kg_method);
490 if (ret)
491 bits_free(ret);
492 return NULL;
493 }
494
495 /*
496 * If shared, cache the key.
497 */
498 if (kg->kg_sharedid) {
499 assert(sk == NULL);
500 sk = ecalloc(1, sizeof(*sk));
501 sk->alg = kg->kg_sharedalg;
502 sk->id = string_dup(kg->kg_sharedid);
503 sk->key = tmp;
504 LIST_INSERT_HEAD(&sharedkeys, sk, list);
505 }
506
507 derive: if (kg->kg_sharedid) {
508 /*
509 * tmp holds the master key, owned by the
510 * struct sharedkey record; replace it by the
511 * derived subkey.
512 */
513 tmp = getsubkey(kg->kg_sharedalg, tmp,
514 kg->kg_sharedinfo, len0);
515 if (tmp == NULL) {
516 if (ret)
517 bits_free(ret);
518 return NULL;
519 }
520 }
521 if (ret)
522 ret = bits_xor_d(tmp, ret);
523 else
524 ret = tmp;
525 }
526
527 return ret;
528 }
529
530 /*ARGSUSED*/
531 static bits_t *
532 getkey_storedkey(const char *target, struct keygen *kg, size_t keylen)
533 {
534 return bits_dup(kg->kg_key);
535 }
536
537 /*ARGSUSED*/
538 static bits_t *
539 getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard)
540 {
541 return bits_getrandombits(keylen, hard);
542 }
543
544 static char *
545 maybe_getpass(char *prompt)
546 {
547 char buf[1024];
548 char *p = NULL;
549 char *tmp, *pass;
550
551 switch (pflag) {
552 case PFLAG_GETPASS:
553 p = getpass_r(prompt, buf, sizeof(buf));
554 break;
555
556 case PFLAG_GETPASS_ECHO:
557 p = getpassfd(prompt, buf, sizeof(buf), NULL,
558 GETPASS_ECHO|GETPASS_ECHO_NL|GETPASS_NEED_TTY, 0);
559 break;
560
561 case PFLAG_STDIN:
562 p = fgets(buf, sizeof(buf), stdin);
563 if (p) {
564 tmp = strchr(p, '\n');
565 if (tmp)
566 *tmp = '\0';
567 }
568 break;
569
570 default:
571 errx(EXIT_FAILURE, "pflag set inappropriately?");
572 }
573
574 if (!p)
575 err(EXIT_FAILURE, "failed to read passphrase");
576
577 pass = estrdup(p);
578 explicit_memset(buf, 0, sizeof(buf));
579
580 return pass;
581 }
582
583 /*ARGSUSED*/
584 /*
585 * XXX take, and pass through, a compat flag that indicates whether we
586 * provide backwards compatibility with a previous bug. The previous
587 * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a
588 * non-zero compat flag. The new default, and correct keygen method is
589 * called pcks5_pbkdf2/sha1. When the old method is removed, so will
590 * be the compat argument.
591 */
592 static bits_t *
593 getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen,
594 int compat)
595 {
596 bits_t *ret;
597 char *passp;
598 char buf[1024];
599 u_int8_t *tmp;
600
601 snprintf(buf, sizeof(buf), "%s's passphrase%s:", target,
602 pflag & PFLAG_GETPASS_ECHO ? " (echo)" : "");
603 passp = maybe_getpass(buf);
604 if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp,
605 strlen(passp),
606 bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)),
607 kg->kg_iterations, compat)) {
608 warnx("failed to generate PKCS#5 PBKDF2 key");
609 return NULL;
610 }
611
612 ret = bits_new(tmp, keylen);
613 kg->kg_key = bits_dup(ret);
614 explicit_memset(passp, 0, strlen(passp));
615 free(passp);
616 free(tmp);
617 return ret;
618 }
619
620 #ifdef HAVE_ARGON2
621 static bits_t *
622 getkey_argon2id(const char *target, struct keygen *kg, size_t keylen)
623 {
624 bits_t *ret;
625 char *passp;
626 char buf[1024];
627 uint8_t raw[256];
628 int err;
629
630 snprintf(buf, sizeof(buf), "%s's passphrase%s:", target,
631 pflag & PFLAG_GETPASS_ECHO ? " (echo)" : "");
632 passp = maybe_getpass(buf);
633 if ((err = argon2_hash(kg->kg_iterations, kg->kg_memory,
634 kg->kg_parallelism,
635 passp, strlen(passp),
636 bits_getbuf(kg->kg_salt),
637 BITS2BYTES(bits_len(kg->kg_salt)),
638 raw, sizeof(raw),
639 NULL, 0,
640 Argon2_id, kg->kg_version)) != ARGON2_OK) {
641 warnx("failed to generate Argon2id key, error code %d", err);
642 return NULL;
643 }
644
645 ret = bits_new(raw, keylen);
646 kg->kg_key = bits_dup(ret);
647 explicit_memset(passp, 0, strlen(passp));
648 explicit_memset(raw, 0, sizeof(raw));
649 free(passp);
650 return ret;
651 }
652 #endif
653
654 /*ARGSUSED*/
655 static bits_t *
656 getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen)
657 {
658 FILE *f;
659 bits_t *ret;
660 int status;
661
662 if ((f = popen(string_tocharstar(kg->kg_cmd), "r")) == NULL)
663 errx(1, "command failed");
664 if ((ret = bits_fget(f, keylen)) == NULL)
665 errx(1, "command output too short");
666 if ((status = pclose(f)) != 0)
667 err(1, "command failed with status %d", status);
668
669 return ret;
670 }
671
672 /*ARGSUSED*/
673 static int
674 unconfigure(int argc, char **argv, struct params *inparams, int flags)
675 {
676 int fd;
677 int ret;
678 char buf[MAXPATHLEN] = "";
679
680 /* only complain about additional arguments, if called from main() */
681 if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
682 usage();
683
684 /* if called from do_all(), then ensure that 2 or 3 args exist */
685 if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
686 return -1;
687
688 fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, prog_open);
689 if (fd == -1) {
690 int saved_errno = errno;
691
692 warn("can't open cgd \"%s\", \"%s\"", *argv, buf);
693
694 /* this isn't fatal with nflag != 0 */
695 if (!nflag)
696 return saved_errno;
697 }
698
699 VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
700
701 if (nflag)
702 return 0;
703
704 ret = unconfigure_fd(fd);
705 (void)prog_close(fd);
706 return ret;
707 }
708
709 static int
710 unconfigure_fd(int fd)
711 {
712 struct cgd_ioctl ci;
713
714 if (prog_ioctl(fd, CGDIOCCLR, &ci) == -1) {
715 warn("ioctl");
716 return -1;
717 }
718
719 return 0;
720 }
721
722 /*ARGSUSED*/
723 static int
724 configure(int argc, char **argv, struct params *inparams, int flags)
725 {
726 struct params *p;
727 struct keygen *kg;
728 int fd;
729 int loop = 0;
730 int ret;
731 char cgdname[PATH_MAX];
732 char devicename[PATH_MAX];
733 const char *dev = NULL; /* XXX: gcc */
734
735 if (argc < 2 || argc > 3) {
736 /* print usage and exit, only if called from main() */
737 if (flags == CONFIG_FLAGS_FROMMAIN) {
738 warnx("wrong number of args");
739 usage();
740 }
741 return -1;
742 }
743
744 if ((
745 fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open)
746 ) != -1) {
747 struct cgd_user cgu;
748
749 cgu.cgu_unit = -1;
750 if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) {
751 warnx("device %s already in use", *argv);
752 prog_close(fd);
753 return -1;
754 }
755 prog_close(fd);
756 }
757
758 dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
759 if (dev == NULL) {
760 warnx("getfsspecname failed: %s", devicename);
761 return -1;
762 }
763
764 if (argc == 2) {
765 char pfile[MAXPATHLEN];
766
767 /* make string writable for basename */
768 strlcpy(pfile, dev, sizeof(pfile));
769 p = params_cget(basename(pfile));
770 } else
771 p = params_cget(argv[2]);
772
773 if (!p)
774 return -1;
775
776 /*
777 * over-ride with command line specifications and fill in default
778 * values.
779 */
780
781 p = params_combine(p, inparams);
782 ret = params_filldefaults(p);
783 if (ret) {
784 params_free(p);
785 return ret;
786 }
787
788 if (!params_verify(p)) {
789 warnx("params invalid");
790 return -1;
791 }
792
793 /*
794 * loop over configuring the disk and checking to see if it
795 * verifies properly. We open and close the disk device each
796 * time, because if the user passes us the block device we
797 * need to flush the buffer cache.
798 *
799 * We only loop if one of the verification methods prompts for
800 * a password.
801 */
802
803 for (kg = p->keygen;
804 (pflag & PFLAG_GETPASS_MASK) && kg;
805 kg = kg->next)
806 if (kg->kg_method == KEYGEN_ARGON2ID ||
807 kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1 ||
808 kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD) {
809 loop = 1;
810 break;
811 }
812
813 for (;;) {
814 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
815 if (fd == -1)
816 return -1;
817
818 if (p->key)
819 bits_free(p->key);
820
821 p->key = getkey(argv[1], p->keygen, p->keylen);
822 if (!p->key)
823 goto bail_err;
824
825 ret = configure_params(fd, cgdname, dev, p);
826 if (ret)
827 goto bail_err;
828
829 ret = verify(p, fd);
830 if (ret == -1) {
831 (void)unconfigure_fd(fd);
832 goto bail_err;
833 }
834 if (ret == 0) /* success */
835 break;
836
837 (void)unconfigure_fd(fd);
838 (void)prog_close(fd);
839
840 if (!loop) {
841 warnx("verification failed permanently");
842 goto bail_err;
843 }
844
845 warnx("verification failed, please reenter passphrase");
846 }
847
848 params_free(p);
849 (void)prog_close(fd);
850 return 0;
851
852 bail_err:;
853 params_free(p);
854 (void)prog_close(fd);
855 return -1;
856 }
857
858 static int
859 configure_stdin(struct params *p, int argc, char **argv)
860 {
861 int fd;
862 int ret;
863 char cgdname[PATH_MAX];
864 char devicename[PATH_MAX];
865 const char *dev;
866
867 if (argc < 3 || argc > 4)
868 usage();
869
870 dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
871 if (dev == NULL) {
872 warnx("getfsspecname failed: %s", devicename);
873 return -1;
874 }
875
876 p->algorithm = string_fromcharstar(argv[2]);
877 if (argc > 3) {
878 size_t keylen;
879
880 if (parse_size_t(argv[3], &keylen) == -1) {
881 warn("failed to parse key length");
882 return -1;
883 }
884 p->keylen = keylen;
885 }
886
887 ret = params_filldefaults(p);
888 if (ret)
889 return ret;
890
891 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
892 if (fd == -1)
893 return -1;
894
895 p->key = bits_fget(stdin, p->keylen);
896 if (!p->key) {
897 warnx("failed to read key from stdin");
898 return -1;
899 }
900
901 return configure_params(fd, cgdname, dev, p);
902 }
903
904 static int
905 opendisk_werror(const char *cgd, char *buf, size_t buflen)
906 {
907 int fd;
908
909 VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd,buf,buflen));
910
911 /* sanity */
912 if (!cgd || !buf)
913 return -1;
914
915 if (nflag) {
916 if (strlcpy(buf, cgd, buflen) >= buflen)
917 return -1;
918 return 0;
919 }
920
921 fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open);
922 if (fd == -1)
923 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
924
925 return fd;
926 }
927
928 static int
929 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
930 {
931 struct cgd_ioctl ci;
932
933 /* sanity */
934 if (!cgd || !dev)
935 return -1;
936
937 (void)memset(&ci, 0x0, sizeof(ci));
938 ci.ci_disk = dev;
939 ci.ci_alg = string_tocharstar(p->algorithm);
940 ci.ci_ivmethod = string_tocharstar(p->ivmeth);
941 ci.ci_key = bits_getbuf(p->key);
942 ci.ci_keylen = p->keylen;
943 ci.ci_blocksize = p->bsize;
944
945 VPRINTF(1, (" with alg %s keylen %zu blocksize %zu ivmethod %s\n",
946 string_tocharstar(p->algorithm), p->keylen, p->bsize,
947 string_tocharstar(p->ivmeth)));
948 VPRINTF(2, ("key: "));
949 VERBOSE(2, bits_fprint(stdout, p->key));
950 VPRINTF(2, ("\n"));
951
952 if (nflag)
953 return 0;
954
955 if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) {
956 int saved_errno = errno;
957 warn("ioctl");
958 return saved_errno;
959 }
960
961 return 0;
962 }
963
964 /*
965 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
966 */
967
968 #define SCANSIZE 8192
969
970 static int
971 verify(struct params *p, int fd)
972 {
973
974 switch (p->verify_method) {
975 case VERIFY_NONE:
976 return 0;
977 case VERIFY_DISKLABEL:
978 return verify_disklabel(fd);
979 case VERIFY_FFS:
980 return verify_ffs(fd);
981 case VERIFY_REENTER:
982 return verify_reenter(p);
983 case VERIFY_MBR:
984 return verify_mbr(fd);
985 case VERIFY_GPT:
986 return verify_gpt(fd);
987 default:
988 warnx("unimplemented verification method");
989 return -1;
990 }
991 }
992
993 static int
994 verify_disklabel(int fd)
995 {
996 struct disklabel l;
997 ssize_t ret;
998 char buf[SCANSIZE];
999
1000 /*
1001 * we simply scan the first few blocks for a disklabel, ignoring
1002 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read
1003 * a cgd, anyway, so it is unlikely that there will be non-native
1004 * partition information.
1005 */
1006
1007 ret = prog_pread(fd, buf, SCANSIZE, 0);
1008 if (ret < 0) {
1009 warn("can't read disklabel area");
1010 return -1;
1011 }
1012
1013 /* now scan for the disklabel */
1014
1015 return disklabel_scan(&l, buf, (size_t)ret);
1016 }
1017
1018 static int
1019 verify_mbr(int fd)
1020 {
1021 struct mbr_sector mbr;
1022 ssize_t ret;
1023 char buf[SCANSIZE];
1024
1025 /*
1026 * we read the first blocks to avoid sector size issues and
1027 * verify the MBR in the beginning
1028 */
1029
1030 ret = prog_pread(fd, buf, SCANSIZE, 0);
1031 if (ret < 0) {
1032 warn("can't read mbr area");
1033 return -1;
1034 }
1035
1036 memcpy(&mbr, buf, sizeof(mbr));
1037 if (le16toh(mbr.mbr_magic) != MBR_MAGIC)
1038 return 1;
1039
1040 return 0;
1041 }
1042
1043 static uint32_t crc32_tab[] = {
1044 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
1045 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1046 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
1047 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1048 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
1049 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1050 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
1051 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1052 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
1053 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1054 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
1055 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1056 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
1057 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1058 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1059 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1060 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
1061 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1062 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
1063 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1064 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
1065 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1066 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
1067 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1068 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1069 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1070 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
1071 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1072 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
1073 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1074 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
1075 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1076 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
1077 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1078 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1079 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1080 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
1081 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1082 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
1083 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1084 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
1085 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1086 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
1087 };
1088
1089 static uint32_t
1090 crc32(const void *buf, size_t size)
1091 {
1092 const uint8_t *p;
1093 uint32_t crc;
1094
1095 p = buf;
1096 crc = ~0U;
1097
1098 while (size--)
1099 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
1100
1101 return crc ^ ~0U;
1102 }
1103
1104 static int
1105 verify_gpt(int fd)
1106 {
1107 struct gpt_hdr hdr;
1108 ssize_t ret;
1109 char buf[SCANSIZE];
1110 unsigned blksize;
1111 size_t off;
1112
1113 /*
1114 * we read the first blocks to avoid sector size issues and
1115 * verify the GPT header.
1116 */
1117
1118 ret = prog_pread(fd, buf, SCANSIZE, 0);
1119 if (ret < 0) {
1120 warn("can't read gpt area");
1121 return -1;
1122 }
1123
1124 ret = 1;
1125 for (blksize = DEV_BSIZE;
1126 (off = (blksize * GPT_HDR_BLKNO)) <= SCANSIZE - sizeof(hdr);
1127 blksize <<= 1) {
1128
1129 memcpy(&hdr, &buf[off], sizeof(hdr));
1130 if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0
1131 && le32toh(hdr.hdr_revision) == GPT_HDR_REVISION
1132 && le32toh(hdr.hdr_size) == GPT_HDR_SIZE) {
1133
1134 hdr.hdr_crc_self = 0;
1135 if (crc32(&hdr, sizeof(hdr))) {
1136 ret = 0;
1137 break;
1138 }
1139 }
1140 }
1141
1142 return ret;
1143 }
1144
1145 static off_t sblock_try[] = SBLOCKSEARCH;
1146
1147 static int
1148 verify_ffs(int fd)
1149 {
1150 size_t i;
1151
1152 for (i = 0; sblock_try[i] != -1; i++) {
1153 union {
1154 char buf[SBLOCKSIZE];
1155 struct fs fs;
1156 } u;
1157 ssize_t ret;
1158
1159 ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]);
1160 if (ret < 0) {
1161 warn("pread");
1162 break;
1163 } else if ((size_t)ret < sizeof(u)) {
1164 warnx("pread: incomplete block");
1165 break;
1166 }
1167 switch (u.fs.fs_magic) {
1168 case FS_UFS1_MAGIC:
1169 case FS_UFS2_MAGIC:
1170 case FS_UFS1_MAGIC_SWAPPED:
1171 case FS_UFS2_MAGIC_SWAPPED:
1172 return 0;
1173 default:
1174 continue;
1175 }
1176 }
1177
1178 return 1; /* failure */
1179 }
1180
1181 static int
1182 verify_reenter(struct params *p)
1183 {
1184 struct keygen *kg;
1185 bits_t *orig_key, *key = NULL;
1186 int ret;
1187
1188 ret = 0;
1189 for (kg = p->keygen; kg && !ret; kg = kg->next) {
1190 if (kg->kg_method != KEYGEN_ARGON2ID &&
1191 kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1 &&
1192 kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD)
1193 continue;
1194
1195 orig_key = kg->kg_key;
1196 kg->kg_key = NULL;
1197
1198 switch (kg->kg_method) {
1199 #ifdef HAVE_ARGON2
1200 case KEYGEN_ARGON2ID:
1201 key = getkey_argon2id("re-enter device", kg,
1202 bits_len(orig_key));
1203 break;
1204 #endif
1205 case KEYGEN_PKCS5_PBKDF2_SHA1:
1206 key = getkey_pkcs5_pbkdf2("re-enter device", kg,
1207 bits_len(orig_key), 0);
1208 break;
1209 case KEYGEN_PKCS5_PBKDF2_OLD:
1210 key = getkey_pkcs5_pbkdf2("re-enter device", kg,
1211 bits_len(orig_key), 1);
1212 break;
1213 default:
1214 warnx("unsupported keygen method");
1215 kg->kg_key = orig_key;
1216 return -1;
1217 }
1218
1219 ret = !bits_match(key, orig_key);
1220
1221 bits_free(key);
1222 bits_free(kg->kg_key);
1223 kg->kg_key = orig_key;
1224 }
1225
1226 return ret;
1227 }
1228
1229 static int
1230 generate(struct params *p, int argc, char **argv, const char *outfile,
1231 const char *Pfile)
1232 {
1233 int ret;
1234
1235 if (argc < 1 || argc > 2)
1236 usage();
1237
1238 p->algorithm = string_fromcharstar(argv[0]);
1239 if (argc > 1) {
1240 size_t keylen;
1241
1242 if (parse_size_t(argv[1], &keylen) == -1) {
1243 warn("Failed to parse key length");
1244 return -1;
1245 }
1246 p->keylen = keylen;
1247 }
1248
1249 ret = params_filldefaults(p);
1250 if (ret)
1251 return ret;
1252
1253 if (Pfile) {
1254 struct params *pp;
1255
1256 pp = params_cget(Pfile);
1257 if (pp == NULL)
1258 return -1;
1259 if (!params_verify(pp)) {
1260 params_free(pp);
1261 warnx("invalid parameters file \"%s\"", Pfile);
1262 return -1;
1263 }
1264 p = params_combine(pp, p);
1265 keygen_stripstored(&p->keygen);
1266 if (!p->keygen) {
1267 warnx("no keygen in parameters file \"%s\"", Pfile);
1268 return -1;
1269 }
1270 } else {
1271 if (!p->keygen) {
1272 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
1273 if (!p->keygen)
1274 return -1;
1275 }
1276
1277 if (keygen_filldefaults(p->keygen, p->keylen)) {
1278 warnx("Failed to generate defaults for keygen");
1279 return -1;
1280 }
1281 }
1282
1283 if (Sflag) {
1284 if (Pfile)
1285 ret = keygen_tweakshared(p->keygen);
1286 else
1287 ret = keygen_makeshared(p->keygen);
1288 if (ret)
1289 return ret;
1290 }
1291
1292 if (!params_verify(p)) {
1293 warnx("invalid parameters generated");
1294 return -1;
1295 }
1296
1297 return params_cput(p, outfile);
1298 }
1299
1300 static int
1301 generate_convert(struct params *p, int argc, char **argv, const char *outfile,
1302 const char *Pfile)
1303 {
1304 struct params *oldp;
1305 struct keygen *kg;
1306 int ret;
1307
1308 if (argc != 1)
1309 usage();
1310
1311 oldp = params_cget(*argv);
1312 if (!oldp)
1313 return -1;
1314
1315 /* for sanity, we ensure that none of the keygens are randomkey */
1316 for (kg=p->keygen; kg; kg=kg->next)
1317 if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
1318 (kg->kg_method == KEYGEN_URANDOMKEY)) {
1319 warnx("can't preserve randomly generated key");
1320 goto bail;
1321 }
1322 for (kg=oldp->keygen; kg; kg=kg->next)
1323 if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
1324 (kg->kg_method == KEYGEN_URANDOMKEY)) {
1325 warnx("can't preserve randomly generated key");
1326 goto bail;
1327 }
1328
1329 if (!params_verify(oldp)) {
1330 warnx("invalid old parameters file \"%s\"", *argv);
1331 return -1;
1332 }
1333
1334 oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
1335
1336 /* we copy across the non-keygen info, here. */
1337
1338 string_free(p->algorithm);
1339 string_free(p->ivmeth);
1340
1341 p->algorithm = string_dup(oldp->algorithm);
1342 p->ivmeth = string_dup(oldp->ivmeth);
1343 p->keylen = oldp->keylen;
1344 p->bsize = oldp->bsize;
1345 if (p->verify_method == VERIFY_UNKNOWN)
1346 p->verify_method = oldp->verify_method;
1347
1348 params_free(oldp);
1349
1350 if (Pfile) {
1351 struct params *pp;
1352
1353 pp = params_cget(Pfile);
1354 if (pp == NULL)
1355 return -1;
1356 if (!params_verify(pp)) {
1357 params_free(pp);
1358 warnx("invalid parameters file \"%s\"", Pfile);
1359 return -1;
1360 }
1361 p = params_combine(pp, p);
1362 keygen_stripstored(&p->keygen);
1363 if (!p->keygen) {
1364 warnx("no keygen in parameters file \"%s\"", Pfile);
1365 return -1;
1366 }
1367 } else {
1368 if (!p->keygen) {
1369 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
1370 if (!p->keygen)
1371 return -1;
1372 }
1373 (void)params_filldefaults(p);
1374 (void)keygen_filldefaults(p->keygen, p->keylen);
1375 }
1376
1377 if (Sflag) {
1378 if (Pfile)
1379 ret = keygen_tweakshared(p->keygen);
1380 else
1381 ret = keygen_makeshared(p->keygen);
1382 if (ret)
1383 return ret;
1384 }
1385
1386 p->key = getkey("new file", p->keygen, p->keylen);
1387
1388 kg = keygen_generate(KEYGEN_STOREDKEY);
1389 kg->kg_key = bits_xor(p->key, oldp->key);
1390 keygen_addlist(&p->keygen, kg);
1391
1392 if (!params_verify(p)) {
1393 warnx("can't generate new parameters file");
1394 return -1;
1395 }
1396
1397 return params_cput(p, outfile);
1398 bail:;
1399 params_free(oldp);
1400 return -1;
1401 }
1402
1403 static int
1404 /*ARGSUSED*/
1405 do_all(const char *cfile, int argc, char **argv,
1406 int (*conf)(int, char **, struct params *, int))
1407 {
1408 FILE *f;
1409 size_t len;
1410 size_t lineno;
1411 int my_argc;
1412 int ret;
1413 const char *fn;
1414 char *line;
1415 char **my_argv;
1416
1417 if (argc > 0)
1418 usage();
1419
1420 if (!cfile[0])
1421 fn = CGDCONFIG_CFILE;
1422 else
1423 fn = cfile;
1424
1425 f = fopen(fn, "r");
1426 if (f == NULL) {
1427 warn("could not open config file \"%s\"", fn);
1428 return -1;
1429 }
1430
1431 ret = 0;
1432 lineno = 0;
1433 for (;;) {
1434 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
1435 if (!line)
1436 break;
1437 if (!*line)
1438 continue;
1439
1440 my_argv = words(line, &my_argc);
1441 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
1442 if (ret) {
1443 warnx("action failed on \"%s\" line %lu", fn,
1444 (u_long)lineno);
1445 break;
1446 }
1447 words_free(my_argv, my_argc);
1448 }
1449 return ret;
1450 }
1451
1452 static const char *
1453 iv_method(int mode)
1454 {
1455
1456 switch (mode) {
1457 case CGD_CIPHER_CBC_ENCBLKNO8:
1458 return "encblkno8";
1459 case CGD_CIPHER_CBC_ENCBLKNO1:
1460 return "encblkno1";
1461 default:
1462 return "unknown";
1463 }
1464 }
1465
1466
1467 static void
1468 show(const char *dev) {
1469 char path[64];
1470 struct cgd_user cgu;
1471 int fd;
1472
1473 fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0);
1474 if (fd == -1) {
1475 warn("open: %s", dev);
1476 return;
1477 }
1478
1479 cgu.cgu_unit = -1;
1480 if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) {
1481 close(fd);
1482 err(1, "CGDIOCGET");
1483 }
1484
1485 printf("%s: ", dev);
1486
1487 if (cgu.cgu_dev == 0) {
1488 printf("not in use");
1489 goto out;
1490 }
1491
1492 dev = devname(cgu.cgu_dev, S_IFBLK);
1493 if (dev != NULL)
1494 printf("%s ", dev);
1495 else
1496 printf("dev %llu,%llu ", (unsigned long long)major(cgu.cgu_dev),
1497 (unsigned long long)minor(cgu.cgu_dev));
1498
1499 if (verbose)
1500 printf("%s ", cgu.cgu_alg);
1501 if (verbose > 1) {
1502 printf("keylen %d ", cgu.cgu_keylen);
1503 printf("blksize %zd ", cgu.cgu_blocksize);
1504 printf("%s ", iv_method(cgu.cgu_mode));
1505 }
1506
1507 out:;
1508 putchar('\n');
1509 close(fd);
1510 }
1511
1512 static int
1513 do_list(int argc, char **argv)
1514 {
1515
1516 if (argc != 0 && argc != 1)
1517 usage();
1518
1519 if (argc) {
1520 show(argv[0]);
1521 return 0;
1522 }
1523
1524 DIR *dirp;
1525 struct dirent *dp;
1526 __BITMAP_TYPE(, uint32_t, 65536) bm;
1527
1528 __BITMAP_ZERO(&bm);
1529
1530 if ((dirp = opendir(_PATH_DEV)) == NULL)
1531 err(1, "opendir: %s", _PATH_DEV);
1532
1533 while ((dp = readdir(dirp)) != NULL) {
1534 char *ep;
1535 if (strncmp(dp->d_name, "rcgd", 4) != 0)
1536 continue;
1537 errno = 0;
1538 int n = (int)strtol(dp->d_name + 4, &ep, 0);
1539 if (ep == dp->d_name + 4 || errno != 0) {
1540 warnx("bad name %s", dp->d_name);
1541 continue;
1542 }
1543 *ep = '\0';
1544 if (__BITMAP_ISSET(n, &bm))
1545 continue;
1546 __BITMAP_SET(n, &bm);
1547 show(dp->d_name + 1);
1548 }
1549
1550 closedir(dirp);
1551 return 0;
1552 }
1553
1554 static int
1555 printkey(const char *dev, const char *paramsfile, const char *fmt, ...)
1556 {
1557 va_list va;
1558 struct params *p;
1559 const uint8_t *raw;
1560 size_t nbits, nbytes;
1561 size_t nb64;
1562 char *b64;
1563 int ret;
1564
1565 p = params_cget(paramsfile);
1566 if (p == NULL)
1567 return -1;
1568 if (!params_verify(p)) {
1569 warnx("invalid parameters file \"%s\"", paramsfile);
1570 return -1;
1571 }
1572 p->key = getkey(dev, p->keygen, p->keylen);
1573 raw = bits_getbuf(p->key);
1574 nbits = bits_len(p->key);
1575 assert(nbits <= INT_MAX - 7);
1576 nbytes = BITS2BYTES(nbits);
1577 assert(nbytes <= 3*(INT_MAX/4) - 2);
1578
1579 nb64 = 4*((nbytes + 2)/3);
1580 b64 = emalloc(nb64 + 2);
1581 ret = __b64_ntop(raw, nbytes, b64, nb64 + 1);
1582 assert(ret == (int)nb64);
1583 b64[nb64] = '\n';
1584 b64[nb64 + 1] = '\0';
1585
1586 va_start(va, fmt);
1587 vprintf(fmt, va);
1588 va_end(va);
1589 if (fwrite(b64, nb64 + 1, 1, stdout) != 1)
1590 err(1, "fwrite");
1591 fflush(stdout);
1592 return ferror(stdout);
1593 }
1594
1595 static int
1596 printkey1(int argc, char **argv, struct params *inparams, int flags)
1597 {
1598 char devicename[PATH_MAX], paramsfilebuf[PATH_MAX];
1599 const char *dev, *paramsfile;
1600
1601 assert(flags == CONFIG_FLAGS_FROMALL);
1602
1603 if (argc < 2 || argc > 3)
1604 return -1;
1605
1606 dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
1607 if (dev == NULL) {
1608 warnx("getfsspecname failed: %s", devicename);
1609 return -1;
1610 }
1611
1612 if (argc == 2) {
1613 strlcpy(paramsfilebuf, dev, sizeof(paramsfilebuf));
1614 paramsfile = basename(paramsfilebuf);
1615 } else {
1616 paramsfile = argv[2];
1617 }
1618
1619 return printkey(dev, paramsfile, "%s: ", dev);
1620 }
1621
1622 static int
1623 do_printkey(int argc, char **argv)
1624 {
1625
1626 if (argc != 1)
1627 usage();
1628 return printkey("key", argv[0], "");
1629 }
1630
1631 static void
1632 eliminate_cores(void)
1633 {
1634 struct rlimit rlp;
1635
1636 rlp.rlim_cur = 0;
1637 rlp.rlim_max = 0;
1638 if (setrlimit(RLIMIT_CORE, &rlp) == -1)
1639 err(EXIT_FAILURE, "Can't disable cores");
1640 }
1641