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