cgdconfig.c revision 1.30 1 #define opendisk1(x,y,z,t,u,v) opendisk(x,y,z,t,u)
2
3 /* $NetBSD: cgdconfig.c,v 1.30 2010/12/02 04:54:32 elric Exp $ */
4
5 /*-
6 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Roland C. Dowdeswell.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __COPYRIGHT("@(#) Copyright (c) 2002, 2003\
37 The NetBSD Foundation, Inc. All rights reserved.");
38 __RCSID("$NetBSD: cgdconfig.c,v 1.30 2010/12/02 04:54:32 elric Exp $");
39 #endif
40
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <libgen.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <util.h>
50
51 #include <sys/ioctl.h>
52 #include <sys/disklabel.h>
53 #include <sys/mman.h>
54 #include <sys/param.h>
55 #include <sys/resource.h>
56
57 #include <dev/cgdvar.h>
58
59 #include <ufs/ffs/fs.h>
60
61 #include "params.h"
62 #include "pkcs5_pbkdf2.h"
63 #include "utils.h"
64 #include "cgd_kernelops.h"
65 #include "cgdconfig.h"
66
67 #define CGDCONFIG_DIR "/etc/cgd"
68 #define CGDCONFIG_CFILE CGDCONFIG_DIR "/cgd.conf"
69
70 enum action {
71 ACTION_DEFAULT, /* default -> configure */
72 ACTION_CONFIGURE, /* configure, with paramsfile */
73 ACTION_UNCONFIGURE, /* unconfigure */
74 ACTION_GENERATE, /* generate a paramsfile */
75 ACTION_GENERATE_CONVERT, /* generate a ``dup'' paramsfile */
76 ACTION_CONFIGALL, /* configure all from config file */
77 ACTION_UNCONFIGALL, /* unconfigure all from config file */
78 ACTION_CONFIGSTDIN /* configure, key from stdin */
79 };
80
81 /* if nflag is set, do not configure/unconfigure the cgd's */
82
83 int nflag = 0;
84
85 /* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */
86
87 #define PFLAG_GETPASS 0x01
88 #define PFLAG_STDIN 0x02
89 int pflag = PFLAG_GETPASS;
90
91 static int configure(int, char **, struct params *, int);
92 static int configure_stdin(struct params *, int argc, char **);
93 static int generate(struct params *, int, char **, const char *);
94 static int generate_convert(struct params *, int, char **, const char *);
95 static int unconfigure(int, char **, struct params *, int);
96 static int do_all(const char *, int, char **,
97 int (*)(int, char **, struct params *, int));
98
99 #define CONFIG_FLAGS_FROMALL 1 /* called from configure_all() */
100 #define CONFIG_FLAGS_FROMMAIN 2 /* called from main() */
101
102 static int configure_params(int, const char *, const char *,
103 struct params *);
104 static void eliminate_cores(void);
105 static bits_t *getkey(const char *, struct keygen *, size_t);
106 static bits_t *getkey_storedkey(const char *, struct keygen *, size_t);
107 static bits_t *getkey_randomkey(const char *, struct keygen *, size_t, int);
108 static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t,
109 int);
110 static bits_t *getkey_shell_cmd(const char *, struct keygen *, size_t);
111 static char *maybe_getpass(char *);
112 static int opendisk_werror(const char *, char *, size_t);
113 static int unconfigure_fd(int);
114 static int verify(struct params *, int);
115 static int verify_disklabel(int);
116 static int verify_ffs(int);
117 static int verify_reenter(struct params *);
118
119 static void usage(void);
120
121 /* Verbose Framework */
122 unsigned verbose = 0;
123
124 #define VERBOSE(x,y) if (verbose >= x) y
125 #define VPRINTF(x,y) if (verbose >= x) (void)printf y
126
127 static void
128 usage(void)
129 {
130
131 (void)fprintf(stderr, "usage: %s [-nv] [-V vmeth] cgd dev [paramsfile]\n",
132 getprogname());
133 (void)fprintf(stderr, " %s -C [-nv] [-f configfile]\n", getprogname());
134 (void)fprintf(stderr, " %s -U [-nv] [-f configfile]\n", getprogname());
135 (void)fprintf(stderr, " %s -G [-nv] [-i ivmeth] [-k kgmeth] "
136 "[-o outfile] paramsfile\n", getprogname());
137 (void)fprintf(stderr, " %s -g [-nv] [-i ivmeth] [-k kgmeth] "
138 "[-o outfile] alg [keylen]\n", getprogname());
139 (void)fprintf(stderr, " %s -s [-nv] [-i ivmeth] cgd dev alg "
140 "[keylen]\n", getprogname());
141 (void)fprintf(stderr, " %s -u [-nv] cgd\n", getprogname());
142 exit(EXIT_FAILURE);
143 }
144
145 static int
146 parse_size_t(const char *s, size_t *l)
147 {
148 char *endptr;
149 long v;
150
151 errno = 0;
152 v = strtol(s, &endptr, 10);
153 if ((v == LONG_MIN || v == LONG_MAX) && errno)
154 return -1;
155 if (v < INT_MIN || v > INT_MAX) {
156 errno = ERANGE;
157 return -1;
158 }
159 if (endptr == s) {
160 errno = EINVAL;
161 return -1;
162 }
163 *l = (size_t)v;
164 return 0;
165 }
166
167 static void
168 set_action(enum action *action, enum action value)
169 {
170 if (*action != ACTION_DEFAULT)
171 usage();
172 *action = value;
173 }
174
175 #ifndef CGDCONFIG_AS_LIB
176 int
177 main(int argc, char **argv)
178 {
179
180 return cgdconfig(argc, argv);
181 }
182 #endif
183
184 int
185 cgdconfig(int argc, char *argv[])
186 {
187 struct params *p;
188 struct params *tp;
189 struct keygen *kg;
190 enum action action = ACTION_DEFAULT;
191 int ch;
192 const char *cfile = NULL;
193 const char *outfile = NULL;
194
195 setprogname(*argv);
196 eliminate_cores();
197 if (mlockall(MCL_FUTURE))
198 err(EXIT_FAILURE, "Can't lock memory");
199 p = params_new();
200 kg = NULL;
201
202 while ((ch = getopt(argc, argv, "CGUV:b:f:gi:k:no:spuv")) != -1)
203 switch (ch) {
204 case 'C':
205 set_action(&action, ACTION_CONFIGALL);
206 break;
207 case 'G':
208 set_action(&action, ACTION_GENERATE_CONVERT);
209 break;
210 case 'U':
211 set_action(&action, ACTION_UNCONFIGALL);
212 break;
213 case 'V':
214 tp = params_verify_method(string_fromcharstar(optarg));
215 if (!tp)
216 usage();
217 p = params_combine(p, tp);
218 break;
219 case 'b':
220 {
221 size_t size;
222
223 if (parse_size_t(optarg, &size) == -1)
224 usage();
225 tp = params_bsize(size);
226 if (!tp)
227 usage();
228 p = params_combine(p, tp);
229 }
230 break;
231 case 'f':
232 if (cfile)
233 usage();
234 cfile = estrdup(optarg);
235 break;
236 case 'g':
237 set_action(&action, ACTION_GENERATE);
238 break;
239 case 'i':
240 tp = params_ivmeth(string_fromcharstar(optarg));
241 p = params_combine(p, tp);
242 break;
243 case 'k':
244 kg = keygen_method(string_fromcharstar(optarg));
245 if (!kg)
246 usage();
247 keygen_addlist(&p->keygen, kg);
248 break;
249 case 'n':
250 nflag = 1;
251 break;
252 case 'o':
253 if (outfile)
254 usage();
255 outfile = estrdup(optarg);
256 break;
257 case 'p':
258 pflag = PFLAG_STDIN;
259 break;
260 case 's':
261 set_action(&action, ACTION_CONFIGSTDIN);
262 break;
263
264 case 'u':
265 set_action(&action, ACTION_UNCONFIGURE);
266 break;
267 case 'v':
268 verbose++;
269 break;
270 default:
271 usage();
272 /* NOTREACHED */
273 }
274
275 argc -= optind;
276 argv += optind;
277
278 if (!outfile)
279 outfile = "";
280 if (!cfile)
281 cfile = "";
282
283 /* validate the consistency of the arguments */
284
285 switch (action) {
286 case ACTION_DEFAULT: /* ACTION_CONFIGURE is the default */
287 case ACTION_CONFIGURE:
288 return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN);
289 case ACTION_UNCONFIGURE:
290 return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN);
291 case ACTION_GENERATE:
292 return generate(p, argc, argv, outfile);
293 case ACTION_GENERATE_CONVERT:
294 return generate_convert(p, argc, argv, outfile);
295 case ACTION_CONFIGALL:
296 return do_all(cfile, argc, argv, configure);
297 case ACTION_UNCONFIGALL:
298 return do_all(cfile, argc, argv, unconfigure);
299 case ACTION_CONFIGSTDIN:
300 return configure_stdin(p, argc, argv);
301 default:
302 errx(EXIT_FAILURE, "undefined action");
303 /* NOTREACHED */
304 }
305 }
306
307 static bits_t *
308 getkey(const char *dev, struct keygen *kg, size_t len)
309 {
310 bits_t *ret = NULL;
311 bits_t *tmp;
312
313 VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len));
314 for (; kg; kg=kg->next) {
315 switch (kg->kg_method) {
316 case KEYGEN_STOREDKEY:
317 tmp = getkey_storedkey(dev, kg, len);
318 break;
319 case KEYGEN_RANDOMKEY:
320 tmp = getkey_randomkey(dev, kg, len, 1);
321 break;
322 case KEYGEN_URANDOMKEY:
323 tmp = getkey_randomkey(dev, kg, len, 0);
324 break;
325 case KEYGEN_PKCS5_PBKDF2_SHA1:
326 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
327 break;
328 /* provide backwards compatibility for old config files */
329 case KEYGEN_PKCS5_PBKDF2_OLD:
330 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1);
331 break;
332 case KEYGEN_SHELL_CMD:
333 tmp = getkey_shell_cmd(dev, kg, len);
334 break;
335 default:
336 warnx("unrecognised keygen method %d in getkey()",
337 kg->kg_method);
338 if (ret)
339 bits_free(ret);
340 return NULL;
341 }
342
343 if (ret)
344 ret = bits_xor_d(tmp, ret);
345 else
346 ret = tmp;
347 }
348
349 return ret;
350 }
351
352 /*ARGSUSED*/
353 static bits_t *
354 getkey_storedkey(const char *target, struct keygen *kg, size_t keylen)
355 {
356 return bits_dup(kg->kg_key);
357 }
358
359 /*ARGSUSED*/
360 static bits_t *
361 getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard)
362 {
363 return bits_getrandombits(keylen, hard);
364 }
365
366 static char *
367 maybe_getpass(char *prompt)
368 {
369 char buf[1024];
370 char *p = buf;
371 char *tmp;
372
373 switch (pflag) {
374 case PFLAG_GETPASS:
375 p = getpass(prompt);
376 break;
377
378 case PFLAG_STDIN:
379 p = fgets(buf, sizeof(buf), stdin);
380 if (p) {
381 tmp = strchr(p, '\n');
382 if (tmp)
383 *tmp = '\0';
384 }
385 break;
386
387 default:
388 errx(EXIT_FAILURE, "pflag set inappropriately?");
389 }
390
391 if (!p)
392 err(EXIT_FAILURE, "failed to read passphrase");
393
394 return estrdup(p);
395 }
396
397 /*ARGSUSED*/
398 /*
399 * XXX take, and pass through, a compat flag that indicates whether we
400 * provide backwards compatibility with a previous bug. The previous
401 * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a
402 * non-zero compat flag. The new default, and correct keygen method is
403 * called pcks5_pbkdf2/sha1. When the old method is removed, so will
404 * be the compat argument.
405 */
406 static bits_t *
407 getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen,
408 int compat)
409 {
410 bits_t *ret;
411 char *passp;
412 char buf[1024];
413 u_int8_t *tmp;
414
415 snprintf(buf, sizeof(buf), "%s's passphrase:", target);
416 passp = maybe_getpass(buf);
417 if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp,
418 strlen(passp),
419 bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)),
420 kg->kg_iterations, compat)) {
421 warnx("failed to generate PKCS#5 PBKDF2 key");
422 return NULL;
423 }
424
425 ret = bits_new(tmp, keylen);
426 kg->kg_key = bits_dup(ret);
427 memset(passp, 0, strlen(passp));
428 free(passp);
429 free(tmp);
430 return ret;
431 }
432
433 /*ARGSUSED*/
434 static bits_t *
435 getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen)
436 {
437 FILE *f;
438 bits_t *ret;
439
440 f = popen(string_tocharstar(kg->kg_cmd), "r");
441 ret = bits_fget(f, keylen);
442 pclose(f);
443
444 return ret;
445 }
446
447 /*ARGSUSED*/
448 static int
449 unconfigure(int argc, char **argv, struct params *inparams, int flags)
450 {
451 int fd;
452 int ret;
453 char buf[MAXPATHLEN] = "";
454
455 /* only complain about additional arguments, if called from main() */
456 if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
457 usage();
458
459 /* if called from do_all(), then ensure that 2 or 3 args exist */
460 if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
461 return -1;
462
463 fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, cgd_kops.ko_open);
464 if (fd == -1) {
465 int saved_errno = errno;
466
467 warn("can't open cgd \"%s\", \"%s\"", *argv, buf);
468
469 /* this isn't fatal with nflag != 0 */
470 if (!nflag)
471 return saved_errno;
472 }
473
474 VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
475
476 if (nflag)
477 return 0;
478
479 ret = unconfigure_fd(fd);
480 (void)cgd_kops.ko_close(fd);
481 return ret;
482 }
483
484 static int
485 unconfigure_fd(int fd)
486 {
487 struct cgd_ioctl ci;
488
489 if (cgd_kops.ko_ioctl(fd, CGDIOCCLR, &ci) == -1) {
490 warn("ioctl");
491 return -1;
492 }
493
494 return 0;
495 }
496
497 /*ARGSUSED*/
498 static int
499 configure(int argc, char **argv, struct params *inparams, int flags)
500 {
501 struct params *p;
502 struct keygen *kg;
503 int fd;
504 int loop = 0;
505 int ret;
506 char cgdname[PATH_MAX];
507
508 if (argc == 2) {
509 char *pfile;
510
511 if (asprintf(&pfile, "%s/%s",
512 CGDCONFIG_DIR, basename(argv[1])) == -1)
513 return -1;
514
515 p = params_cget(pfile);
516 free(pfile);
517 } else if (argc == 3) {
518 p = params_cget(argv[2]);
519 } else {
520 /* print usage and exit, only if called from main() */
521 if (flags == CONFIG_FLAGS_FROMMAIN) {
522 warnx("wrong number of args");
523 usage();
524 }
525 return -1;
526 }
527
528 if (!p)
529 return -1;
530
531 /*
532 * over-ride with command line specifications and fill in default
533 * values.
534 */
535
536 p = params_combine(p, inparams);
537 ret = params_filldefaults(p);
538 if (ret) {
539 params_free(p);
540 return ret;
541 }
542
543 if (!params_verify(p)) {
544 warnx("params invalid");
545 return -1;
546 }
547
548 /*
549 * loop over configuring the disk and checking to see if it
550 * verifies properly. We open and close the disk device each
551 * time, because if the user passes us the block device we
552 * need to flush the buffer cache.
553 *
554 * We only loop if one of the verification methods prompts for
555 * a password.
556 */
557
558 for (kg = p->keygen; pflag == PFLAG_GETPASS && kg; kg = kg->next)
559 if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) ||
560 (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) {
561 loop = 1;
562 break;
563 }
564
565 for (;;) {
566 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
567 if (fd == -1)
568 return -1;
569
570 if (p->key)
571 bits_free(p->key);
572
573 p->key = getkey(argv[1], p->keygen, p->keylen);
574 if (!p->key)
575 goto bail_err;
576
577 ret = configure_params(fd, cgdname, argv[1], p);
578 if (ret)
579 goto bail_err;
580
581 ret = verify(p, fd);
582 if (ret == -1)
583 goto bail_err;
584 if (!ret)
585 break;
586
587 (void)unconfigure_fd(fd);
588 (void)cgd_kops.ko_close(fd);
589
590 if (!loop) {
591 warnx("verification failed permanently");
592 goto bail_err;
593 }
594
595 warnx("verification failed, please reenter passphrase");
596 }
597
598 params_free(p);
599 (void)cgd_kops.ko_close(fd);
600 return 0;
601 bail_err:
602 params_free(p);
603 (void)cgd_kops.ko_close(fd);
604 return -1;
605 }
606
607 static int
608 configure_stdin(struct params *p, int argc, char **argv)
609 {
610 int fd;
611 int ret;
612 char cgdname[PATH_MAX];
613
614 if (argc < 3 || argc > 4)
615 usage();
616
617 p->algorithm = string_fromcharstar(argv[2]);
618 if (argc > 3) {
619 size_t keylen;
620
621 if (parse_size_t(argv[3], &keylen) == -1) {
622 warn("failed to parse key length");
623 return -1;
624 }
625 p->keylen = keylen;
626 }
627
628 ret = params_filldefaults(p);
629 if (ret)
630 return ret;
631
632 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
633 if (fd == -1)
634 return -1;
635
636 p->key = bits_fget(stdin, p->keylen);
637 if (!p->key) {
638 warnx("failed to read key from stdin");
639 return -1;
640 }
641
642 return configure_params(fd, cgdname, argv[1], p);
643 }
644
645 static int
646 opendisk_werror(const char *cgd, char *buf, size_t buflen)
647 {
648 int fd;
649
650 VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd, buf, buflen));
651
652 /* sanity */
653 if (!cgd || !buf)
654 return -1;
655
656 if (nflag) {
657 if (strlcpy(buf, cgd, buflen) >= buflen)
658 return -1;
659 return 0;
660 }
661
662 fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, cgd_kops.ko_open);
663 if (fd == -1)
664 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
665
666 return fd;
667 }
668
669 static int
670 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
671 {
672 struct cgd_ioctl ci;
673
674 /* sanity */
675 if (!cgd || !dev)
676 return -1;
677
678 (void)memset(&ci, 0x0, sizeof(ci));
679 ci.ci_disk = dev;
680 ci.ci_alg = string_tocharstar(p->algorithm);
681 ci.ci_ivmethod = string_tocharstar(p->ivmeth);
682 ci.ci_key = bits_getbuf(p->key);
683 ci.ci_keylen = p->keylen;
684 ci.ci_blocksize = p->bsize;
685
686 VPRINTF(1, (" with alg %s keylen %zu blocksize %zu ivmethod %s\n",
687 string_tocharstar(p->algorithm), p->keylen, p->bsize,
688 string_tocharstar(p->ivmeth)));
689 VPRINTF(2, ("key: "));
690 VERBOSE(2, bits_fprint(stdout, p->key));
691 VPRINTF(2, ("\n"));
692
693 if (nflag)
694 return 0;
695
696 if (cgd_kops.ko_ioctl(fd, CGDIOCSET, &ci) == -1) {
697 int saved_errno = errno;
698 warn("ioctl");
699 return saved_errno;
700 }
701
702 return 0;
703 }
704
705 /*
706 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
707 */
708
709 #define SCANSIZE 8192
710
711 static int
712 verify(struct params *p, int fd)
713 {
714
715 switch (p->verify_method) {
716 case VERIFY_NONE:
717 return 0;
718 case VERIFY_DISKLABEL:
719 return verify_disklabel(fd);
720 case VERIFY_FFS:
721 return verify_ffs(fd);
722 case VERIFY_REENTER:
723 return verify_reenter(p);
724 default:
725 warnx("unimplemented verification method");
726 return -1;
727 }
728 }
729
730 static int
731 verify_disklabel(int fd)
732 {
733 struct disklabel l;
734 ssize_t ret;
735 char buf[SCANSIZE];
736
737 /*
738 * we simply scan the first few blocks for a disklabel, ignoring
739 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read
740 * a cgd, anyway, so it is unlikely that there will be non-native
741 * partition information.
742 */
743
744 ret = cgd_kops.ko_pread(fd, buf, 8192, 0);
745 if (ret < 0) {
746 warn("can't read disklabel area");
747 return -1;
748 }
749
750 /* now scan for the disklabel */
751
752 return disklabel_scan(&l, buf, (size_t)ret);
753 }
754
755 static off_t sblock_try[] = SBLOCKSEARCH;
756
757 static int
758 verify_ffs(int fd)
759 {
760 size_t i;
761
762 for (i = 0; sblock_try[i] != -1; i++) {
763 union {
764 char buf[SBLOCKSIZE];
765 struct fs fs;
766 } u;
767 ssize_t ret;
768
769 ret = cgd_kops.ko_pread(fd, &u, sizeof(u), sblock_try[i]);
770 if (ret < 0) {
771 warn("pread");
772 break;
773 } else if ((size_t)ret < sizeof(u)) {
774 warnx("pread: incomplete block");
775 break;
776 }
777 switch (u.fs.fs_magic) {
778 case FS_UFS1_MAGIC:
779 case FS_UFS2_MAGIC:
780 case FS_UFS1_MAGIC_SWAPPED:
781 case FS_UFS2_MAGIC_SWAPPED:
782 return 0;
783 default:
784 continue;
785 }
786 }
787
788 return 1; /* failure */
789 }
790
791 static int
792 verify_reenter(struct params *p)
793 {
794 struct keygen *kg;
795 bits_t *orig_key, *key;
796 int ret;
797
798 ret = 0;
799 for (kg = p->keygen; kg && !ret; kg = kg->next) {
800 if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
801 (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
802 continue;
803
804 orig_key = kg->kg_key;
805 kg->kg_key = NULL;
806
807 /* add a compat flag till the _OLD method goes away */
808 key = getkey_pkcs5_pbkdf2("re-enter device", kg,
809 bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
810 ret = !bits_match(key, orig_key);
811
812 bits_free(key);
813 bits_free(kg->kg_key);
814 kg->kg_key = orig_key;
815 }
816
817 return ret;
818 }
819
820 static int
821 generate(struct params *p, int argc, char **argv, const char *outfile)
822 {
823 int ret;
824
825 if (argc < 1 || argc > 2)
826 usage();
827
828 p->algorithm = string_fromcharstar(argv[0]);
829 if (argc > 1) {
830 size_t keylen;
831
832 if (parse_size_t(argv[1], &keylen) == -1) {
833 warn("Failed to parse key length");
834 return -1;
835 }
836 p->keylen = keylen;
837 }
838
839 ret = params_filldefaults(p);
840 if (ret)
841 return ret;
842
843 if (!p->keygen) {
844 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
845 if (!p->keygen)
846 return -1;
847 }
848
849 if (keygen_filldefaults(p->keygen, p->keylen)) {
850 warnx("Failed to generate defaults for keygen");
851 return -1;
852 }
853
854 if (!params_verify(p)) {
855 warnx("invalid parameters generated");
856 return -1;
857 }
858
859 return params_cput(p, outfile);
860 }
861
862 static int
863 generate_convert(struct params *p, int argc, char **argv, const char *outfile)
864 {
865 struct params *oldp;
866 struct keygen *kg;
867
868 if (argc != 1)
869 usage();
870
871 oldp = params_cget(*argv);
872 if (!oldp)
873 return -1;
874
875 /* for sanity, we ensure that none of the keygens are randomkey */
876 for (kg=p->keygen; kg; kg=kg->next)
877 if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
878 (kg->kg_method == KEYGEN_URANDOMKEY)) {
879 warnx("can't preserve randomly generated key");
880 goto bail;
881 }
882 for (kg=oldp->keygen; kg; kg=kg->next)
883 if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
884 (kg->kg_method == KEYGEN_URANDOMKEY)) {
885 warnx("can't preserve randomly generated key");
886 goto bail;
887 }
888
889 if (!params_verify(oldp)) {
890 warnx("invalid old parameters file \"%s\"", *argv);
891 return -1;
892 }
893
894 oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
895
896 /* we copy across the non-keygen info, here. */
897
898 string_free(p->algorithm);
899 string_free(p->ivmeth);
900
901 p->algorithm = string_dup(oldp->algorithm);
902 p->ivmeth = string_dup(oldp->ivmeth);
903 p->keylen = oldp->keylen;
904 p->bsize = oldp->bsize;
905 if (p->verify_method == VERIFY_UNKNOWN)
906 p->verify_method = oldp->verify_method;
907
908 params_free(oldp);
909
910 if (!p->keygen) {
911 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
912 if (!p->keygen)
913 return -1;
914 }
915 (void)params_filldefaults(p);
916 (void)keygen_filldefaults(p->keygen, p->keylen);
917 p->key = getkey("new file", p->keygen, p->keylen);
918
919 kg = keygen_generate(KEYGEN_STOREDKEY);
920 kg->kg_key = bits_xor(p->key, oldp->key);
921 keygen_addlist(&p->keygen, kg);
922
923 if (!params_verify(p)) {
924 warnx("can't generate new parameters file");
925 return -1;
926 }
927
928 return params_cput(p, outfile);
929 bail:
930 params_free(oldp);
931 return -1;
932 }
933
934 static int
935 /*ARGSUSED*/
936 do_all(const char *cfile, int argc, char **argv,
937 int (*conf)(int, char **, struct params *, int))
938 {
939 FILE *f;
940 size_t len;
941 size_t lineno;
942 int my_argc;
943 int ret;
944 const char *fn;
945 char *line;
946 char **my_argv;
947
948 if (argc > 0)
949 usage();
950
951 if (!cfile[0])
952 fn = CGDCONFIG_CFILE;
953 else
954 fn = cfile;
955
956 f = fopen(fn, "r");
957 if (!f) {
958 warn("could not open config file \"%s\"", fn);
959 return -1;
960 }
961
962 ret = chdir(CGDCONFIG_DIR);
963 if (ret == -1)
964 warn("could not chdir to %s", CGDCONFIG_DIR);
965
966 ret = 0;
967 lineno = 0;
968 for (;;) {
969 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
970 if (!line)
971 break;
972 if (!*line)
973 continue;
974
975 my_argv = words(line, &my_argc);
976 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
977 if (ret) {
978 warnx("action failed on \"%s\" line %lu", fn,
979 (u_long)lineno);
980 break;
981 }
982 words_free(my_argv, my_argc);
983 }
984 return ret;
985 }
986
987 static void
988 eliminate_cores(void)
989 {
990 struct rlimit rlp;
991
992 rlp.rlim_cur = 0;
993 rlp.rlim_max = 0;
994 if (setrlimit(RLIMIT_CORE, &rlp) == -1)
995 err(EXIT_FAILURE, "Can't disable cores");
996 }
997