gbde.c revision 108060
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 108060 2002-12-18 22:11:54Z 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#if 0 422 printf("s0 = %jd\n", (intmax_t)gl->sector0); 423 printf("sN = %jd\n", (intmax_t)gl->sectorN); 424 printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]); 425 printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]); 426 printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]); 427 printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]); 428 printf("k = %jd\n", (intmax_t)gl->keyoffset); 429 printf("ss = %jd\n", (intmax_t)gl->sectorsize); 430#endif 431} 432 433static void 434cmd_destroy(struct g_bde_key *gl, int nkey) 435{ 436 int i; 437 438 bzero(&gl->sector0, sizeof gl->sector0); 439 bzero(&gl->sectorN, sizeof gl->sectorN); 440 bzero(&gl->keyoffset, sizeof gl->keyoffset); 441 bzero(&gl->flags, sizeof gl->flags); 442 bzero(gl->mkey, sizeof gl->mkey); 443 for (i = 0; i < G_BDE_MAXKEYS; i++) 444 if (i != nkey) 445 gl->lsector[i] = ~0; 446} 447 448static int 449sorthelp(const void *a, const void *b) 450{ 451 const off_t *oa, *ob; 452 453 oa = a; 454 ob = b; 455 return (*oa - *ob); 456} 457 458static void 459cmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 460{ 461 int i; 462 u_char *buf; 463 unsigned sector_size; 464 uint64_t first_sector; 465 uint64_t last_sector; 466 uint64_t total_sectors; 467 off_t off, off2; 468 unsigned nkeys; 469 const char *p; 470 char *q, cbuf[BUFSIZ]; 471 unsigned u, u2; 472 uint64_t o; 473 properties params; 474 475 bzero(gl, sizeof *gl); 476 if (f_opt != NULL) { 477 i = open(f_opt, O_RDONLY); 478 if (i < 0) 479 err(1, f_opt); 480 params = properties_read(i); 481 close (i); 482 } else { 483 /* XXX: Polish */ 484 q = strdup("/tmp/temp.XXXXXXXXXX"); 485 i = mkstemp(q); 486 if (i < 0) 487 err(1, q); 488 write(i, template, strlen(template)); 489 close (i); 490 if (i_opt) { 491 p = getenv("EDITOR"); 492 if (p == NULL) 493 p = "vi"; 494 sprintf(cbuf, "%s %s\n", p, q); 495 system(cbuf); 496 } 497 i = open(q, O_RDONLY); 498 if (i < 0) 499 err(1, f_opt); 500 params = properties_read(i); 501 close (i); 502 unlink(q); 503 } 504 505 /* <sector_size> */ 506 p = property_find(params, "sector_size"); 507 i = ioctl(dfd, DIOCGSECTORSIZE, &u); 508 if (p != NULL) { 509 sector_size = strtoul(p, &q, 0); 510 if (!*p || *q) 511 errx(1, "sector_size not a proper number"); 512 } else if (i == 0) { 513 sector_size = u; 514 } else { 515 errx(1, "Missing sector_size property"); 516 } 517 if (sector_size & (sector_size - 1)) 518 errx(1, "sector_size not a power of 2"); 519 if (sector_size < 512) 520 errx(1, "sector_size is smaller than 512"); 521 buf = malloc(sector_size); 522 if (buf == NULL) 523 err(1, "Failed to malloc sector buffer"); 524 gl->sectorsize = sector_size; 525 526 i = ioctl(dfd, DIOCGMEDIASIZE, &off); 527 if (i == 0) { 528 first_sector = 0; 529 total_sectors = off / sector_size; 530 last_sector = total_sectors - 1; 531 } else { 532 first_sector = 0; 533 last_sector = 0; 534 total_sectors = 0; 535 } 536 537 /* <first_sector> */ 538 p = property_find(params, "first_sector"); 539 if (p != NULL) { 540 first_sector = strtoul(p, &q, 0); 541 if (!*p || *q) 542 errx(1, "first_sector not a proper number"); 543 } 544 545 /* <last_sector> */ 546 p = property_find(params, "last_sector"); 547 if (p != NULL) { 548 last_sector = strtoul(p, &q, 0); 549 if (!*p || *q) 550 errx(1, "last_sector not a proper number"); 551 if (last_sector <= first_sector) 552 errx(1, "last_sector not larger than first_sector"); 553 total_sectors = last_sector + 1; 554 } 555 556 /* <total_sectors> */ 557 p = property_find(params, "total_sectors"); 558 if (p != NULL) { 559 total_sectors = strtoul(p, &q, 0); 560 if (!*p || *q) 561 errx(1, "total_sectors not a proper number"); 562 if (last_sector == 0) 563 last_sector = first_sector + total_sectors - 1; 564 } 565 566 if (l_opt == NULL && first_sector != 0) 567 errx(1, "No -L new-lockfile argument and first_sector != 0"); 568 else if (l_opt == NULL) { 569 first_sector++; 570 total_sectors--; 571 gl->flags |= 1; 572 } 573 gl->sector0 = first_sector * gl->sectorsize; 574 575 if (total_sectors != (last_sector - first_sector) + 1) 576 errx(1, "total_sectors disagree with first_sector and last_sector"); 577 if (total_sectors == 0) 578 errx(1, "missing last_sector or total_sectors"); 579 580 gl->sectorN = (last_sector + 1) * gl->sectorsize; 581 582 /* Find a random keyoffset */ 583 random_bits(&o, sizeof o); 584 o %= (gl->sectorN - gl->sector0); 585 o &= ~(gl->sectorsize - 1); 586 gl->keyoffset = o; 587 588 /* <number_of_keys> */ 589 p = property_find(params, "number_of_keys"); 590 if (p == NULL) 591 errx(1, "Missing number_of_keys property"); 592 nkeys = strtoul(p, &q, 0); 593 if (!*p || *q) 594 errx(1, "number_of_keys not a proper number"); 595 if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 596 errx(1, "number_of_keys out of range"); 597 for (u = 0; u < nkeys; u++) { 598 for(;;) { 599 do { 600 random_bits(&o, sizeof o); 601 o %= gl->sectorN; 602 o &= ~(gl->sectorsize - 1); 603 } while(o < gl->sector0); 604 for (u2 = 0; u2 < u; u2++) 605 if (o == gl->lsector[u2]) 606 break; 607 if (u2 < u) 608 continue; 609 break; 610 } 611 gl->lsector[u] = o; 612 } 613 for (; u < G_BDE_MAXKEYS; u++) { 614 do 615 random_bits(&o, sizeof o); 616 while (o < gl->sectorN); 617 gl->lsector[u] = o; 618 } 619 qsort(gl->lsector, G_BDE_MAXKEYS, sizeof gl->lsector[0], sorthelp); 620 621 /* Flush sector zero if we use it for lockfile data */ 622 if (gl->flags & 1) { 623 off2 = lseek(dfd, 0, SEEK_SET); 624 if (off2 != 0) 625 err(1, "lseek(2) to sector 0"); 626 random_bits(buf, sector_size); 627 i = write(dfd, buf, sector_size); 628 if (i != (int)sector_size) 629 err(1, "write sector 0"); 630 } 631 632 /* <random_flush> */ 633 p = property_find(params, "random_flush"); 634 if (p != NULL) { 635 off = first_sector * sector_size; 636 off2 = lseek(dfd, off, SEEK_SET); 637 if (off2 != off) 638 err(1, "lseek(2) to first_sector"); 639 off2 = last_sector * sector_size; 640 while (off <= off2) { 641 random_bits(buf, sector_size); 642 i = write(dfd, buf, sector_size); 643 if (i != (int)sector_size) 644 err(1, "write to $device_name"); 645 off += sector_size; 646 } 647 } 648 649 random_bits(gl->mkey, sizeof gl->mkey); 650 random_bits(gl->salt, sizeof gl->salt); 651 652 return; 653} 654 655static enum action { 656 ACT_HUH, 657 ACT_ATTACH, ACT_DETACH, 658 ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 659} action; 660 661int 662main(int argc, char **argv) 663{ 664 const char *opts; 665 const char *l_opt, *L_opt; 666 const char *p_opt, *P_opt; 667 const char *f_opt; 668 char *dest; 669 int i_opt, n_opt, ch, dfd, doopen; 670 u_int nkey; 671 int i; 672 char *q, buf[BUFSIZ]; 673 struct g_bde_key *gl; 674 struct g_bde_softc sc; 675 676 if (argc < 3) 677 usage("Too few arguments\n"); 678 679 doopen = 0; 680 if (!strcmp(argv[1], "attach")) { 681 action = ACT_ATTACH; 682 opts = "l:p:"; 683 } else if (!strcmp(argv[1], "detach")) { 684 action = ACT_DETACH; 685 opts = ""; 686 } else if (!strcmp(argv[1], "init")) { 687 action = ACT_INIT; 688 doopen = 1; 689 opts = "f:iL:P:"; 690 } else if (!strcmp(argv[1], "setkey")) { 691 action = ACT_SETKEY; 692 doopen = 1; 693 opts = "n:l:L:p:P:"; 694 } else if (!strcmp(argv[1], "destroy")) { 695 action = ACT_DESTROY; 696 doopen = 1; 697 opts = "l:p:"; 698 } else if (!strcmp(argv[1], "nuke")) { 699 action = ACT_NUKE; 700 doopen = 1; 701 opts = "l:p:n:"; 702 } else { 703 usage("Unknown sub command\n"); 704 } 705 argc--; 706 argv++; 707 708 dest = strdup(argv[1]); 709 argc--; 710 argv++; 711 712 p_opt = NULL; 713 P_opt = NULL; 714 l_opt = NULL; 715 L_opt = NULL; 716 f_opt = NULL; 717 n_opt = 0; 718 i_opt = 0; 719 720 while((ch = getopt(argc, argv, opts)) != -1) 721 switch (ch) { 722 case 'f': 723 f_opt = optarg; 724 break; 725 case 'i': 726 i_opt = !i_opt; 727 case 'l': 728 l_opt = optarg; 729 break; 730 case 'L': 731 L_opt = optarg; 732 break; 733 case 'p': 734 p_opt = optarg; 735 break; 736 case 'P': 737 P_opt = optarg; 738 break; 739 case 'n': 740 n_opt = strtoul(optarg, &q, 0); 741 if (!*optarg || *q) 742 usage("-n argument not numeric\n"); 743 if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 744 usage("-n argument out of range\n"); break; 745 default: 746 usage("Invalid option\n"); 747 } 748 749 if (doopen) { 750 dfd = open(dest, O_RDWR | O_CREAT, 0644); 751 if (dfd < 0) { 752 sprintf(buf, "%s%s", _PATH_DEV, dest); 753 dfd = open(buf, O_RDWR | O_CREAT, 0644); 754 } 755 if (dfd < 0) 756 err(1, dest); 757 } else { 758 if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 759 strcpy(dest, dest + strlen(_PATH_DEV)); 760 if (strchr(dest, '/')) 761 usage("\"dest\" argument must be geom-name\n"); 762 } 763 764 memset(&sc, 0, sizeof sc); 765 sc.consumer = (void *)&dfd; 766 gl = &sc.key; 767 switch(action) { 768 case ACT_ATTACH: 769 setup_passphrase(&sc, 0, p_opt); 770 cmd_attach(&sc, dest, l_opt); 771 break; 772 case ACT_DETACH: 773 cmd_detach(dest); 774 break; 775 case ACT_INIT: 776 cmd_init(gl, dfd, f_opt, i_opt, L_opt); 777 setup_passphrase(&sc, 1, P_opt); 778 cmd_write(gl, &sc, dfd, 0, L_opt); 779 break; 780 case ACT_SETKEY: 781 setup_passphrase(&sc, 0, p_opt); 782 cmd_open(&sc, dfd, l_opt, &nkey); 783 if (n_opt == 0) 784 n_opt = nkey + 1; 785 setup_passphrase(&sc, 1, P_opt); 786 cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 787 break; 788 case ACT_DESTROY: 789 setup_passphrase(&sc, 0, p_opt); 790 cmd_open(&sc, dfd, l_opt, &nkey); 791 cmd_destroy(gl, nkey); 792 reset_passphrase(&sc); 793 cmd_write(gl, &sc, dfd, nkey, l_opt); 794 break; 795 case ACT_NUKE: 796 setup_passphrase(&sc, 0, p_opt); 797 cmd_open(&sc, dfd, l_opt, &nkey); 798 if (n_opt == 0) 799 n_opt = nkey + 1; 800 if (n_opt == -1) { 801 for(i = 0; i < G_BDE_MAXKEYS; i++) 802 cmd_nuke(gl, dfd, i); 803 } else { 804 cmd_nuke(gl, dfd, n_opt - 1); 805 } 806 break; 807 default: 808 usage("Internal error\n"); 809 } 810 811 return(0); 812} 813