Home | History | Annotate | Line # | Download | only in cgdconfig
cgdconfig.c revision 1.2
      1 /* $NetBSD: cgdconfig.c,v 1.2 2002/10/12 15:56:26 elric Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2002 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\
     43 	The NetBSD Foundation, Inc.  All rights reserved.");
     44 __RCSID("$NetBSD: cgdconfig.c,v 1.2 2002/10/12 15:56:26 elric Exp $");
     45 #endif
     46 
     47 #include <errno.h>
     48 #include <fcntl.h>
     49 #include <libgen.h>
     50 #include <malloc.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/param.h>
     59 
     60 #include <dev/cgdvar.h>
     61 
     62 #include "params.h"
     63 #include "pkcs5_pbkdf2.h"
     64 #include "utils.h"
     65 
     66 #define CGDCONFIG_DIR		"/etc/cgd"
     67 #define CGDCONFIG_CFILE		CGDCONFIG_DIR "/cgd.conf"
     68 #define DEFAULT_SALTLEN		128
     69 
     70 #define ACTION_CONFIGURE	0x1	/* configure, with paramsfile */
     71 #define ACTION_UNCONFIGURE	0x2	/* unconfigure */
     72 #define ACTION_GENERATE		0x3	/* generate a paramsfile */
     73 #define ACTION_CONFIGALL	0x4	/* configure all from config file */
     74 #define ACTION_UNCONFIGALL	0x5	/* unconfigure all from config file */
     75 #define ACTION_CONFIGSTDIN	0x6	/* configure, key from stdin */
     76 
     77 /* if nflag is set, do not configure/unconfigure the cgd's */
     78 
     79 int	nflag = 0;
     80 
     81 static int	configure(int, char **, int);
     82 static int	configure_stdin(struct params *, int argc, char **);
     83 static int	generate(struct params *, int, char **, const char *);
     84 static int	unconfigure(int, char **, int);
     85 static int	do_all(const char *, int, char **, int (*)(int, char **, int));
     86 
     87 #define CONFIG_FLAGS_FROMALL	1	/* called from configure_all() */
     88 #define CONFIG_FLAGS_FROMMAIN	2	/* called from main() */
     89 
     90 static int	 configure_params(int, const char *, const char *,
     91 				  struct params *);
     92 static void	 key_print(FILE *, const u_int8_t *, int);
     93 static char	*getrandbits(int);
     94 static int	 getkey(const char *, struct params *);
     95 static int	 getkeyfrompassphrase(const char *, struct params *);
     96 static int	 getkeyfromfile(FILE *, struct params *);
     97 static int	 opendisk_werror(const char *, char *, int);
     98 
     99 static void	usage(void);
    100 
    101 /* Verbose Framework */
    102 int	verbose = 0;
    103 
    104 #define VERBOSE(x,y)	if (verbose >= x) y
    105 #define VPRINTF(x,y)	if (verbose >= x) printf y
    106 
    107 static void
    108 usage(void)
    109 {
    110 
    111 	fprintf(stderr, "usage: %s [-nv] cgd dev [paramsfile]\n",
    112 	    getprogname());
    113 	fprintf(stderr, "       %s -C [-nv] [-f configfile]\n", getprogname());
    114 	fprintf(stderr, "       %s -U [-nv] [-f configfile]\n", getprogname());
    115 	fprintf(stderr, "       %s -g [-nv] [-i ivmeth] [-k kgmeth] "
    116 	    "[-o outfile] alg [keylen]\n", getprogname());
    117 	fprintf(stderr, "       %s -s [-nv] [-i ivmeth] cgd dev alg "
    118 	    "[keylen]\n", getprogname());
    119 	fprintf(stderr, "       %s -u [-nv] cgd\n", getprogname());
    120 	exit(1);
    121 }
    122 
    123 int
    124 main(int argc, char **argv)
    125 {
    126 	struct params cf;
    127 	int	action = ACTION_CONFIGURE;
    128 	int	actions = 0;
    129 	int	ch;
    130 	int	ret;
    131 	char	cfile[FILENAME_MAX] = "";
    132 	char	outfile[FILENAME_MAX] = "";
    133 
    134 	setprogname(*argv);
    135 	params_init(&cf);
    136 
    137 	while ((ch = getopt(argc, argv, "CUb:f:gi:k:no:usv")) != -1)
    138 		switch (ch) {
    139 		case 'C':
    140 			action = ACTION_CONFIGALL;
    141 			actions++;
    142 			break;
    143 		case 'U':
    144 			action = ACTION_UNCONFIGALL;
    145 			actions++;
    146 			break;
    147 
    148 		case 'b':
    149 			ret = params_setbsize(&cf, atoi(optarg));
    150 			if (ret)
    151 				usage();
    152 			break;
    153 		case 'f':
    154 			strncpy(cfile, optarg, FILENAME_MAX);
    155 			break;
    156 		case 'g':
    157 			action = ACTION_GENERATE;
    158 			actions++;
    159 			break;
    160 		case 'i':
    161 			params_setivmeth(&cf, optarg);
    162 			break;
    163 		case 'k':
    164 			ret = params_setkeygen_method_str(&cf, optarg);
    165 			if (ret)
    166 				usage();
    167 			break;
    168 		case 'n':
    169 			nflag = 1;
    170 			break;
    171 		case 'o':
    172 			strncpy(outfile, optarg, FILENAME_MAX);
    173 			break;
    174 		case 's':
    175 			action = ACTION_CONFIGSTDIN;
    176 			actions++;
    177 			break;
    178 
    179 		case 'u':
    180 			action = ACTION_UNCONFIGURE;
    181 			actions++;
    182 			break;
    183 		case 'v':
    184 			verbose++;
    185 			break;
    186 		default:
    187 			usage();
    188 			/* NOTREACHED */
    189 		}
    190 
    191 	argc -= optind;
    192 	argv += optind;
    193 
    194 	/* validate the consistency of the arguments */
    195 
    196 	if (actions > 1)
    197 		usage();
    198 	if (action == ACTION_CONFIGURE && params_changed(&cf))
    199 		usage();
    200 
    201 	switch (action) {
    202 	case ACTION_CONFIGURE:
    203 		return configure(argc, argv, CONFIG_FLAGS_FROMMAIN);
    204 	case ACTION_UNCONFIGURE:
    205 		return unconfigure(argc, argv, CONFIG_FLAGS_FROMMAIN);
    206 	case ACTION_GENERATE:
    207 		return generate(&cf, argc, argv, outfile);
    208 	case ACTION_CONFIGALL:
    209 		return do_all(cfile, argc, argv, configure);
    210 	case ACTION_UNCONFIGALL:
    211 		return do_all(cfile, argc, argv, unconfigure);
    212 	case ACTION_CONFIGSTDIN:
    213 		return configure_stdin(&cf, argc, argv);
    214 	default:
    215 		fprintf(stderr, "undefined action\n");
    216 		return 1;
    217 	}
    218 	/* NOTREACHED */
    219 }
    220 
    221 static int
    222 getkey(const char *target, struct params *p)
    223 {
    224 
    225 	switch (p->keygen_method) {
    226 	case KEYGEN_RANDOMKEY:
    227 		p->key = getrandbits(p->keylen);
    228 		if (!p->key)
    229 			return -1;
    230 		return 0;
    231 	case KEYGEN_PKCS5_PBKDF2:
    232 		return getkeyfrompassphrase(target, p);
    233 	default:
    234 		fprintf(stderr, "getkey: unknown keygen_method\n");
    235 		return -1;
    236 	}
    237 	/* NOTREACHED */
    238 }
    239 
    240 static int
    241 getkeyfromfile(FILE *f, struct params *p)
    242 {
    243 	int	ret;
    244 
    245 	/* XXXrcd: data hiding? */
    246 	p->key = malloc(p->keylen);
    247 	if (!p->key)
    248 		return -1;
    249 	ret = fread(p->key, p->keylen, 1, f);
    250 	if (ret < 1) {
    251 		fprintf(stderr, "failed to read key from stdin\n");
    252 		return -1;
    253 	}
    254 	return 0;
    255 }
    256 
    257 static int
    258 getkeyfrompassphrase(const char *target, struct params *p)
    259 {
    260 	int	 ret;
    261 	char	*passp;
    262 	char	 buf[1024];
    263 
    264 	snprintf(buf, 1024, "%s's passphrase:", target);
    265 	passp = getpass(buf);
    266 	/* XXXrcd: data hiding ? we should be allocating the key here. */
    267 	ret = pkcs5_pbkdf2(&p->key, BITS2BYTES(p->keylen), passp,
    268 	    strlen(passp), p->keygen_salt, BITS2BYTES(p->keygen_saltlen),
    269 	    p->keygen_iterations);
    270 	if (p->xor_key)
    271 		memxor(p->key, p->xor_key, BITS2BYTES(p->keylen));
    272 	return ret;
    273 }
    274 
    275 static int
    276 unconfigure(int argc, char **argv, int flags)
    277 {
    278 	struct	cgd_ioctl ci;
    279 	int	fd;
    280 	int	ret;
    281 	char	buf[MAXPATHLEN] = "";
    282 
    283 	/* only complain about additional arguments, if called from main() */
    284 	if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
    285 		usage();
    286 
    287 	/* if called from do_all(), then ensure that 2 or 3 args exist */
    288 	if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
    289 		return -1;
    290 
    291 	fd = opendisk(*argv, O_RDWR, buf, sizeof(buf), 1);
    292 	if (fd == -1) {
    293 		fprintf(stderr, "can't open cgd \"%s\", \"%s\": %s\n",
    294 		    *argv, buf, strerror(errno));
    295 
    296 		/* this isn't fatal with nflag != 0 */
    297 		if (!nflag)
    298 			return errno;
    299 	}
    300 
    301 	VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
    302 
    303 	if (nflag)
    304 		return 0;
    305 
    306 	ret = ioctl(fd, CGDIOCCLR, &ci);
    307 	if (ret == -1) {
    308 		perror("ioctl");
    309 		return errno;
    310 	}
    311 
    312 	return 0;
    313 }
    314 
    315 /* ARGSUSED */
    316 static int
    317 configure(int argc, char **argv, int flags)
    318 {
    319 	struct params	params;
    320 	int		fd;
    321 	int		ret;
    322 	char		pfile[FILENAME_MAX];
    323 	char		cgdname[PATH_MAX];
    324 
    325 	params_init(&params);
    326 
    327 	switch (argc) {
    328 	case 2:
    329 		strlcpy(pfile, CGDCONFIG_DIR, FILENAME_MAX);
    330 		strlcat(pfile, "/", FILENAME_MAX);
    331 		strlcat(pfile, basename(argv[1]), FILENAME_MAX);
    332 		break;
    333 	case 3:
    334 		strlcpy(pfile, argv[2], FILENAME_MAX);
    335 		break;
    336 	default:
    337 		/* print usage and exit, only if called from main() */
    338 		if (flags == CONFIG_FLAGS_FROMMAIN)
    339 			usage();
    340 		return -1;
    341 		/* NOTREACHED */
    342 	}
    343 
    344 	ret = params_cget(&params, pfile);
    345 	if (ret)
    346 		return ret;
    347 	ret = params_filldefaults(&params);
    348 	if (ret)
    349 		return ret;
    350 
    351 	fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    352 	if (fd == -1)
    353 		return -1;
    354 
    355 	ret = getkey(argv[1], &params);
    356 	if (ret)
    357 		return ret;
    358 
    359 	ret = configure_params(fd, cgdname, argv[1], &params);
    360 
    361 	params_free(&params);
    362 	return ret;
    363 }
    364 
    365 static int
    366 configure_stdin(struct params *p, int argc, char **argv)
    367 {
    368 	int	fd;
    369 	int	ret;
    370 	char	cgdname[PATH_MAX];
    371 
    372 	if (argc < 3 || argc > 4)
    373 		usage();
    374 
    375 	ret = params_setalgorithm(p, argv[2]);
    376 	if (ret)
    377 		return ret;
    378 	if (argc > 3) {
    379 		ret = params_setkeylen(p, atoi(argv[3]));
    380 		if (ret)
    381 			return ret;
    382 	}
    383 
    384 	ret = params_filldefaults(p);
    385 	if (ret)
    386 		return ret;
    387 
    388 	fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    389 	if (fd == -1)
    390 		return -1;
    391 
    392 	ret = getkeyfromfile(stdin, p);
    393 	if (ret)
    394 		return -1;
    395 
    396 	return configure_params(fd, cgdname, argv[1], p);
    397 }
    398 
    399 static int
    400 opendisk_werror(const char *cgd, char *buf, int buflen)
    401 {
    402 	int	fd;
    403 
    404 	/* sanity */
    405 	if (!cgd || !buf)
    406 		return -1;
    407 
    408 	if (nflag) {
    409 		strncpy(buf, cgd, buflen);
    410 		return 0;
    411 	}
    412 
    413 	fd = opendisk(cgd, O_RDWR, buf, buflen, 1);
    414 	if (fd == -1)
    415 		fprintf(stderr, "can't open cgd \"%s\", \"%s\": %s\n",
    416 		    cgd, buf, strerror(errno));
    417 	return fd;
    418 }
    419 
    420 static int
    421 configure_params(int fd, const char *cgd, const char *dev, struct params *p)
    422 {
    423 	struct cgd_ioctl ci;
    424 	int	  ret;
    425 
    426 	/* sanity */
    427 	if (!cgd || !dev)
    428 		return -1;
    429 
    430 	memset(&ci, 0x0, sizeof(ci));
    431 	ci.ci_disk = (char *)dev;
    432 	ci.ci_alg = p->alg;
    433 	ci.ci_ivmethod = p->ivmeth;
    434 	ci.ci_key = p->key;
    435 	ci.ci_keylen = p->keylen;
    436 	ci.ci_blocksize = p->bsize;
    437 
    438 	VPRINTF(1, ("attaching: %s attach to %s\n", cgd, dev));
    439 	VPRINTF(1, ("    with alg %s keylen %d blocksize %d ivmethod %s\n",
    440 	    p->alg, p->keylen, p->bsize, p->ivmeth));
    441 	VERBOSE(2, key_print(stdout, p->key, p->keylen));
    442 
    443 	if (nflag)
    444 		return 0;
    445 
    446 	ret = ioctl(fd, CGDIOCSET, &ci);
    447 	if (ret == -1) {
    448 		perror("ioctl");
    449 		return errno;
    450 	}
    451 
    452 	return 0;
    453 }
    454 
    455 static int
    456 generate(struct params *p, int argc, char **argv, const char *outfile)
    457 {
    458 	FILE	*f;
    459 	int	 ret;
    460 	char	*tmp;
    461 
    462 	if (argc < 1 || argc > 2)
    463 		usage();
    464 
    465 	ret = params_setalgorithm(p, argv[0]);
    466 	if (ret)
    467 		return ret;
    468 	if (argc > 1) {
    469 		ret = params_setkeylen(p, atoi(argv[1]));
    470 		if (ret)
    471 			return ret;
    472 	}
    473 
    474 	ret = params_filldefaults(p);
    475 	if (ret)
    476 		return ret;
    477 
    478 	if (!p->keygen_method != KEYGEN_RANDOMKEY) {
    479 		tmp = getrandbits(DEFAULT_SALTLEN);
    480 		params_setkeygen_salt(p, tmp, DEFAULT_SALTLEN);
    481 		free(tmp);
    482 		tmp = getrandbits(p->keylen);
    483 		params_setxor_key(p, tmp, p->keylen);
    484 		free(tmp);
    485 
    486 		/* XXXrcd: generate key hash, if desired */
    487 	}
    488 
    489 	if (*outfile) {
    490 		f = fopen(outfile, "w");
    491 		if (!f) {
    492 			fprintf(stderr, "could not open outfile \"%s\": %s\n",
    493 			    outfile, strerror(errno));
    494 			perror("fopen");
    495 			return -1;
    496 		}
    497 	} else {
    498 		f = stdout;
    499 	}
    500 
    501 	ret = params_fput(p, f);
    502 	params_free(p);
    503 	return ret;
    504 }
    505 
    506 static int
    507 do_all(const char *cfile, int argc, char **argv,
    508        int (*conf)(int, char **, int))
    509 {
    510 	FILE		 *f;
    511 	size_t		  len;
    512 	size_t		  lineno;
    513 	int		  my_argc;
    514 	int		  ret;
    515 	const char	 *fn;
    516 	char		 *line;
    517 	char		**my_argv;
    518 
    519 	if (argc > 0)
    520 		usage();
    521 
    522 	if (!cfile[0])
    523 		fn = CGDCONFIG_CFILE;
    524 	else
    525 		fn = cfile;
    526 
    527 	f = fopen(fn, "r");
    528 	if (!f) {
    529 		fprintf(stderr, "could not open config file \"%s\": %s\n",
    530 		    fn, strerror(errno));
    531 		return -1;
    532 	}
    533 
    534 	ret = 0;
    535 	lineno = 0;
    536 	for (;;) {
    537 
    538 		line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
    539 		if (!line)
    540 			break;
    541 		if (!*line)
    542 			continue;
    543 
    544 		my_argv = words(line, &my_argc);
    545 		ret = conf(my_argc, my_argv, CONFIG_FLAGS_FROMALL);
    546 		if (ret) {
    547 			fprintf(stderr, "on \"%s\" line %lu\n", fn,
    548 			    (u_long)lineno);
    549 			break;
    550 		}
    551 		words_free(my_argv, my_argc);
    552 	}
    553 	return ret;
    554 }
    555 
    556 /*
    557  * XXX: key_print doesn't work quite exactly properly if the keylength
    558  *      is not evenly divisible by 8.  If the key is not divisible by
    559  *      8 then a few extra bits are printed.
    560  */
    561 
    562 static void
    563 key_print(FILE *f, const u_int8_t *key, int len)
    564 {
    565 	int	i;
    566 	int	col;
    567 
    568 	len = BITS2BYTES(len);
    569 	fprintf(f, "key: ");
    570 	for (i=0, col=5; i < len; i++, col+=2) {
    571 		fprintf(f, "%02x", key[i]);
    572 		if (col > 70) {
    573 			col = 5 - 2;
    574 			fprintf(f, "\n     ");
    575 		}
    576 	}
    577 	fprintf(f, "\n");
    578 }
    579 
    580 static char *
    581 getrandbits(int len)
    582 {
    583 	FILE	*f;
    584 	int	 ret;
    585 	char	*res;
    586 
    587 	len = (len + 7) / 8;
    588 	res = malloc(len);
    589 	if (!res)
    590 		return NULL;
    591 	f = fopen("/dev/random", "r");
    592 	if (!f)
    593 		return NULL;
    594 	ret = fread(res, len, 1, f);
    595 	if (ret != 1) {
    596 		free(res);
    597 		return NULL;
    598 	}
    599 	return res;
    600 }
    601