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