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