gbde.c revision 105541
1105513Sphk/*- 2105513Sphk * Copyright (c) 2002 Poul-Henning Kamp 3105513Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 4105513Sphk * All rights reserved. 5105513Sphk * 6105513Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7105513Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 8105513Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9105513Sphk * DARPA CHATS research program. 10105513Sphk * 11105513Sphk * Redistribution and use in source and binary forms, with or without 12105513Sphk * modification, are permitted provided that the following conditions 13105513Sphk * are met: 14105513Sphk * 1. Redistributions of source code must retain the above copyright 15105513Sphk * notice, this list of conditions and the following disclaimer. 16105513Sphk * 2. Redistributions in binary form must reproduce the above copyright 17105513Sphk * notice, this list of conditions and the following disclaimer in the 18105513Sphk * documentation and/or other materials provided with the distribution. 19105513Sphk * 3. The names of the authors may not be used to endorse or promote 20105513Sphk * products derived from this software without specific prior written 21105513Sphk * permission. 22105513Sphk * 23105513Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24105513Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25105513Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26105513Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27105513Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28105513Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29105513Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30105513Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31105513Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32105513Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33105513Sphk * SUCH DAMAGE. 34105513Sphk * 35105513Sphk * $FreeBSD: head/sbin/gbde/gbde.c 105541 2002-10-20 19:08:56Z phk $ 36105513Sphk */ 37105513Sphk 38105513Sphk#include <sys/types.h> 39105513Sphk#include <sys/queue.h> 40105513Sphk#include <sys/mutex.h> 41105513Sphk#include <md5.h> 42105513Sphk#include <readpassphrase.h> 43105513Sphk#include <string.h> 44105513Sphk#include <stdint.h> 45105513Sphk#include <unistd.h> 46105513Sphk#include <fcntl.h> 47105513Sphk#include <strings.h> 48105513Sphk#include <stdlib.h> 49105513Sphk#include <err.h> 50105513Sphk#include <stdio.h> 51105513Sphk#include <libutil.h> 52105513Sphk#include <sys/errno.h> 53105513Sphk#include <sys/disk.h> 54105513Sphk#include <crypto/rijndael/rijndael.h> 55105513Sphk 56105513Sphk#include <geom/geom.h> 57105513Sphk#include <geom/bde/g_bde.h> 58105513Sphk 59105513Sphkextern const char template[]; 60105513Sphk 61105513Sphkstatic void __dead2 62105513Sphkusage(const char *reason) 63105513Sphk{ 64105513Sphk const char *p; 65105513Sphk 66105513Sphk p = getprogname(); 67105513Sphk fprintf(stderr, "Usage error: %s", reason); 68105513Sphk fprintf(stderr, "Usage:\n"); 69105513Sphk fprintf(stderr, "\t%s attach dest -l filename\n", p); 70105541Sphk fprintf(stderr, "\t%s detach dest\n", p); 71105513Sphk fprintf(stderr, "\t%s init dest [-i] [-f filename] -l filename\n", p); 72105513Sphk fprintf(stderr, "\t%s setkey dest [-n key] -l filename\n", p); 73105513Sphk fprintf(stderr, "\t%s destroy dest [-n key] -l filename\n", p); 74105513Sphk exit (1); 75105513Sphk} 76105513Sphk 77105513Sphkvoid * 78105513Sphkg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 79105513Sphk{ 80105513Sphk void *p; 81105513Sphk int fd, i; 82105513Sphk off_t o2; 83105513Sphk 84105513Sphk p = malloc(length); 85105513Sphk if (p == NULL) 86105513Sphk err(1, "malloc"); 87105513Sphk fd = *(int *)cp; 88105513Sphk o2 = lseek(fd, offset, SEEK_SET); 89105513Sphk if (o2 != offset) 90105513Sphk err(1, "lseek"); 91105513Sphk i = read(fd, p, length); 92105513Sphk if (i != length) 93105513Sphk err(1, "read"); 94105513Sphk if (error != NULL) 95105513Sphk error = 0; 96105513Sphk return (p); 97105513Sphk} 98105513Sphk 99105513Sphkstatic void 100105513Sphkrandom_bits(void *p, u_int len) 101105513Sphk{ 102105513Sphk static int fdr = -1; 103105513Sphk int i; 104105513Sphk 105105513Sphk if (fdr < 0) { 106105513Sphk fdr = open("/dev/urandom", O_RDONLY); 107105513Sphk if (fdr < 0) 108105513Sphk err(1, "/dev/urandom"); 109105513Sphk } 110105513Sphk 111105513Sphk i = read(fdr, p, len); 112105513Sphk if (i != (int)len) 113105513Sphk err(1, "read from /dev/urandom"); 114105513Sphk} 115105513Sphk 116105513Sphk/* XXX: not nice */ 117105513Sphkstatic u_char sbox[256]; 118105513Sphk 119105513Sphkstatic void 120105513Sphkreset_passphrase(struct g_bde_softc *sc) 121105513Sphk{ 122105513Sphk 123105513Sphk memcpy(sc->arc4_sbox, sbox, 256); 124105513Sphk sc->arc4_i = sc->arc4_j = 0; 125105513Sphk} 126105513Sphk 127105513Sphkstatic void 128105513Sphksetup_passphrase(struct g_bde_softc *sc, int sure, const char *input) 129105513Sphk{ 130105513Sphk char buf1[BUFSIZ], buf2[BUFSIZ], *p; 131105513Sphk 132105513Sphk if (input != NULL) { 133105513Sphk g_bde_arc4_seed(sc, input, strlen(input)); 134105513Sphk memcpy(sbox, sc->arc4_sbox, 256); 135105513Sphk return; 136105513Sphk } 137105513Sphk for (;;) { 138105513Sphk p = readpassphrase( 139105513Sphk sure ? "Enter new passphrase:" : "Enter passphrase: ", 140105513Sphk buf1, sizeof buf1, 141105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 142105513Sphk if (p == NULL) 143105513Sphk err(1, "readpassphrase"); 144105513Sphk 145105513Sphk if (sure) { 146105513Sphk p = readpassphrase("Reenter new passphrase: ", 147105513Sphk buf2, sizeof buf2, 148105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 149105513Sphk if (p == NULL) 150105513Sphk err(1, "readpassphrase"); 151105513Sphk 152105513Sphk if (strcmp(buf1, buf2)) { 153105513Sphk printf("They didn't match.\n"); 154105513Sphk continue; 155105513Sphk } 156105513Sphk } 157105513Sphk if (strlen(buf1) < 3) { 158105513Sphk printf("Too short passphrase.\n"); 159105513Sphk continue; 160105513Sphk } 161105513Sphk break; 162105513Sphk } 163105513Sphk g_bde_arc4_seed(sc, buf1, strlen(buf1)); 164105513Sphk memcpy(sbox, sc->arc4_sbox, 256); 165105513Sphk} 166105513Sphk 167105513Sphkstatic void 168105513Sphkencrypt_sector(void *d, int len, void *key) 169105513Sphk{ 170105513Sphk keyInstance ki; 171105513Sphk cipherInstance ci; 172105513Sphk int error; 173105513Sphk 174105513Sphk error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 175105513Sphk if (error <= 0) 176105513Sphk errx(1, "rijndael_cipherInit=%d", error); 177105513Sphk error = rijndael_makeKey(&ki, DIR_ENCRYPT, 128, key); 178105513Sphk if (error <= 0) 179105513Sphk errx(1, "rijndael_makeKeY=%d", error); 180105513Sphk error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 181105513Sphk if (error <= 0) 182105513Sphk errx(1, "rijndael_blockEncrypt=%d", error); 183105513Sphk} 184105513Sphk 185105513Sphkstatic void 186105513Sphkcmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 187105513Sphk{ 188105513Sphk int gfd, i, ffd; 189105513Sphk struct geomconfiggeom gcg; 190105513Sphk u_char buf[256 + 16]; 191105513Sphk 192105513Sphk gfd = open("/dev/geom.ctl", O_RDWR); 193105513Sphk if (gfd < 0) 194105513Sphk err(1, "/dev/geom.ctl"); 195105513Sphk memset(&gcg, 0, sizeof gcg); 196105513Sphk gcg.class.u.name = "BDE"; 197105513Sphk gcg.class.len = strlen(gcg.class.u.name); 198105513Sphk gcg.provider.u.name = dest; 199105513Sphk gcg.provider.len = strlen(gcg.provider.u.name); 200105513Sphk gcg.flag = 0; 201105513Sphk gcg.len = sizeof buf; 202105513Sphk gcg.ptr = buf; 203105513Sphk 204105513Sphk if (lfile != NULL) { 205105513Sphk ffd = open(lfile, O_RDONLY, 0); 206105513Sphk if (ffd < 0) 207105513Sphk err(1, lfile); 208105513Sphk read(ffd, buf + 256, 16); 209105513Sphk close(ffd); 210105513Sphk } else { 211105513Sphk memset(buf + 256, 0, 16); 212105513Sphk } 213105513Sphk memcpy(buf, sc->arc4_sbox, 256); 214105513Sphk 215105513Sphk i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 216105513Sphk if (i != 0) 217105513Sphk err(1, "ioctl(GEOMCONFIGGEOM)"); 218105513Sphk exit (0); 219105513Sphk} 220105513Sphk 221105513Sphkstatic void 222105541Sphkcmd_detach(const char *dest) 223105513Sphk{ 224105513Sphk int i, gfd; 225105513Sphk struct geomconfiggeom gcg; 226105513Sphk 227105513Sphk gfd = open("/dev/geom.ctl", O_RDWR); 228105513Sphk if (gfd < 0) 229105513Sphk err(1, "/dev/geom.ctl"); 230105513Sphk memset(&gcg, 0, sizeof gcg); 231105513Sphk gcg.class.u.name = "BDE"; 232105513Sphk gcg.class.len = strlen(gcg.class.u.name); 233105513Sphk gcg.provider.u.name = dest; 234105513Sphk gcg.provider.len = strlen(gcg.provider.u.name); 235105513Sphk gcg.flag = 1; 236105513Sphk 237105513Sphk i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 238105513Sphk if (i != 0) 239105513Sphk err(1, "ioctl(GEOMCONFIGGEOM)"); 240105513Sphk exit (0); 241105513Sphk} 242105513Sphk 243105513Sphkstatic void 244105513Sphkcmd_open(struct g_bde_softc *sc, int dfd __unused, const char *l_opt, u_int *nkey) 245105513Sphk{ 246105513Sphk int error; 247105513Sphk int ffd; 248105513Sphk u_char keyloc[16]; 249105513Sphk 250105513Sphk if (l_opt != NULL) { 251105513Sphk ffd = open(l_opt, O_RDONLY, 0); 252105513Sphk if (ffd < 0) 253105513Sphk err(1, l_opt); 254105513Sphk read(ffd, keyloc, sizeof keyloc); 255105513Sphk close(ffd); 256105513Sphk } else { 257105513Sphk memset(keyloc, 0, sizeof keyloc); 258105513Sphk } 259105513Sphk 260105513Sphk error = g_bde_decrypt_lock(sc, sbox, keyloc, 0xffffffff, 261105513Sphk 512, nkey); 262105513Sphk if (error == ENOENT) 263105513Sphk errx(1, "Lock was destroyed."); 264105513Sphk if (error == ESRCH) 265105513Sphk errx(1, "Lock was nuked."); 266105513Sphk if (error == ENOTDIR) 267105513Sphk errx(1, "Lock not found"); 268105513Sphk if (error != 0) 269105513Sphk errx(1, "Error %d decrypting lock", error); 270105513Sphk if (nkey) 271105513Sphk printf("Opened with key %u\n", *nkey); 272105513Sphk return; 273105513Sphk} 274105513Sphk 275105513Sphkstatic void 276105513Sphkcmd_nuke(struct g_bde_key *gl, int dfd , int key) 277105513Sphk{ 278105513Sphk int i; 279105513Sphk u_char *sbuf; 280105513Sphk off_t offset, offset2; 281105513Sphk 282105513Sphk sbuf = malloc(gl->sectorsize); 283105513Sphk memset(sbuf, 0, gl->sectorsize); 284105513Sphk offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 285105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 286105513Sphk if (offset2 != offset) 287105513Sphk err(1, "lseek"); 288105513Sphk i = write(dfd, sbuf, gl->sectorsize); 289105513Sphk if (i != (int)gl->sectorsize) 290105513Sphk err(1, "write"); 291105513Sphk printf("Nuked key %d\n", key); 292105513Sphk} 293105513Sphk 294105513Sphkstatic void 295105513Sphkcmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 296105513Sphk{ 297105513Sphk char buf[BUFSIZ]; 298105513Sphk int i, ffd; 299105513Sphk uint64_t off[2]; 300105513Sphk u_char keyloc[16]; 301105513Sphk u_char *sbuf, *q; 302105513Sphk MD5_CTX c; 303105513Sphk off_t offset, offset2; 304105513Sphk 305105513Sphk sbuf = malloc(gl->sectorsize); 306105513Sphk /* 307105513Sphk * Find the byte-offset in the lock sector where we will put the lock 308105513Sphk * data structure. We can put it any random place as long as the 309105513Sphk * structure fits. 310105513Sphk */ 311105513Sphk for(;;) { 312105513Sphk random_bits(off, sizeof off); 313105513Sphk off[0] &= (gl->sectorsize - 1); 314105513Sphk if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 315105513Sphk continue; 316105513Sphk break; 317105513Sphk } 318105513Sphk 319105513Sphk /* Add the sector offset in bytes */ 320105513Sphk off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 321105513Sphk gl->lsector[key] = off[0]; 322105513Sphk 323105513Sphk i = g_bde_keyloc_encrypt(sc, off, keyloc); 324105513Sphk if (i) 325105513Sphk errx(1, "g_bde_keyloc_encrypt()"); 326105513Sphk if (l_opt != NULL) { 327105513Sphk ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 328105513Sphk if (ffd < 0) 329105513Sphk err(1, l_opt); 330105513Sphk write(ffd, keyloc, sizeof keyloc); 331105513Sphk close(ffd); 332105513Sphk } else if (gl->flags & 1) { 333105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 334105513Sphk if (offset2 != 0) 335105513Sphk err(1, "lseek"); 336105513Sphk i = read(dfd, sbuf, gl->sectorsize); 337105513Sphk if (i != (int)gl->sectorsize) 338105513Sphk err(1, "read"); 339105513Sphk memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 340105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 341105513Sphk if (offset2 != 0) 342105513Sphk err(1, "lseek"); 343105513Sphk i = write(dfd, sbuf, gl->sectorsize); 344105513Sphk if (i != (int)gl->sectorsize) 345105513Sphk err(1, "write"); 346105513Sphk } else { 347105513Sphk errx(1, "No -L option and no space in sector 0 for lockfile"); 348105513Sphk } 349105513Sphk 350105513Sphk /* Allocate a sectorbuffer and fill it with random junk */ 351105513Sphk if (sbuf == NULL) 352105513Sphk err(1, "malloc"); 353105513Sphk random_bits(sbuf, gl->sectorsize); 354105513Sphk 355105513Sphk /* Fill in the hash field with something we can recognize again */ 356105513Sphk g_bde_arc4_seq(sc, buf, 16); 357105513Sphk MD5Init(&c); 358105513Sphk MD5Update(&c, "0000", 4); /* XXX: for future versioning */ 359105513Sphk MD5Update(&c, buf, 16); 360105513Sphk MD5Final(gl->hash, &c); 361105513Sphk 362105513Sphk /* Fill random bits in the spare field */ 363105513Sphk random_bits(gl->spare, sizeof(gl->spare)); 364105513Sphk 365105513Sphk /* Encode the structure where we want it */ 366105513Sphk q = sbuf + (off[0] % gl->sectorsize); 367105513Sphk g_bde_encode_lock(gl, q); 368105513Sphk 369105513Sphk /* 370105513Sphk * The encoded structure likely contains long sequences of zeros 371105513Sphk * which stick out as a sore thumb, so we XOR with key-material 372105513Sphk * to make it harder to recognize in a brute-force attack 373105513Sphk */ 374105513Sphk g_bde_arc4_seq(sc, buf, G_BDE_LOCKSIZE); 375105513Sphk for (i = 0; i < G_BDE_LOCKSIZE; i++) 376105513Sphk q[i] ^= buf[i]; 377105513Sphk 378105513Sphk g_bde_arc4_seq(sc, buf, 16); 379105513Sphk 380105513Sphk encrypt_sector(q, G_BDE_LOCKSIZE, buf); 381105513Sphk offset = gl->lsector[key] & ~(gl->sectorsize - 1); 382105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 383105513Sphk if (offset2 != offset) 384105513Sphk err(1, "lseek"); 385105513Sphk i = write(dfd, sbuf, gl->sectorsize); 386105513Sphk if (i != (int)gl->sectorsize) 387105513Sphk err(1, "write"); 388105513Sphk printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 389105513Sphk 390105513Sphk} 391105513Sphk 392105513Sphkstatic void 393105513Sphkcmd_destroy(struct g_bde_key *gl, int nkey) 394105513Sphk{ 395105513Sphk int i; 396105513Sphk 397105513Sphk bzero(&gl->sector0, sizeof gl->sector0); 398105513Sphk bzero(&gl->sectorN, sizeof gl->sectorN); 399105513Sphk bzero(&gl->keyoffset, sizeof gl->keyoffset); 400105513Sphk bzero(&gl->flags, sizeof gl->flags); 401105513Sphk bzero(gl->key, sizeof gl->key); 402105513Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) 403105513Sphk if (i != nkey) 404105513Sphk gl->lsector[i] = ~0; 405105513Sphk} 406105513Sphk 407105513Sphkstatic void 408105513Sphkcmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 409105513Sphk{ 410105513Sphk int i; 411105513Sphk u_char *buf; 412105513Sphk unsigned sector_size; 413105513Sphk uint64_t first_sector; 414105513Sphk uint64_t last_sector; 415105513Sphk uint64_t total_sectors; 416105513Sphk off_t off, off2; 417105513Sphk unsigned nkeys; 418105513Sphk const char *p; 419105513Sphk char *q, cbuf[BUFSIZ]; 420105513Sphk unsigned u, u2; 421105513Sphk uint64_t o; 422105513Sphk properties params; 423105513Sphk 424105513Sphk bzero(gl, sizeof *gl); 425105513Sphk if (f_opt != NULL) { 426105513Sphk i = open(f_opt, O_RDONLY); 427105513Sphk if (i < 0) 428105513Sphk err(1, f_opt); 429105513Sphk params = properties_read(i); 430105513Sphk close (i); 431105513Sphk } else { 432105513Sphk /* XXX: Polish */ 433105513Sphk q = strdup("/tmp/temp.XXXXXXXXXX"); 434105513Sphk i = mkstemp(q); 435105513Sphk if (i < 0) 436105513Sphk err(1, q); 437105513Sphk write(i, template, strlen(template)); 438105513Sphk close (i); 439105513Sphk if (i_opt) { 440105513Sphk p = getenv("EDITOR"); 441105513Sphk if (p == NULL) 442105513Sphk p = "vi"; 443105513Sphk sprintf(cbuf, "%s %s\n", p, q); 444105513Sphk system(cbuf); 445105513Sphk } 446105513Sphk i = open(q, O_RDONLY); 447105513Sphk if (i < 0) 448105513Sphk err(1, f_opt); 449105513Sphk params = properties_read(i); 450105513Sphk close (i); 451105513Sphk unlink(q); 452105513Sphk } 453105513Sphk 454105513Sphk /* <sector_size> */ 455105513Sphk p = property_find(params, "sector_size"); 456105513Sphk i = ioctl(dfd, DIOCGSECTORSIZE, &u); 457105513Sphk if (i == 0) 458105513Sphk sector_size = u; 459105513Sphk else if (p == NULL) 460105513Sphk errx(1, "Missing sector_size property"); 461105513Sphk if (p != NULL) { 462105513Sphk sector_size = strtoul(p, &q, 0); 463105513Sphk if (!*p || *q) 464105513Sphk errx(1, "sector_size not a proper number"); 465105513Sphk } 466105513Sphk if (sector_size & (sector_size - 1)) 467105513Sphk errx(1, "sector_size not a power of 2"); 468105513Sphk if (sector_size < 512) 469105513Sphk errx(1, "sector_size is smaller than 512"); 470105513Sphk buf = malloc(sector_size); 471105513Sphk if (buf == NULL) 472105513Sphk err(1, "Failed to malloc sector buffer"); 473105513Sphk gl->sectorsize = sector_size; 474105513Sphk 475105513Sphk i = ioctl(dfd, DIOCGMEDIASIZE, &off); 476105513Sphk if (i == 0) { 477105513Sphk first_sector = 0; 478105513Sphk total_sectors = off / sector_size; 479105513Sphk last_sector = total_sectors - 1; 480105513Sphk } else { 481105513Sphk first_sector = 0; 482105513Sphk last_sector = 0; 483105513Sphk total_sectors = 0; 484105513Sphk } 485105513Sphk 486105513Sphk /* <first_sector> */ 487105513Sphk p = property_find(params, "first_sector"); 488105513Sphk if (p != NULL) { 489105513Sphk first_sector = strtoul(p, &q, 0); 490105513Sphk if (!*p || *q) 491105513Sphk errx(1, "first_sector not a proper number"); 492105513Sphk } 493105513Sphk gl->sector0 = first_sector * gl->sectorsize; 494105513Sphk 495105513Sphk /* <last_sector> */ 496105513Sphk p = property_find(params, "last_sector"); 497105513Sphk if (p != NULL) { 498105513Sphk last_sector = strtoul(p, &q, 0); 499105513Sphk if (!*p || *q) 500105513Sphk errx(1, "last_sector not a proper number"); 501105513Sphk if (last_sector <= first_sector) 502105513Sphk errx(1, "last_sector not larger than first_sector"); 503105513Sphk total_sectors = last_sector + 1; 504105513Sphk } 505105513Sphk 506105513Sphk /* <total_sectors> */ 507105513Sphk p = property_find(params, "total_sectors"); 508105513Sphk if (p != NULL) { 509105513Sphk total_sectors = strtoul(p, &q, 0); 510105513Sphk if (!*p || *q) 511105513Sphk errx(1, "total_sectors not a proper number"); 512105513Sphk if (last_sector == 0) 513105513Sphk last_sector = first_sector + total_sectors - 1; 514105513Sphk } 515105513Sphk 516105513Sphk if (l_opt == NULL && first_sector != 0) 517105513Sphk errx(1, "No -L new-lockfile argument and first_sector != 0"); 518105513Sphk else if (l_opt == NULL) { 519105513Sphk first_sector++; 520105513Sphk total_sectors--; 521105513Sphk gl->flags |= 1; 522105513Sphk } 523105513Sphk 524105513Sphk if (total_sectors != (last_sector - first_sector) + 1) 525105513Sphk errx(1, "total_sectors disagree with first_sector and last_sector"); 526105513Sphk if (total_sectors == 0) 527105513Sphk errx(1, "missing last_sector or total_sectors"); 528105513Sphk 529105513Sphk gl->sectorN = (last_sector + 1) * gl->sectorsize; 530105513Sphk 531105513Sphk /* Find a random keyoffset */ 532105513Sphk random_bits(&o, sizeof o); 533105513Sphk o %= (gl->sectorN - gl->sector0); 534105513Sphk o &= ~(gl->sectorsize - 1); 535105513Sphk gl->keyoffset = o; 536105513Sphk 537105513Sphk /* <number_of_keys> */ 538105513Sphk p = property_find(params, "number_of_keys"); 539105513Sphk if (p == NULL) 540105513Sphk errx(1, "Missing number_of_keys property"); 541105513Sphk nkeys = strtoul(p, &q, 0); 542105513Sphk if (!*p || *q) 543105513Sphk errx(1, "number_of_keys not a proper number"); 544105513Sphk if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 545105513Sphk errx(1, "number_of_keys out of range"); 546105513Sphk for (u = 0; u < nkeys; u++) { 547105513Sphk for(;;) { 548105513Sphk do { 549105513Sphk random_bits(&o, sizeof o); 550105513Sphk o %= gl->sectorN; 551105513Sphk o &= ~(gl->sectorsize - 1); 552105513Sphk } while(o < gl->sector0); 553105513Sphk for (u2 = 0; u2 < u; u2++) 554105513Sphk if (o == gl->lsector[u2]) 555105513Sphk break; 556105513Sphk if (u2 < u) 557105513Sphk continue; 558105513Sphk break; 559105513Sphk } 560105513Sphk gl->lsector[u] = o; 561105513Sphk } 562105513Sphk for (; u < G_BDE_MAXKEYS; u++) { 563105513Sphk do 564105513Sphk random_bits(&o, sizeof o); 565105513Sphk while (o < gl->sectorN); 566105513Sphk gl->lsector[u] = o; 567105513Sphk } 568105513Sphk 569105513Sphk /* Flush sector zero if we use it for lockfile data */ 570105513Sphk if (gl->flags & 1) { 571105513Sphk off2 = lseek(dfd, 0, SEEK_SET); 572105513Sphk if (off2 != 0) 573105513Sphk err(1, "lseek(2) to sector 0"); 574105513Sphk random_bits(buf, sector_size); 575105513Sphk i = write(dfd, buf, sector_size); 576105513Sphk if (i != (int)sector_size) 577105513Sphk err(1, "write sector 0"); 578105513Sphk } 579105513Sphk 580105513Sphk /* <random_flush> */ 581105513Sphk p = property_find(params, "random_flush"); 582105513Sphk if (p != NULL) { 583105513Sphk off = first_sector * sector_size; 584105513Sphk off2 = lseek(dfd, off, SEEK_SET); 585105513Sphk if (off2 != off) 586105513Sphk err(1, "lseek(2) to first_sector"); 587105513Sphk off2 = last_sector * sector_size; 588105513Sphk while (off <= off2) { 589105513Sphk random_bits(buf, sector_size); 590105513Sphk i = write(dfd, buf, sector_size); 591105513Sphk if (i != (int)sector_size) 592105513Sphk err(1, "write to $device_name"); 593105513Sphk off += sector_size; 594105513Sphk } 595105513Sphk } 596105513Sphk 597105513Sphk random_bits(gl->key, sizeof gl->key); 598105513Sphk 599105513Sphk return; 600105513Sphk} 601105513Sphk 602105513Sphkstatic enum action { 603105513Sphk ACT_HUH, 604105541Sphk ACT_ATTACH, ACT_DETACH, 605105513Sphk ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 606105513Sphk} action; 607105513Sphk 608105513Sphkint 609105513Sphkmain(int argc, char **argv) 610105513Sphk{ 611105513Sphk const char *opts; 612105513Sphk const char *l_opt, *L_opt; 613105513Sphk const char *p_opt, *P_opt; 614105513Sphk const char *f_opt; 615105513Sphk const char *dest; 616105513Sphk int i_opt, n_opt, ch, dfd, nkey, doopen; 617105513Sphk int i; 618105513Sphk char *q; 619105513Sphk struct g_bde_key *gl; 620105513Sphk struct g_bde_softc sc; 621105513Sphk 622105513Sphk if (argc < 3) 623105513Sphk usage("Too few arguments\n"); 624105513Sphk 625105513Sphk doopen = 0; 626105513Sphk if (!strcmp(argv[1], "attach")) { 627105513Sphk action = ACT_ATTACH; 628105513Sphk opts = "l:p:"; 629105541Sphk } else if (!strcmp(argv[1], "detach")) { 630105541Sphk action = ACT_DETACH; 631105513Sphk opts = ""; 632105513Sphk } else if (!strcmp(argv[1], "init")) { 633105513Sphk action = ACT_INIT; 634105513Sphk doopen = 1; 635105513Sphk opts = "f:iL:P:"; 636105513Sphk } else if (!strcmp(argv[1], "setkey")) { 637105513Sphk action = ACT_SETKEY; 638105513Sphk doopen = 1; 639105513Sphk opts = "n:l:L:p:P:"; 640105513Sphk } else if (!strcmp(argv[1], "destroy")) { 641105513Sphk action = ACT_DESTROY; 642105513Sphk doopen = 1; 643105513Sphk opts = "l:p:"; 644105513Sphk } else if (!strcmp(argv[1], "nuke")) { 645105513Sphk action = ACT_NUKE; 646105513Sphk doopen = 1; 647105513Sphk opts = "l:p:n:"; 648105513Sphk } else { 649105513Sphk usage("Unknown sub command\n"); 650105513Sphk } 651105513Sphk argc--; 652105513Sphk argv++; 653105513Sphk 654105513Sphk dest = argv[1]; 655105513Sphk argc--; 656105513Sphk argv++; 657105513Sphk 658105513Sphk p_opt = NULL; 659105513Sphk P_opt = NULL; 660105513Sphk l_opt = NULL; 661105513Sphk L_opt = NULL; 662105513Sphk f_opt = NULL; 663105513Sphk n_opt = 0; 664105513Sphk i_opt = 0; 665105513Sphk 666105513Sphk while((ch = getopt(argc, argv, opts)) != -1) 667105513Sphk switch (ch) { 668105513Sphk case 'f': 669105513Sphk f_opt = optarg; 670105513Sphk break; 671105513Sphk case 'i': 672105513Sphk i_opt = !i_opt; 673105513Sphk case 'l': 674105513Sphk l_opt = optarg; 675105513Sphk break; 676105513Sphk case 'L': 677105513Sphk L_opt = optarg; 678105513Sphk break; 679105513Sphk case 'p': 680105513Sphk p_opt = optarg; 681105513Sphk break; 682105513Sphk case 'P': 683105513Sphk P_opt = optarg; 684105513Sphk break; 685105513Sphk case 'n': 686105513Sphk n_opt = strtoul(optarg, &q, 0); 687105513Sphk if (!*optarg || *q) 688105513Sphk usage("-n argument not numeric\n"); 689105513Sphk if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 690105513Sphk usage("-n argument out of range\n"); 691105513Sphk break; 692105513Sphk default: 693105513Sphk usage("Invalid option\n"); 694105513Sphk } 695105513Sphk 696105513Sphk if (doopen) { 697105513Sphk dfd = open(dest, O_RDWR | O_CREAT, 0644); 698105513Sphk if (dfd < 0) 699105513Sphk err(1, dest); 700105513Sphk } 701105513Sphk 702105513Sphk memset(&sc, 0, sizeof sc); 703105513Sphk sc.consumer = (struct g_consumer *)&dfd; 704105513Sphk gl = &sc.key; 705105513Sphk switch(action) { 706105513Sphk case ACT_ATTACH: 707105513Sphk setup_passphrase(&sc, 0, p_opt); 708105513Sphk cmd_attach(&sc, dest, l_opt); 709105513Sphk break; 710105541Sphk case ACT_DETACH: 711105541Sphk cmd_detach(dest); 712105513Sphk break; 713105513Sphk case ACT_INIT: 714105513Sphk cmd_init(gl, dfd, f_opt, i_opt, L_opt); 715105513Sphk setup_passphrase(&sc, 1, P_opt); 716105513Sphk cmd_write(gl, &sc, dfd, 0, L_opt); 717105513Sphk break; 718105513Sphk case ACT_SETKEY: 719105513Sphk setup_passphrase(&sc, 0, p_opt); 720105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 721105513Sphk if (n_opt == 0) 722105513Sphk n_opt = nkey + 1; 723105513Sphk setup_passphrase(&sc, 1, P_opt); 724105513Sphk cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 725105513Sphk break; 726105513Sphk case ACT_DESTROY: 727105513Sphk setup_passphrase(&sc, 0, p_opt); 728105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 729105513Sphk cmd_destroy(gl, nkey); 730105513Sphk reset_passphrase(&sc); 731105513Sphk cmd_write(gl, &sc, dfd, nkey, l_opt); 732105513Sphk break; 733105513Sphk case ACT_NUKE: 734105513Sphk setup_passphrase(&sc, 0, p_opt); 735105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 736105513Sphk if (n_opt == 0) 737105513Sphk n_opt = nkey + 1; 738105513Sphk if (n_opt == -1) { 739105513Sphk for(i = 0; i < G_BDE_MAXKEYS; i++) 740105513Sphk cmd_nuke(gl, dfd, i); 741105513Sphk } else { 742105513Sphk cmd_nuke(gl, dfd, n_opt - 1); 743105513Sphk } 744105513Sphk break; 745105513Sphk default: 746105513Sphk usage("Internal error\n"); 747105513Sphk } 748105513Sphk 749105513Sphk return(0); 750105513Sphk} 751