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