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