cgdconfig.c revision 1.13 1 /* $NetBSD: cgdconfig.c,v 1.13 2005/03/30 15:45:56 elric 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.13 2005/03/30 15:45:56 elric 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/param.h>
60 #include <sys/resource.h>
61
62 #include <dev/cgdvar.h>
63
64 #include <ufs/ffs/fs.h>
65
66 #include "params.h"
67 #include "pkcs5_pbkdf2.h"
68 #include "utils.h"
69
70 #define CGDCONFIG_DIR "/etc/cgd"
71 #define CGDCONFIG_CFILE CGDCONFIG_DIR "/cgd.conf"
72
73 #define ACTION_CONFIGURE 0x1 /* configure, with paramsfile */
74 #define ACTION_UNCONFIGURE 0x2 /* unconfigure */
75 #define ACTION_GENERATE 0x3 /* generate a paramsfile */
76 #define ACTION_GENERATE_CONVERT 0x4 /* generate a ``dup'' paramsfile */
77 #define ACTION_CONFIGALL 0x5 /* configure all from config file */
78 #define ACTION_UNCONFIGALL 0x6 /* unconfigure all from config file */
79 #define ACTION_CONFIGSTDIN 0x7 /* configure, key from stdin */
80
81 /* if nflag is set, do not configure/unconfigure the cgd's */
82
83 int nflag = 0;
84
85 static int configure(int, char **, struct params *, int);
86 static int configure_stdin(struct params *, int argc, char **);
87 static int generate(struct params *, int, char **, const char *);
88 static int generate_convert(struct params *, int, char **, const char *);
89 static int unconfigure(int, char **, struct params *, int);
90 static int do_all(const char *, int, char **,
91 int (*)(int, char **, struct params *, int));
92
93 #define CONFIG_FLAGS_FROMALL 1 /* called from configure_all() */
94 #define CONFIG_FLAGS_FROMMAIN 2 /* called from main() */
95
96 static int configure_params(int, const char *, const char *,
97 struct params *);
98 static void eliminate_cores(void);
99 static bits_t *getkey(const char *, struct keygen *, int);
100 static bits_t *getkey_storedkey(const char *, struct keygen *, int);
101 static bits_t *getkey_randomkey(const char *, struct keygen *, int, int);
102 static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, int, int);
103 static int opendisk_werror(const char *, char *, int);
104 static int unconfigure_fd(int);
105 static int verify(struct params *, int);
106 static int verify_disklabel(int);
107 static int verify_ffs(int);
108 static int verify_reenter(struct params *);
109
110 static void usage(void);
111
112 /* Verbose Framework */
113 int verbose = 0;
114
115 #define VERBOSE(x,y) if (verbose >= x) y
116 #define VPRINTF(x,y) if (verbose >= x) printf y
117
118 static void
119 usage(void)
120 {
121
122 fprintf(stderr, "usage: %s [-nv] [-V vmeth] cgd dev [paramsfile]\n",
123 getprogname());
124 fprintf(stderr, " %s -C [-nv] [-f configfile]\n", getprogname());
125 fprintf(stderr, " %s -U [-nv] [-f configfile]\n", getprogname());
126 fprintf(stderr, " %s -G [-nv] [-i ivmeth] [-k kgmeth] "
127 "[-o outfile] paramsfile\n", getprogname());
128 fprintf(stderr, " %s -g [-nv] [-i ivmeth] [-k kgmeth] "
129 "[-o outfile] alg [keylen]\n", getprogname());
130 fprintf(stderr, " %s -s [-nv] [-i ivmeth] cgd dev alg "
131 "[keylen]\n", getprogname());
132 fprintf(stderr, " %s -u [-nv] cgd\n", getprogname());
133 exit(1);
134 }
135
136 int
137 main(int argc, char **argv)
138 {
139 struct params *p;
140 struct params *tp;
141 struct keygen *kg;
142 int action = ACTION_CONFIGURE;
143 int actions = 0;
144 int ch;
145 char cfile[FILENAME_MAX] = "";
146 char outfile[FILENAME_MAX] = "";
147
148 eliminate_cores();
149 setprogname(*argv);
150 p = params_new();
151 kg = NULL;
152
153 while ((ch = getopt(argc, argv, "CGUV:b:f:gi:k:no:usv")) != -1)
154 switch (ch) {
155 case 'C':
156 action = ACTION_CONFIGALL;
157 actions++;
158 break;
159 case 'G':
160 action = ACTION_GENERATE_CONVERT;
161 actions++;
162 break;
163 case 'U':
164 action = ACTION_UNCONFIGALL;
165 actions++;
166 break;
167 case 'V':
168 tp = params_verify_method(string_fromcharstar(optarg));
169 if (!tp)
170 usage();
171 p = params_combine(p, tp);
172 break;
173 case 'b':
174 tp = params_bsize(atoi(optarg));
175 if (!tp)
176 usage();
177 p = params_combine(p, tp);
178 break;
179 case 'f':
180 strlcpy(cfile, optarg, sizeof(cfile));
181 break;
182 case 'g':
183 action = ACTION_GENERATE;
184 actions++;
185 break;
186 case 'i':
187 tp = params_ivmeth(string_fromcharstar(optarg));
188 p = params_combine(p, tp);
189 break;
190 case 'k':
191 kg = keygen_method(string_fromcharstar(optarg));
192 if (!kg)
193 usage();
194 keygen_addlist(&p->keygen, kg);
195 break;
196 case 'n':
197 nflag = 1;
198 break;
199 case 'o':
200 strlcpy(outfile, optarg, sizeof(outfile));
201 break;
202 case 's':
203 action = ACTION_CONFIGSTDIN;
204 actions++;
205 break;
206
207 case 'u':
208 action = ACTION_UNCONFIGURE;
209 actions++;
210 break;
211 case 'v':
212 verbose++;
213 break;
214 default:
215 usage();
216 /* NOTREACHED */
217 }
218
219 argc -= optind;
220 argv += optind;
221
222 /* validate the consistency of the arguments */
223
224 if (actions > 1)
225 usage();
226
227 switch (action) {
228 case ACTION_CONFIGURE:
229 return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN);
230 case ACTION_UNCONFIGURE:
231 return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN);
232 case ACTION_GENERATE:
233 return generate(p, argc, argv, outfile);
234 case ACTION_GENERATE_CONVERT:
235 return generate_convert(p, argc, argv, outfile);
236 case ACTION_CONFIGALL:
237 return do_all(cfile, argc, argv, configure);
238 case ACTION_UNCONFIGALL:
239 return do_all(cfile, argc, argv, unconfigure);
240 case ACTION_CONFIGSTDIN:
241 return configure_stdin(p, argc, argv);
242 default:
243 errx(EXIT_FAILURE, "undefined action");
244 }
245 /* NOTREACHED */
246 }
247
248 static bits_t *
249 getkey(const char *dev, struct keygen *kg, int len)
250 {
251 bits_t *ret = NULL;
252 bits_t *tmp;
253
254 VPRINTF(3, ("getkey(\"%s\", %p, %d) called\n", dev, kg, len));
255 for (; kg; kg=kg->next) {
256 switch (kg->kg_method) {
257 case KEYGEN_STOREDKEY:
258 tmp = getkey_storedkey(dev, kg, len);
259 break;
260 case KEYGEN_RANDOMKEY:
261 tmp = getkey_randomkey(dev, kg, len, 1);
262 break;
263 case KEYGEN_URANDOMKEY:
264 tmp = getkey_randomkey(dev, kg, len, 0);
265 break;
266 case KEYGEN_PKCS5_PBKDF2_SHA1:
267 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
268 break;
269 /* provide backwards compatibility for old config files */
270 case KEYGEN_PKCS5_PBKDF2_OLD:
271 tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1);
272 break;
273 default:
274 warnx("unrecognised keygen method %d in getkey()",
275 kg->kg_method);
276 if (ret)
277 bits_free(ret);
278 return NULL;
279 }
280
281 if (ret)
282 ret = bits_xor_d(tmp, ret);
283 else
284 ret = tmp;
285 }
286
287 return ret;
288 }
289
290 /*ARGSUSED*/
291 static bits_t *
292 getkey_storedkey(const char *target, struct keygen *kg, int keylen)
293 {
294
295 return bits_dup(kg->kg_key);
296 }
297
298 /*ARGSUSED*/
299 static bits_t *
300 getkey_randomkey(const char *target, struct keygen *kg, int keylen, int hard)
301 {
302
303 return bits_getrandombits(keylen, hard);
304 }
305
306 /*ARGSUSED*/
307 /*
308 * XXX take, and pass through, a compat flag that indicates whether we
309 * provide backwards compatibility with a previous bug. The previous
310 * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a
311 * non-zero compat flag. The new default, and correct keygen method is
312 * called pcks5_pbkdf2/sha1. When the old method is removed, so will
313 * be the compat argument.
314 */
315 static bits_t *
316 getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, int keylen, int compat)
317 {
318 bits_t *ret;
319 char *passp;
320 char buf[1024];
321 u_int8_t *tmp;
322
323 snprintf(buf, sizeof(buf), "%s's passphrase:", target);
324 passp = getpass(buf);
325 if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), passp, strlen(passp),
326 bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)),
327 kg->kg_iterations, compat)) {
328 warnx("failed to generate PKCS#5 PBKDF2 key");
329 return NULL;
330 }
331
332 ret = bits_new(tmp, keylen);
333 kg->kg_key = bits_dup(ret);
334 free(tmp);
335 return ret;
336 }
337
338 /*ARGSUSED*/
339 static int
340 unconfigure(int argc, char **argv, struct params *inparams, int flags)
341 {
342 int fd;
343 int ret;
344 char buf[MAXPATHLEN] = "";
345
346 /* only complain about additional arguments, if called from main() */
347 if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
348 usage();
349
350 /* if called from do_all(), then ensure that 2 or 3 args exist */
351 if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
352 return -1;
353
354 fd = opendisk(*argv, O_RDWR, buf, sizeof(buf), 1);
355 if (fd == -1) {
356 warn("can't open cgd \"%s\", \"%s\"", *argv, buf);
357
358 /* this isn't fatal with nflag != 0 */
359 if (!nflag)
360 return errno;
361 }
362
363 VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
364
365 if (nflag)
366 return 0;
367
368 ret = unconfigure_fd(fd);
369 close(fd);
370 return ret;
371 }
372
373 static int
374 unconfigure_fd(int fd)
375 {
376 struct cgd_ioctl ci;
377 int ret;
378
379 ret = ioctl(fd, CGDIOCCLR, &ci);
380 if (ret == -1) {
381 perror("ioctl");
382 return -1;
383 }
384
385 return 0;
386 }
387
388 /*ARGSUSED*/
389 static int
390 configure(int argc, char **argv, struct params *inparams, int flags)
391 {
392 struct params *p;
393 int fd;
394 int ret;
395 char pfile[FILENAME_MAX];
396 char cgdname[PATH_MAX];
397
398 switch (argc) {
399 case 2:
400 strlcpy(pfile, CGDCONFIG_DIR, FILENAME_MAX);
401 strlcat(pfile, "/", FILENAME_MAX);
402 strlcat(pfile, basename(argv[1]), FILENAME_MAX);
403 break;
404 case 3:
405 strlcpy(pfile, argv[2], FILENAME_MAX);
406 break;
407 default:
408 /* print usage and exit, only if called from main() */
409 if (flags == CONFIG_FLAGS_FROMMAIN) {
410 warnx("wrong number of args");
411 usage();
412 }
413 return -1;
414 /* NOTREACHED */
415 }
416
417 p = params_cget(pfile);
418 if (!p)
419 return -1;
420
421 /*
422 * over-ride with command line specifications and fill in default
423 * values.
424 */
425
426 p = params_combine(p, inparams);
427 ret = params_filldefaults(p);
428 if (ret) {
429 params_free(p);
430 return ret;
431 }
432
433 if (!params_verify(p)) {
434 warnx("params invalid");
435 return -1;
436 }
437
438 /*
439 * loop over configuring the disk and checking to see if it
440 * verifies properly. We open and close the disk device each
441 * time, because if the user passes us the block device we
442 * need to flush the buffer cache.
443 */
444
445 for (;;) {
446 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
447 if (fd == -1)
448 return -1;
449
450 if (p->key)
451 bits_free(p->key);
452
453 p->key = getkey(argv[1], p->keygen, p->keylen);
454 if (!p->key)
455 goto bail_err;
456
457 ret = configure_params(fd, cgdname, argv[1], p);
458 if (ret)
459 goto bail_err;
460
461 ret = verify(p, fd);
462 if (ret == -1)
463 goto bail_err;
464 if (!ret)
465 break;
466
467 fprintf(stderr, "verification failed, please reenter "
468 "passphrase\n");
469
470 unconfigure_fd(fd);
471 close(fd);
472 }
473
474 params_free(p);
475 close(fd);
476 return 0;
477 bail_err:
478 params_free(p);
479 close(fd);
480 return -1;
481 }
482
483 static int
484 configure_stdin(struct params *p, int argc, char **argv)
485 {
486 int fd;
487 int ret;
488 char cgdname[PATH_MAX];
489
490 if (argc < 3 || argc > 4)
491 usage();
492
493 p->algorithm = string_fromcharstar(argv[2]);
494 if (argc > 3)
495 p->keylen = atoi(argv[3]);
496
497 ret = params_filldefaults(p);
498 if (ret)
499 return ret;
500
501 fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
502 if (fd == -1)
503 return -1;
504
505 p->key = bits_fget(stdin, p->keylen);
506 if (!p->key) {
507 warnx("failed to read key from stdin");
508 return -1;
509 }
510
511 return configure_params(fd, cgdname, argv[1], p);
512 }
513
514 static int
515 opendisk_werror(const char *cgd, char *buf, int buflen)
516 {
517 int fd;
518
519 VPRINTF(3, ("opendisk_werror(%s, %s, %d) called.\n", cgd, buf, buflen));
520
521 /* sanity */
522 if (!cgd || !buf)
523 return -1;
524
525 if (nflag) {
526 strlcpy(buf, cgd, buflen);
527 return 0;
528 }
529
530 fd = opendisk(cgd, O_RDWR, buf, buflen, 0);
531 if (fd == -1)
532 warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
533
534 return fd;
535 }
536
537 static int
538 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
539 {
540 struct cgd_ioctl ci;
541 int ret;
542
543 /* sanity */
544 if (!cgd || !dev)
545 return -1;
546
547 memset(&ci, 0x0, sizeof(ci));
548 ci.ci_disk = (char *)dev;
549 ci.ci_alg = (char *)string_tocharstar(p->algorithm);
550 ci.ci_ivmethod = (char *)string_tocharstar(p->ivmeth);
551 ci.ci_key = (char *)bits_getbuf(p->key);
552 ci.ci_keylen = p->keylen;
553 ci.ci_blocksize = p->bsize;
554
555 VPRINTF(1, (" with alg %s keylen %d blocksize %d ivmethod %s\n",
556 string_tocharstar(p->algorithm), p->keylen, p->bsize,
557 string_tocharstar(p->ivmeth)));
558 VPRINTF(2, ("key: "));
559 VERBOSE(2, bits_fprint(stdout, p->key));
560 VPRINTF(2, ("\n"));
561
562 if (nflag)
563 return 0;
564
565 ret = ioctl(fd, CGDIOCSET, &ci);
566 if (ret == -1) {
567 perror("ioctl");
568 return errno;
569 }
570
571 return 0;
572 }
573
574 /*
575 * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
576 */
577
578 #define SCANSIZE 8192
579
580 static int
581 verify(struct params *p, int fd)
582 {
583
584 switch (p->verify_method) {
585 case VERIFY_NONE:
586 return 0;
587 case VERIFY_DISKLABEL:
588 return verify_disklabel(fd);
589 case VERIFY_FFS:
590 return verify_ffs(fd);
591 case VERIFY_REENTER:
592 return verify_reenter(p);
593 default:
594 warnx("unimplemented verification method");
595 return -1;
596 }
597 }
598
599 static int
600 verify_disklabel(int fd)
601 {
602 struct disklabel l;
603 int ret;
604 char buf[SCANSIZE];
605
606 /*
607 * we simply scan the first few blocks for a disklabel, ignoring
608 * any MBR/filecore sorts of logic. MSDOS and RiscOS can't read
609 * a cgd, anyway, so it is unlikely that there will be non-native
610 * partition information.
611 */
612
613 ret = pread(fd, buf, 8192, 0);
614 if (ret == -1) {
615 warn("can't read disklabel area");
616 return -1;
617 }
618
619 /* now scan for the disklabel */
620
621 return disklabel_scan(&l, buf, sizeof(buf));
622 }
623
624 static off_t sblock_try[] = SBLOCKSEARCH;
625
626 static int
627 verify_ffs(int fd)
628 {
629 struct fs *fs;
630 int ret, i;
631 char buf[SBLOCKSIZE];
632
633 for (i = 0; sblock_try[i] != -1; i++) {
634 ret = pread(fd, buf, sizeof(buf), sblock_try[i]);
635 if (ret == -1) {
636 warn("pread");
637 return 0;
638 }
639 fs = (struct fs *)buf;
640 switch (fs->fs_magic) {
641 case FS_UFS1_MAGIC:
642 case FS_UFS2_MAGIC:
643 case FS_UFS1_MAGIC_SWAPPED:
644 case FS_UFS2_MAGIC_SWAPPED:
645 return 0;
646 default:
647 continue;
648 }
649 }
650 return 1;
651 }
652
653 static int
654 verify_reenter(struct params *p)
655 {
656 struct keygen *kg;
657 bits_t *orig_key, *key;
658 int ret;
659
660 ret = 0;
661 for (kg = p->keygen; kg && !ret; kg = kg->next) {
662 if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
663 (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
664 continue;
665
666 orig_key = kg->kg_key;
667 kg->kg_key = NULL;
668
669 /* add a compat flag till the _OLD method goes away */
670 key = getkey_pkcs5_pbkdf2("re-enter device", kg,
671 bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
672 ret = !bits_match(key, orig_key);
673
674 bits_free(key);
675 bits_free(kg->kg_key);
676 kg->kg_key = orig_key;
677 }
678
679 return ret;
680 }
681
682 static int
683 generate(struct params *p, int argc, char **argv, const char *outfile)
684 {
685 int ret;
686
687 if (argc < 1 || argc > 2)
688 usage();
689
690 p->algorithm = string_fromcharstar(argv[0]);
691 if (argc > 1)
692 p->keylen = atoi(argv[1]);
693
694 ret = params_filldefaults(p);
695 if (ret)
696 return ret;
697
698 if (!p->keygen) {
699 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
700 if (!p->keygen)
701 return -1;
702 }
703
704 if (keygen_filldefaults(p->keygen, p->keylen)) {
705 warnx("Failed to generate defaults for keygen");
706 return -1;
707 }
708
709 if (!params_verify(p)) {
710 warnx("invalid parameters generated");
711 return -1;
712 }
713
714 return params_cput(p, outfile);
715 }
716
717 static int
718 generate_convert(struct params *p, int argc, char **argv, const char *outfile)
719 {
720 struct params *oldp;
721 struct keygen *kg;
722
723 if (argc != 1)
724 usage();
725
726 oldp = params_cget(*argv);
727 if (!oldp)
728 return -1;
729
730 /* for sanity, we ensure that none of the keygens are randomkey */
731 for (kg=p->keygen; kg; kg=kg->next)
732 if (kg->kg_method == KEYGEN_RANDOMKEY)
733 goto bail;
734 for (kg=oldp->keygen; kg; kg=kg->next)
735 if (kg->kg_method == KEYGEN_RANDOMKEY)
736 goto bail;
737
738 if (!params_verify(oldp)) {
739 warnx("invalid old parameters file \"%s\"", *argv);
740 return -1;
741 }
742
743 oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
744
745 /* we copy across the non-keygen info, here. */
746
747 string_free(p->algorithm);
748 string_free(p->ivmeth);
749
750 p->algorithm = string_dup(oldp->algorithm);
751 p->ivmeth = string_dup(oldp->ivmeth);
752 p->keylen = oldp->keylen;
753 p->bsize = oldp->bsize;
754 if (p->verify_method == VERIFY_UNKNOWN)
755 p->verify_method = oldp->verify_method;
756
757 params_free(oldp);
758
759 if (!p->keygen) {
760 p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
761 if (!p->keygen)
762 return -1;
763 }
764 params_filldefaults(p);
765 keygen_filldefaults(p->keygen, p->keylen);
766 p->key = getkey("new file", p->keygen, p->keylen);
767
768 kg = keygen_generate(KEYGEN_STOREDKEY);
769 kg->kg_key = bits_xor(p->key, oldp->key);
770 keygen_addlist(&p->keygen, kg);
771
772 if (!params_verify(p)) {
773 warnx("can't generate new parameters file");
774 return -1;
775 }
776
777 return params_cput(p, outfile);
778 bail:
779 params_free(oldp);
780 return -1;
781 }
782
783 static int
784 do_all(const char *cfile, int argc, char **argv,
785 int (*conf)(int, char **, struct params *, int))
786 {
787 FILE *f;
788 size_t len;
789 size_t lineno;
790 int my_argc;
791 int ret;
792 const char *fn;
793 char *line;
794 char **my_argv;
795
796 if (argc > 0)
797 usage();
798
799 if (!cfile[0])
800 fn = CGDCONFIG_CFILE;
801 else
802 fn = cfile;
803
804 f = fopen(fn, "r");
805 if (!f) {
806 warn("could not open config file \"%s\"", fn);
807 return -1;
808 }
809
810 ret = chdir(CGDCONFIG_DIR);
811 if (ret == -1)
812 warn("could not chdir to %s", CGDCONFIG_DIR);
813
814 ret = 0;
815 lineno = 0;
816 for (;;) {
817 line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
818 if (!line)
819 break;
820 if (!*line)
821 continue;
822
823 my_argv = words(line, &my_argc);
824 ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
825 if (ret) {
826 warnx("action failed on \"%s\" line %lu", fn,
827 (u_long)lineno);
828 break;
829 }
830 words_free(my_argv, my_argc);
831 }
832 return ret;
833 }
834
835 static void
836 eliminate_cores(void)
837 {
838 struct rlimit rlp;
839 int ret;
840
841 rlp.rlim_cur = 0;
842 rlp.rlim_max = 0;
843 ret = setrlimit(RLIMIT_CORE, &rlp);
844 if (ret)
845 err(EXIT_FAILURE, "Can't disable cores");
846 }
847