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