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