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