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