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