gbde.c revision 108020
1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: head/sbin/gbde/gbde.c 108020 2002-12-18 07:25:33Z phk $ 33 */ 34 35#include <sys/types.h> 36#include <sys/queue.h> 37#include <sys/mutex.h> 38#include <md5.h> 39#include <readpassphrase.h> 40#include <string.h> 41#include <stdint.h> 42#include <unistd.h> 43#include <fcntl.h> 44#include <paths.h> 45#include <strings.h> 46#include <stdlib.h> 47#include <err.h> 48#include <stdio.h> 49#include <libutil.h> 50#include <sys/errno.h> 51#include <sys/disk.h> 52#include <sys/stat.h> 53#include <crypto/rijndael/rijndael.h> 54#include <crypto/sha2/sha2.h> 55 56#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0) 57 58#include <geom/geom.h> 59#include <geom/bde/g_bde.h> 60 61extern const char template[]; 62 63 64#if 0 65static void 66g_hexdump(void *ptr, int length) 67{ 68 int i, j, k; 69 unsigned char *cp; 70 71 cp = ptr; 72 for (i = 0; i < length; i+= 16) { 73 printf("%04x ", i); 74 for (j = 0; j < 16; j++) { 75 k = i + j; 76 if (k < length) 77 printf(" %02x", cp[k]); 78 else 79 printf(" "); 80 } 81 printf(" |"); 82 for (j = 0; j < 16; j++) { 83 k = i + j; 84 if (k >= length) 85 printf(" "); 86 else if (cp[k] >= ' ' && cp[k] <= '~') 87 printf("%c", cp[k]); 88 else 89 printf("."); 90 } 91 printf("|\n"); 92 } 93} 94#endif 95 96static void __dead2 97usage(const char *reason) 98{ 99 const char *p; 100 101 p = getprogname(); 102 fprintf(stderr, "Usage error: %s", reason); 103 fprintf(stderr, "Usage:\n"); 104 fprintf(stderr, "\t%s attach dest [-l lockfile]\n", p); 105 fprintf(stderr, "\t%s detach dest\n", p); 106 fprintf(stderr, "\t%s init /dev/dest [-i] [-f filename] [-L lockfile]\n", p); 107 fprintf(stderr, "\t%s setkey dest [-n key] [-l lockfile] [-L lockfile]\n", p); 108 fprintf(stderr, "\t%s destroy dest [-n key] [-l lockfile] [-L lockfile]\n", p); 109 exit (1); 110} 111 112void * 113g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 114{ 115 void *p; 116 int fd, i; 117 off_t o2; 118 119 p = malloc(length); 120 if (p == NULL) 121 err(1, "malloc"); 122 fd = *(int *)cp; 123 o2 = lseek(fd, offset, SEEK_SET); 124 if (o2 != offset) 125 err(1, "lseek"); 126 i = read(fd, p, length); 127 if (i != length) 128 err(1, "read"); 129 if (error != NULL) 130 error = 0; 131 return (p); 132} 133 134static void 135random_bits(void *p, u_int len) 136{ 137 static int fdr = -1; 138 int i; 139 140 if (fdr < 0) { 141 fdr = open("/dev/urandom", O_RDONLY); 142 if (fdr < 0) 143 err(1, "/dev/urandom"); 144 } 145 146 i = read(fdr, p, len); 147 if (i != (int)len) 148 err(1, "read from /dev/urandom"); 149} 150 151/* XXX: not nice */ 152static u_char sha2[SHA512_DIGEST_LENGTH]; 153 154static void 155reset_passphrase(struct g_bde_softc *sc) 156{ 157 158 memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH); 159} 160 161static void 162setup_passphrase(struct g_bde_softc *sc, int sure, const char *input) 163{ 164 char buf1[BUFSIZ], buf2[BUFSIZ], *p; 165 166 if (input != NULL) { 167 g_bde_hash_pass(sc, input, strlen(input)); 168 memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 169 return; 170 } 171 for (;;) { 172 p = readpassphrase( 173 sure ? "Enter new passphrase:" : "Enter passphrase: ", 174 buf1, sizeof buf1, 175 RPP_ECHO_OFF | RPP_REQUIRE_TTY); 176 if (p == NULL) 177 err(1, "readpassphrase"); 178 179 if (sure) { 180 p = readpassphrase("Reenter new passphrase: ", 181 buf2, sizeof buf2, 182 RPP_ECHO_OFF | RPP_REQUIRE_TTY); 183 if (p == NULL) 184 err(1, "readpassphrase"); 185 186 if (strcmp(buf1, buf2)) { 187 printf("They didn't match.\n"); 188 continue; 189 } 190 } 191 if (strlen(buf1) < 3) { 192 printf("Too short passphrase.\n"); 193 continue; 194 } 195 break; 196 } 197 g_bde_hash_pass(sc, buf1, strlen(buf1)); 198 memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 199} 200 201static void 202encrypt_sector(void *d, int len, int klen, void *key) 203{ 204 keyInstance ki; 205 cipherInstance ci; 206 int error; 207 208 error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 209 if (error <= 0) 210 errx(1, "rijndael_cipherInit=%d", error); 211 error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key); 212 if (error <= 0) 213 errx(1, "rijndael_makeKeY=%d", error); 214 error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 215 if (error <= 0) 216 errx(1, "rijndael_blockEncrypt=%d", error); 217} 218 219static void 220cmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 221{ 222 int gfd, i, ffd; 223 struct geomconfiggeom gcg; 224 u_char buf[256 + 16]; 225 226 gfd = open("/dev/geom.ctl", O_RDWR); 227 if (gfd < 0) 228 err(1, "/dev/geom.ctl"); 229 memset(&gcg, 0, sizeof gcg); 230 gcg.class.u.name = "BDE"; 231 gcg.class.len = strlen(gcg.class.u.name); 232 gcg.provider.u.name = dest; 233 gcg.provider.len = strlen(gcg.provider.u.name); 234 gcg.flag = GCFG_CREATE; 235 gcg.len = sizeof buf; 236 gcg.ptr = buf; 237 238 if (lfile != NULL) { 239 ffd = open(lfile, O_RDONLY, 0); 240 if (ffd < 0) 241 err(1, lfile); 242 read(ffd, buf + sizeof(sc->sha2), 16); 243 close(ffd); 244 } else { 245 memset(buf + sizeof(sc->sha2), 0, 16); 246 } 247 memcpy(buf, sc->sha2, sizeof(sc->sha2)); 248 249 i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 250 if (i != 0) 251 err(1, "ioctl(GEOMCONFIGGEOM)"); 252 exit (0); 253} 254 255static void 256cmd_detach(const char *dest) 257{ 258 int i, gfd; 259 struct geomconfiggeom gcg; 260 261 gfd = open("/dev/geom.ctl", O_RDWR); 262 if (gfd < 0) 263 err(1, "/dev/geom.ctl"); 264 memset(&gcg, 0, sizeof gcg); 265 gcg.class.u.name = "BDE"; 266 gcg.class.len = strlen(gcg.class.u.name); 267 gcg.provider.u.name = dest; 268 gcg.provider.len = strlen(gcg.provider.u.name); 269 gcg.flag = GCFG_DISMANTLE; 270 271 i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 272 if (i != 0) 273 err(1, "ioctl(GEOMCONFIGGEOM)"); 274 exit (0); 275} 276 277static void 278cmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey) 279{ 280 int error; 281 int ffd; 282 u_char keyloc[16]; 283 u_int sectorsize; 284 off_t mediasize; 285 struct stat st; 286 287 error = ioctl(dfd, DIOCGSECTORSIZE, §orsize); 288 if (error) 289 sectorsize = 512; 290 error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize); 291 if (error) { 292 error = fstat(dfd, &st); 293 if (error == 0 && S_ISREG(st.st_mode)) 294 mediasize = st.st_size; 295 else 296 error = ENOENT; 297 } 298 if (error) 299 mediasize = (off_t)-1; 300 if (l_opt != NULL) { 301 ffd = open(l_opt, O_RDONLY, 0); 302 if (ffd < 0) 303 err(1, l_opt); 304 read(ffd, keyloc, sizeof keyloc); 305 close(ffd); 306 } else { 307 memset(keyloc, 0, sizeof keyloc); 308 } 309 310 error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize, 311 sectorsize, nkey); 312 if (error == ENOENT) 313 errx(1, "Lock was destroyed."); 314 if (error == ESRCH) 315 errx(1, "Lock was nuked."); 316 if (error == ENOTDIR) 317 errx(1, "Lock not found"); 318 if (error != 0) 319 errx(1, "Error %d decrypting lock", error); 320 if (nkey) 321 printf("Opened with key %u\n", *nkey); 322 return; 323} 324 325static void 326cmd_nuke(struct g_bde_key *gl, int dfd , int key) 327{ 328 int i; 329 u_char *sbuf; 330 off_t offset, offset2; 331 332 sbuf = malloc(gl->sectorsize); 333 memset(sbuf, 0, gl->sectorsize); 334 offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 335 offset2 = lseek(dfd, offset, SEEK_SET); 336 if (offset2 != offset) 337 err(1, "lseek"); 338 i = write(dfd, sbuf, gl->sectorsize); 339 if (i != (int)gl->sectorsize) 340 err(1, "write"); 341 printf("Nuked key %d\n", key); 342} 343 344static void 345cmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 346{ 347 int i, ffd; 348 uint64_t off[2]; 349 u_char keyloc[16]; 350 u_char *sbuf, *q; 351 off_t offset, offset2; 352 353 sbuf = malloc(gl->sectorsize); 354 /* 355 * Find the byte-offset in the lock sector where we will put the lock 356 * data structure. We can put it any random place as long as the 357 * structure fits. 358 */ 359 for(;;) { 360 random_bits(off, sizeof off); 361 off[0] &= (gl->sectorsize - 1); 362 if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 363 continue; 364 break; 365 } 366 367 /* Add the sector offset in bytes */ 368 off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 369 gl->lsector[key] = off[0]; 370 371 i = g_bde_keyloc_encrypt(sc, off, keyloc); 372 if (i) 373 errx(1, "g_bde_keyloc_encrypt()"); 374 if (l_opt != NULL) { 375 ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 376 if (ffd < 0) 377 err(1, l_opt); 378 write(ffd, keyloc, sizeof keyloc); 379 close(ffd); 380 } else if (gl->flags & 1) { 381 offset2 = lseek(dfd, 0, SEEK_SET); 382 if (offset2 != 0) 383 err(1, "lseek"); 384 i = read(dfd, sbuf, gl->sectorsize); 385 if (i != (int)gl->sectorsize) 386 err(1, "read"); 387 memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 388 offset2 = lseek(dfd, 0, SEEK_SET); 389 if (offset2 != 0) 390 err(1, "lseek"); 391 i = write(dfd, sbuf, gl->sectorsize); 392 if (i != (int)gl->sectorsize) 393 err(1, "write"); 394 } else { 395 errx(1, "No -L option and no space in sector 0 for lockfile"); 396 } 397 398 /* Allocate a sectorbuffer and fill it with random junk */ 399 if (sbuf == NULL) 400 err(1, "malloc"); 401 random_bits(sbuf, gl->sectorsize); 402 403 /* Fill random bits in the spare field */ 404 random_bits(gl->spare, sizeof(gl->spare)); 405 406 /* Encode the structure where we want it */ 407 q = sbuf + (off[0] % gl->sectorsize); 408 i = g_bde_encode_lock(sc, gl, q); 409 if (i < 0) 410 errx(1, "programming error encoding lock"); 411 412 encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); 413 offset = gl->lsector[key] & ~(gl->sectorsize - 1); 414 offset2 = lseek(dfd, offset, SEEK_SET); 415 if (offset2 != offset) 416 err(1, "lseek"); 417 i = write(dfd, sbuf, gl->sectorsize); 418 if (i != (int)gl->sectorsize) 419 err(1, "write"); 420 printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 421 422} 423 424static void 425cmd_destroy(struct g_bde_key *gl, int nkey) 426{ 427 int i; 428 429 bzero(&gl->sector0, sizeof gl->sector0); 430 bzero(&gl->sectorN, sizeof gl->sectorN); 431 bzero(&gl->keyoffset, sizeof gl->keyoffset); 432 bzero(&gl->flags, sizeof gl->flags); 433 bzero(gl->mkey, sizeof gl->mkey); 434 for (i = 0; i < G_BDE_MAXKEYS; i++) 435 if (i != nkey) 436 gl->lsector[i] = ~0; 437} 438 439static void 440cmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 441{ 442 int i; 443 u_char *buf; 444 unsigned sector_size; 445 uint64_t first_sector; 446 uint64_t last_sector; 447 uint64_t total_sectors; 448 off_t off, off2; 449 unsigned nkeys; 450 const char *p; 451 char *q, cbuf[BUFSIZ]; 452 unsigned u, u2; 453 uint64_t o; 454 properties params; 455 456 bzero(gl, sizeof *gl); 457 if (f_opt != NULL) { 458 i = open(f_opt, O_RDONLY); 459 if (i < 0) 460 err(1, f_opt); 461 params = properties_read(i); 462 close (i); 463 } else { 464 /* XXX: Polish */ 465 q = strdup("/tmp/temp.XXXXXXXXXX"); 466 i = mkstemp(q); 467 if (i < 0) 468 err(1, q); 469 write(i, template, strlen(template)); 470 close (i); 471 if (i_opt) { 472 p = getenv("EDITOR"); 473 if (p == NULL) 474 p = "vi"; 475 sprintf(cbuf, "%s %s\n", p, q); 476 system(cbuf); 477 } 478 i = open(q, O_RDONLY); 479 if (i < 0) 480 err(1, f_opt); 481 params = properties_read(i); 482 close (i); 483 unlink(q); 484 } 485 486 /* <sector_size> */ 487 p = property_find(params, "sector_size"); 488 i = ioctl(dfd, DIOCGSECTORSIZE, &u); 489 if (p != NULL) { 490 sector_size = strtoul(p, &q, 0); 491 if (!*p || *q) 492 errx(1, "sector_size not a proper number"); 493 } else if (i == 0) { 494 sector_size = u; 495 } else { 496 errx(1, "Missing sector_size property"); 497 } 498 if (sector_size & (sector_size - 1)) 499 errx(1, "sector_size not a power of 2"); 500 if (sector_size < 512) 501 errx(1, "sector_size is smaller than 512"); 502 buf = malloc(sector_size); 503 if (buf == NULL) 504 err(1, "Failed to malloc sector buffer"); 505 gl->sectorsize = sector_size; 506 507 i = ioctl(dfd, DIOCGMEDIASIZE, &off); 508 if (i == 0) { 509 first_sector = 0; 510 total_sectors = off / sector_size; 511 last_sector = total_sectors - 1; 512 } else { 513 first_sector = 0; 514 last_sector = 0; 515 total_sectors = 0; 516 } 517 518 /* <first_sector> */ 519 p = property_find(params, "first_sector"); 520 if (p != NULL) { 521 first_sector = strtoul(p, &q, 0); 522 if (!*p || *q) 523 errx(1, "first_sector not a proper number"); 524 } 525 gl->sector0 = first_sector * gl->sectorsize; 526 527 /* <last_sector> */ 528 p = property_find(params, "last_sector"); 529 if (p != NULL) { 530 last_sector = strtoul(p, &q, 0); 531 if (!*p || *q) 532 errx(1, "last_sector not a proper number"); 533 if (last_sector <= first_sector) 534 errx(1, "last_sector not larger than first_sector"); 535 total_sectors = last_sector + 1; 536 } 537 538 /* <total_sectors> */ 539 p = property_find(params, "total_sectors"); 540 if (p != NULL) { 541 total_sectors = strtoul(p, &q, 0); 542 if (!*p || *q) 543 errx(1, "total_sectors not a proper number"); 544 if (last_sector == 0) 545 last_sector = first_sector + total_sectors - 1; 546 } 547 548 if (l_opt == NULL && first_sector != 0) 549 errx(1, "No -L new-lockfile argument and first_sector != 0"); 550 else if (l_opt == NULL) { 551 first_sector++; 552 total_sectors--; 553 gl->flags |= 1; 554 } 555 556 if (total_sectors != (last_sector - first_sector) + 1) 557 errx(1, "total_sectors disagree with first_sector and last_sector"); 558 if (total_sectors == 0) 559 errx(1, "missing last_sector or total_sectors"); 560 561 gl->sectorN = (last_sector + 1) * gl->sectorsize; 562 563 /* Find a random keyoffset */ 564 random_bits(&o, sizeof o); 565 o %= (gl->sectorN - gl->sector0); 566 o &= ~(gl->sectorsize - 1); 567 gl->keyoffset = o; 568 569 /* <number_of_keys> */ 570 p = property_find(params, "number_of_keys"); 571 if (p == NULL) 572 errx(1, "Missing number_of_keys property"); 573 nkeys = strtoul(p, &q, 0); 574 if (!*p || *q) 575 errx(1, "number_of_keys not a proper number"); 576 if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 577 errx(1, "number_of_keys out of range"); 578 for (u = 0; u < nkeys; u++) { 579 for(;;) { 580 do { 581 random_bits(&o, sizeof o); 582 o %= gl->sectorN; 583 o &= ~(gl->sectorsize - 1); 584 } while(o < gl->sector0); 585 for (u2 = 0; u2 < u; u2++) 586 if (o == gl->lsector[u2]) 587 break; 588 if (u2 < u) 589 continue; 590 break; 591 } 592 gl->lsector[u] = o; 593 } 594 for (; u < G_BDE_MAXKEYS; u++) { 595 do 596 random_bits(&o, sizeof o); 597 while (o < gl->sectorN); 598 gl->lsector[u] = o; 599 } 600 601 /* Flush sector zero if we use it for lockfile data */ 602 if (gl->flags & 1) { 603 off2 = lseek(dfd, 0, SEEK_SET); 604 if (off2 != 0) 605 err(1, "lseek(2) to sector 0"); 606 random_bits(buf, sector_size); 607 i = write(dfd, buf, sector_size); 608 if (i != (int)sector_size) 609 err(1, "write sector 0"); 610 } 611 612 /* <random_flush> */ 613 p = property_find(params, "random_flush"); 614 if (p != NULL) { 615 off = first_sector * sector_size; 616 off2 = lseek(dfd, off, SEEK_SET); 617 if (off2 != off) 618 err(1, "lseek(2) to first_sector"); 619 off2 = last_sector * sector_size; 620 while (off <= off2) { 621 random_bits(buf, sector_size); 622 i = write(dfd, buf, sector_size); 623 if (i != (int)sector_size) 624 err(1, "write to $device_name"); 625 off += sector_size; 626 } 627 } 628 629 random_bits(gl->mkey, sizeof gl->mkey); 630 random_bits(gl->salt, sizeof gl->salt); 631 632 return; 633} 634 635static enum action { 636 ACT_HUH, 637 ACT_ATTACH, ACT_DETACH, 638 ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 639} action; 640 641int 642main(int argc, char **argv) 643{ 644 const char *opts; 645 const char *l_opt, *L_opt; 646 const char *p_opt, *P_opt; 647 const char *f_opt; 648 char *dest; 649 int i_opt, n_opt, ch, dfd, doopen; 650 u_int nkey; 651 int i; 652 char *q, buf[BUFSIZ]; 653 struct g_bde_key *gl; 654 struct g_bde_softc sc; 655 656 if (argc < 3) 657 usage("Too few arguments\n"); 658 659 doopen = 0; 660 if (!strcmp(argv[1], "attach")) { 661 action = ACT_ATTACH; 662 opts = "l:p:"; 663 } else if (!strcmp(argv[1], "detach")) { 664 action = ACT_DETACH; 665 opts = ""; 666 } else if (!strcmp(argv[1], "init")) { 667 action = ACT_INIT; 668 doopen = 1; 669 opts = "f:iL:P:"; 670 } else if (!strcmp(argv[1], "setkey")) { 671 action = ACT_SETKEY; 672 doopen = 1; 673 opts = "n:l:L:p:P:"; 674 } else if (!strcmp(argv[1], "destroy")) { 675 action = ACT_DESTROY; 676 doopen = 1; 677 opts = "l:p:"; 678 } else if (!strcmp(argv[1], "nuke")) { 679 action = ACT_NUKE; 680 doopen = 1; 681 opts = "l:p:n:"; 682 } else { 683 usage("Unknown sub command\n"); 684 } 685 argc--; 686 argv++; 687 688 dest = strdup(argv[1]); 689 argc--; 690 argv++; 691 692 p_opt = NULL; 693 P_opt = NULL; 694 l_opt = NULL; 695 L_opt = NULL; 696 f_opt = NULL; 697 n_opt = 0; 698 i_opt = 0; 699 700 while((ch = getopt(argc, argv, opts)) != -1) 701 switch (ch) { 702 case 'f': 703 f_opt = optarg; 704 break; 705 case 'i': 706 i_opt = !i_opt; 707 case 'l': 708 l_opt = optarg; 709 break; 710 case 'L': 711 L_opt = optarg; 712 break; 713 case 'p': 714 p_opt = optarg; 715 break; 716 case 'P': 717 P_opt = optarg; 718 break; 719 case 'n': 720 n_opt = strtoul(optarg, &q, 0); 721 if (!*optarg || *q) 722 usage("-n argument not numeric\n"); 723 if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 724 usage("-n argument out of range\n"); break; 725 default: 726 usage("Invalid option\n"); 727 } 728 729 if (doopen) { 730 dfd = open(dest, O_RDWR | O_CREAT, 0644); 731 if (dfd < 0) { 732 sprintf(buf, "%s%s", _PATH_DEV, dest); 733 dfd = open(buf, O_RDWR | O_CREAT, 0644); 734 } 735 if (dfd < 0) 736 err(1, dest); 737 } else { 738 if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 739 strcpy(dest, dest + strlen(_PATH_DEV)); 740 if (strchr(dest, '/')) 741 usage("\"dest\" argument must be geom-name\n"); 742 } 743 744 memset(&sc, 0, sizeof sc); 745 sc.consumer = (void *)&dfd; 746 gl = &sc.key; 747 switch(action) { 748 case ACT_ATTACH: 749 setup_passphrase(&sc, 0, p_opt); 750 cmd_attach(&sc, dest, l_opt); 751 break; 752 case ACT_DETACH: 753 cmd_detach(dest); 754 break; 755 case ACT_INIT: 756 cmd_init(gl, dfd, f_opt, i_opt, L_opt); 757 setup_passphrase(&sc, 1, P_opt); 758 cmd_write(gl, &sc, dfd, 0, L_opt); 759 break; 760 case ACT_SETKEY: 761 setup_passphrase(&sc, 0, p_opt); 762 cmd_open(&sc, dfd, l_opt, &nkey); 763 if (n_opt == 0) 764 n_opt = nkey + 1; 765 setup_passphrase(&sc, 1, P_opt); 766 cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 767 break; 768 case ACT_DESTROY: 769 setup_passphrase(&sc, 0, p_opt); 770 cmd_open(&sc, dfd, l_opt, &nkey); 771 cmd_destroy(gl, nkey); 772 reset_passphrase(&sc); 773 cmd_write(gl, &sc, dfd, nkey, l_opt); 774 break; 775 case ACT_NUKE: 776 setup_passphrase(&sc, 0, p_opt); 777 cmd_open(&sc, dfd, l_opt, &nkey); 778 if (n_opt == 0) 779 n_opt = nkey + 1; 780 if (n_opt == -1) { 781 for(i = 0; i < G_BDE_MAXKEYS; i++) 782 cmd_nuke(gl, dfd, i); 783 } else { 784 cmd_nuke(gl, dfd, n_opt - 1); 785 } 786 break; 787 default: 788 usage("Internal error\n"); 789 } 790 791 return(0); 792} 793