gbde.c revision 107455
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 * 20105513Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21105513Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22105513Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23105513Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24105513Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25105513Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26105513Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27105513Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28105513Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29105513Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30105513Sphk * SUCH DAMAGE. 31105513Sphk * 32105513Sphk * $FreeBSD: head/sbin/gbde/gbde.c 107455 2002-12-01 15:58:28Z phk $ 33105513Sphk */ 34105513Sphk 35105513Sphk#include <sys/types.h> 36105513Sphk#include <sys/queue.h> 37105513Sphk#include <sys/mutex.h> 38105513Sphk#include <md5.h> 39105513Sphk#include <readpassphrase.h> 40105513Sphk#include <string.h> 41105513Sphk#include <stdint.h> 42105513Sphk#include <unistd.h> 43105513Sphk#include <fcntl.h> 44107455Sphk#include <paths.h> 45105513Sphk#include <strings.h> 46105513Sphk#include <stdlib.h> 47105513Sphk#include <err.h> 48105513Sphk#include <stdio.h> 49105513Sphk#include <libutil.h> 50105513Sphk#include <sys/errno.h> 51105513Sphk#include <sys/disk.h> 52106407Sphk#include <sys/stat.h> 53105513Sphk#include <crypto/rijndael/rijndael.h> 54106407Sphk#include <crypto/sha2/sha2.h> 55105513Sphk 56106407Sphk#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0) 57106407Sphk 58105513Sphk#include <geom/geom.h> 59105513Sphk#include <geom/bde/g_bde.h> 60105513Sphk 61105513Sphkextern const char template[]; 62105513Sphk 63106407Sphk 64106407Sphk#if 0 65106407Sphkstatic void 66106407Sphkg_hexdump(void *ptr, int length) 67106407Sphk{ 68106407Sphk int i, j, k; 69106407Sphk unsigned char *cp; 70106407Sphk 71106407Sphk cp = ptr; 72106407Sphk for (i = 0; i < length; i+= 16) { 73106407Sphk printf("%04x ", i); 74106407Sphk for (j = 0; j < 16; j++) { 75106407Sphk k = i + j; 76106407Sphk if (k < length) 77106407Sphk printf(" %02x", cp[k]); 78106407Sphk else 79106407Sphk printf(" "); 80106407Sphk } 81106407Sphk printf(" |"); 82106407Sphk for (j = 0; j < 16; j++) { 83106407Sphk k = i + j; 84106407Sphk if (k >= length) 85106407Sphk printf(" "); 86106407Sphk else if (cp[k] >= ' ' && cp[k] <= '~') 87106407Sphk printf("%c", cp[k]); 88106407Sphk else 89106407Sphk printf("."); 90106407Sphk } 91106407Sphk printf("|\n"); 92106407Sphk } 93106407Sphk} 94106407Sphk#endif 95106407Sphk 96105513Sphkstatic void __dead2 97105513Sphkusage(const char *reason) 98105513Sphk{ 99105513Sphk const char *p; 100105513Sphk 101105513Sphk p = getprogname(); 102105513Sphk fprintf(stderr, "Usage error: %s", reason); 103105513Sphk fprintf(stderr, "Usage:\n"); 104107455Sphk fprintf(stderr, "\t%s attach dest [-l lockfile]\n", p); 105105541Sphk fprintf(stderr, "\t%s detach dest\n", p); 106107455Sphk fprintf(stderr, "\t%s init /dev/dest [-i] [-f filename] [-L lockfile]\n", p); 107107455Sphk fprintf(stderr, "\t%s setkey dest [-n key] [-l lockfile] [-L lockfile]\n", p); 108107455Sphk fprintf(stderr, "\t%s destroy dest [-n key] [-l lockfile] [-L lockfile]\n", p); 109105513Sphk exit (1); 110105513Sphk} 111105513Sphk 112105513Sphkvoid * 113105513Sphkg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 114105513Sphk{ 115105513Sphk void *p; 116105513Sphk int fd, i; 117105513Sphk off_t o2; 118105513Sphk 119105513Sphk p = malloc(length); 120105513Sphk if (p == NULL) 121105513Sphk err(1, "malloc"); 122105513Sphk fd = *(int *)cp; 123105513Sphk o2 = lseek(fd, offset, SEEK_SET); 124105513Sphk if (o2 != offset) 125105513Sphk err(1, "lseek"); 126105513Sphk i = read(fd, p, length); 127105513Sphk if (i != length) 128105513Sphk err(1, "read"); 129105513Sphk if (error != NULL) 130105513Sphk error = 0; 131105513Sphk return (p); 132105513Sphk} 133105513Sphk 134105513Sphkstatic void 135105513Sphkrandom_bits(void *p, u_int len) 136105513Sphk{ 137105513Sphk static int fdr = -1; 138105513Sphk int i; 139105513Sphk 140105513Sphk if (fdr < 0) { 141105513Sphk fdr = open("/dev/urandom", O_RDONLY); 142105513Sphk if (fdr < 0) 143105513Sphk err(1, "/dev/urandom"); 144105513Sphk } 145105513Sphk 146105513Sphk i = read(fdr, p, len); 147105513Sphk if (i != (int)len) 148105513Sphk err(1, "read from /dev/urandom"); 149105513Sphk} 150105513Sphk 151105513Sphk/* XXX: not nice */ 152106407Sphkstatic u_char sha2[SHA512_DIGEST_LENGTH]; 153105513Sphk 154105513Sphkstatic void 155105513Sphkreset_passphrase(struct g_bde_softc *sc) 156105513Sphk{ 157105513Sphk 158106407Sphk memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH); 159105513Sphk} 160105513Sphk 161105513Sphkstatic void 162105513Sphksetup_passphrase(struct g_bde_softc *sc, int sure, const char *input) 163105513Sphk{ 164105513Sphk char buf1[BUFSIZ], buf2[BUFSIZ], *p; 165105513Sphk 166105513Sphk if (input != NULL) { 167106407Sphk g_bde_hash_pass(sc, input, strlen(input)); 168106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 169105513Sphk return; 170105513Sphk } 171105513Sphk for (;;) { 172105513Sphk p = readpassphrase( 173105513Sphk sure ? "Enter new passphrase:" : "Enter passphrase: ", 174105513Sphk buf1, sizeof buf1, 175105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 176105513Sphk if (p == NULL) 177105513Sphk err(1, "readpassphrase"); 178105513Sphk 179105513Sphk if (sure) { 180105513Sphk p = readpassphrase("Reenter new passphrase: ", 181105513Sphk buf2, sizeof buf2, 182105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 183105513Sphk if (p == NULL) 184105513Sphk err(1, "readpassphrase"); 185105513Sphk 186105513Sphk if (strcmp(buf1, buf2)) { 187105513Sphk printf("They didn't match.\n"); 188105513Sphk continue; 189105513Sphk } 190105513Sphk } 191105513Sphk if (strlen(buf1) < 3) { 192105513Sphk printf("Too short passphrase.\n"); 193105513Sphk continue; 194105513Sphk } 195105513Sphk break; 196105513Sphk } 197106407Sphk g_bde_hash_pass(sc, buf1, strlen(buf1)); 198106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 199105513Sphk} 200105513Sphk 201105513Sphkstatic void 202106407Sphkencrypt_sector(void *d, int len, int klen, void *key) 203105513Sphk{ 204105513Sphk keyInstance ki; 205105513Sphk cipherInstance ci; 206105513Sphk int error; 207105513Sphk 208105513Sphk error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 209105513Sphk if (error <= 0) 210105513Sphk errx(1, "rijndael_cipherInit=%d", error); 211106407Sphk error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key); 212105513Sphk if (error <= 0) 213105513Sphk errx(1, "rijndael_makeKeY=%d", error); 214105513Sphk error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 215105513Sphk if (error <= 0) 216105513Sphk errx(1, "rijndael_blockEncrypt=%d", error); 217105513Sphk} 218105513Sphk 219105513Sphkstatic void 220105513Sphkcmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 221105513Sphk{ 222105513Sphk int gfd, i, ffd; 223105513Sphk struct geomconfiggeom gcg; 224105513Sphk u_char buf[256 + 16]; 225105513Sphk 226105513Sphk gfd = open("/dev/geom.ctl", O_RDWR); 227105513Sphk if (gfd < 0) 228105513Sphk err(1, "/dev/geom.ctl"); 229105513Sphk memset(&gcg, 0, sizeof gcg); 230105513Sphk gcg.class.u.name = "BDE"; 231105513Sphk gcg.class.len = strlen(gcg.class.u.name); 232105513Sphk gcg.provider.u.name = dest; 233105513Sphk gcg.provider.len = strlen(gcg.provider.u.name); 234105513Sphk gcg.flag = 0; 235105513Sphk gcg.len = sizeof buf; 236105513Sphk gcg.ptr = buf; 237105513Sphk 238105513Sphk if (lfile != NULL) { 239105513Sphk ffd = open(lfile, O_RDONLY, 0); 240105513Sphk if (ffd < 0) 241105513Sphk err(1, lfile); 242106407Sphk read(ffd, buf + sizeof(sc->sha2), 16); 243105513Sphk close(ffd); 244105513Sphk } else { 245106407Sphk memset(buf + sizeof(sc->sha2), 0, 16); 246105513Sphk } 247106407Sphk memcpy(buf, sc->sha2, sizeof(sc->sha2)); 248105513Sphk 249105513Sphk i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 250105513Sphk if (i != 0) 251105513Sphk err(1, "ioctl(GEOMCONFIGGEOM)"); 252105513Sphk exit (0); 253105513Sphk} 254105513Sphk 255105513Sphkstatic void 256105541Sphkcmd_detach(const char *dest) 257105513Sphk{ 258105513Sphk int i, gfd; 259105513Sphk struct geomconfiggeom gcg; 260105513Sphk 261105513Sphk gfd = open("/dev/geom.ctl", O_RDWR); 262105513Sphk if (gfd < 0) 263105513Sphk err(1, "/dev/geom.ctl"); 264105513Sphk memset(&gcg, 0, sizeof gcg); 265105513Sphk gcg.class.u.name = "BDE"; 266105513Sphk gcg.class.len = strlen(gcg.class.u.name); 267105513Sphk gcg.provider.u.name = dest; 268105513Sphk gcg.provider.len = strlen(gcg.provider.u.name); 269105513Sphk gcg.flag = 1; 270105513Sphk 271105513Sphk i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 272105513Sphk if (i != 0) 273105513Sphk err(1, "ioctl(GEOMCONFIGGEOM)"); 274105513Sphk exit (0); 275105513Sphk} 276105513Sphk 277105513Sphkstatic void 278106407Sphkcmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey) 279105513Sphk{ 280105513Sphk int error; 281105513Sphk int ffd; 282105513Sphk u_char keyloc[16]; 283106407Sphk u_int sectorsize; 284106407Sphk off_t mediasize; 285106407Sphk struct stat st; 286105513Sphk 287106407Sphk error = ioctl(dfd, DIOCGSECTORSIZE, §orsize); 288106407Sphk if (error) 289106407Sphk sectorsize = 512; 290106407Sphk error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize); 291106407Sphk if (error) { 292106407Sphk error = fstat(dfd, &st); 293106407Sphk if (error == 0 && S_ISREG(st.st_mode)) 294106407Sphk mediasize = st.st_size; 295106407Sphk else 296106407Sphk error = ENOENT; 297106407Sphk } 298106407Sphk if (error) 299106407Sphk mediasize = (off_t)-1; 300105513Sphk if (l_opt != NULL) { 301105513Sphk ffd = open(l_opt, O_RDONLY, 0); 302105513Sphk if (ffd < 0) 303105513Sphk err(1, l_opt); 304105513Sphk read(ffd, keyloc, sizeof keyloc); 305105513Sphk close(ffd); 306105513Sphk } else { 307105513Sphk memset(keyloc, 0, sizeof keyloc); 308105513Sphk } 309105513Sphk 310106407Sphk error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize, 311106407Sphk sectorsize, nkey); 312105513Sphk if (error == ENOENT) 313105513Sphk errx(1, "Lock was destroyed."); 314105513Sphk if (error == ESRCH) 315105513Sphk errx(1, "Lock was nuked."); 316105513Sphk if (error == ENOTDIR) 317105513Sphk errx(1, "Lock not found"); 318105513Sphk if (error != 0) 319105513Sphk errx(1, "Error %d decrypting lock", error); 320105513Sphk if (nkey) 321105513Sphk printf("Opened with key %u\n", *nkey); 322105513Sphk return; 323105513Sphk} 324105513Sphk 325105513Sphkstatic void 326105513Sphkcmd_nuke(struct g_bde_key *gl, int dfd , int key) 327105513Sphk{ 328105513Sphk int i; 329105513Sphk u_char *sbuf; 330105513Sphk off_t offset, offset2; 331105513Sphk 332105513Sphk sbuf = malloc(gl->sectorsize); 333105513Sphk memset(sbuf, 0, gl->sectorsize); 334105513Sphk offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 335105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 336105513Sphk if (offset2 != offset) 337105513Sphk err(1, "lseek"); 338105513Sphk i = write(dfd, sbuf, gl->sectorsize); 339105513Sphk if (i != (int)gl->sectorsize) 340105513Sphk err(1, "write"); 341105513Sphk printf("Nuked key %d\n", key); 342105513Sphk} 343105513Sphk 344105513Sphkstatic void 345105513Sphkcmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 346105513Sphk{ 347105513Sphk int i, ffd; 348105513Sphk uint64_t off[2]; 349105513Sphk u_char keyloc[16]; 350105513Sphk u_char *sbuf, *q; 351105513Sphk off_t offset, offset2; 352105513Sphk 353105513Sphk sbuf = malloc(gl->sectorsize); 354105513Sphk /* 355105513Sphk * Find the byte-offset in the lock sector where we will put the lock 356105513Sphk * data structure. We can put it any random place as long as the 357105513Sphk * structure fits. 358105513Sphk */ 359105513Sphk for(;;) { 360105513Sphk random_bits(off, sizeof off); 361105513Sphk off[0] &= (gl->sectorsize - 1); 362105513Sphk if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 363105513Sphk continue; 364105513Sphk break; 365105513Sphk } 366105513Sphk 367105513Sphk /* Add the sector offset in bytes */ 368105513Sphk off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 369105513Sphk gl->lsector[key] = off[0]; 370105513Sphk 371105513Sphk i = g_bde_keyloc_encrypt(sc, off, keyloc); 372105513Sphk if (i) 373105513Sphk errx(1, "g_bde_keyloc_encrypt()"); 374105513Sphk if (l_opt != NULL) { 375105513Sphk ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 376105513Sphk if (ffd < 0) 377105513Sphk err(1, l_opt); 378105513Sphk write(ffd, keyloc, sizeof keyloc); 379105513Sphk close(ffd); 380105513Sphk } else if (gl->flags & 1) { 381105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 382105513Sphk if (offset2 != 0) 383105513Sphk err(1, "lseek"); 384105513Sphk i = read(dfd, sbuf, gl->sectorsize); 385105513Sphk if (i != (int)gl->sectorsize) 386105513Sphk err(1, "read"); 387105513Sphk memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 388105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 389105513Sphk if (offset2 != 0) 390105513Sphk err(1, "lseek"); 391105513Sphk i = write(dfd, sbuf, gl->sectorsize); 392105513Sphk if (i != (int)gl->sectorsize) 393105513Sphk err(1, "write"); 394105513Sphk } else { 395105513Sphk errx(1, "No -L option and no space in sector 0 for lockfile"); 396105513Sphk } 397105513Sphk 398105513Sphk /* Allocate a sectorbuffer and fill it with random junk */ 399105513Sphk if (sbuf == NULL) 400105513Sphk err(1, "malloc"); 401105513Sphk random_bits(sbuf, gl->sectorsize); 402105513Sphk 403105513Sphk /* Fill random bits in the spare field */ 404105513Sphk random_bits(gl->spare, sizeof(gl->spare)); 405105513Sphk 406105513Sphk /* Encode the structure where we want it */ 407105513Sphk q = sbuf + (off[0] % gl->sectorsize); 408106407Sphk i = g_bde_encode_lock(sc, gl, q); 409106407Sphk if (i < 0) 410106407Sphk errx(1, "programming error encoding lock"); 411105513Sphk 412106407Sphk encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); 413105513Sphk offset = gl->lsector[key] & ~(gl->sectorsize - 1); 414105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 415105513Sphk if (offset2 != offset) 416105513Sphk err(1, "lseek"); 417105513Sphk i = write(dfd, sbuf, gl->sectorsize); 418105513Sphk if (i != (int)gl->sectorsize) 419105513Sphk err(1, "write"); 420105513Sphk printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 421105513Sphk 422105513Sphk} 423105513Sphk 424105513Sphkstatic void 425105513Sphkcmd_destroy(struct g_bde_key *gl, int nkey) 426105513Sphk{ 427105513Sphk int i; 428105513Sphk 429105513Sphk bzero(&gl->sector0, sizeof gl->sector0); 430105513Sphk bzero(&gl->sectorN, sizeof gl->sectorN); 431105513Sphk bzero(&gl->keyoffset, sizeof gl->keyoffset); 432105513Sphk bzero(&gl->flags, sizeof gl->flags); 433106227Sphk bzero(gl->mkey, sizeof gl->mkey); 434105513Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) 435105513Sphk if (i != nkey) 436105513Sphk gl->lsector[i] = ~0; 437105513Sphk} 438105513Sphk 439105513Sphkstatic void 440105513Sphkcmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 441105513Sphk{ 442105513Sphk int i; 443105513Sphk u_char *buf; 444105513Sphk unsigned sector_size; 445105513Sphk uint64_t first_sector; 446105513Sphk uint64_t last_sector; 447105513Sphk uint64_t total_sectors; 448105513Sphk off_t off, off2; 449105513Sphk unsigned nkeys; 450105513Sphk const char *p; 451105513Sphk char *q, cbuf[BUFSIZ]; 452105513Sphk unsigned u, u2; 453105513Sphk uint64_t o; 454105513Sphk properties params; 455105513Sphk 456105513Sphk bzero(gl, sizeof *gl); 457105513Sphk if (f_opt != NULL) { 458105513Sphk i = open(f_opt, O_RDONLY); 459105513Sphk if (i < 0) 460105513Sphk err(1, f_opt); 461105513Sphk params = properties_read(i); 462105513Sphk close (i); 463105513Sphk } else { 464105513Sphk /* XXX: Polish */ 465105513Sphk q = strdup("/tmp/temp.XXXXXXXXXX"); 466105513Sphk i = mkstemp(q); 467105513Sphk if (i < 0) 468105513Sphk err(1, q); 469105513Sphk write(i, template, strlen(template)); 470105513Sphk close (i); 471105513Sphk if (i_opt) { 472105513Sphk p = getenv("EDITOR"); 473105513Sphk if (p == NULL) 474105513Sphk p = "vi"; 475105513Sphk sprintf(cbuf, "%s %s\n", p, q); 476105513Sphk system(cbuf); 477105513Sphk } 478105513Sphk i = open(q, O_RDONLY); 479105513Sphk if (i < 0) 480105513Sphk err(1, f_opt); 481105513Sphk params = properties_read(i); 482105513Sphk close (i); 483105513Sphk unlink(q); 484105513Sphk } 485105513Sphk 486105513Sphk /* <sector_size> */ 487105513Sphk p = property_find(params, "sector_size"); 488105513Sphk i = ioctl(dfd, DIOCGSECTORSIZE, &u); 489105513Sphk if (i == 0) 490105513Sphk sector_size = u; 491105513Sphk else if (p == NULL) 492105513Sphk errx(1, "Missing sector_size property"); 493105513Sphk if (p != NULL) { 494105513Sphk sector_size = strtoul(p, &q, 0); 495105513Sphk if (!*p || *q) 496105513Sphk errx(1, "sector_size not a proper number"); 497105513Sphk } 498105513Sphk if (sector_size & (sector_size - 1)) 499105513Sphk errx(1, "sector_size not a power of 2"); 500105513Sphk if (sector_size < 512) 501105513Sphk errx(1, "sector_size is smaller than 512"); 502105513Sphk buf = malloc(sector_size); 503105513Sphk if (buf == NULL) 504105513Sphk err(1, "Failed to malloc sector buffer"); 505105513Sphk gl->sectorsize = sector_size; 506105513Sphk 507105513Sphk i = ioctl(dfd, DIOCGMEDIASIZE, &off); 508105513Sphk if (i == 0) { 509105513Sphk first_sector = 0; 510105513Sphk total_sectors = off / sector_size; 511105513Sphk last_sector = total_sectors - 1; 512105513Sphk } else { 513105513Sphk first_sector = 0; 514105513Sphk last_sector = 0; 515105513Sphk total_sectors = 0; 516105513Sphk } 517105513Sphk 518105513Sphk /* <first_sector> */ 519105513Sphk p = property_find(params, "first_sector"); 520105513Sphk if (p != NULL) { 521105513Sphk first_sector = strtoul(p, &q, 0); 522105513Sphk if (!*p || *q) 523105513Sphk errx(1, "first_sector not a proper number"); 524105513Sphk } 525105513Sphk gl->sector0 = first_sector * gl->sectorsize; 526105513Sphk 527105513Sphk /* <last_sector> */ 528105513Sphk p = property_find(params, "last_sector"); 529105513Sphk if (p != NULL) { 530105513Sphk last_sector = strtoul(p, &q, 0); 531105513Sphk if (!*p || *q) 532105513Sphk errx(1, "last_sector not a proper number"); 533105513Sphk if (last_sector <= first_sector) 534105513Sphk errx(1, "last_sector not larger than first_sector"); 535105513Sphk total_sectors = last_sector + 1; 536105513Sphk } 537105513Sphk 538105513Sphk /* <total_sectors> */ 539105513Sphk p = property_find(params, "total_sectors"); 540105513Sphk if (p != NULL) { 541105513Sphk total_sectors = strtoul(p, &q, 0); 542105513Sphk if (!*p || *q) 543105513Sphk errx(1, "total_sectors not a proper number"); 544105513Sphk if (last_sector == 0) 545105513Sphk last_sector = first_sector + total_sectors - 1; 546105513Sphk } 547105513Sphk 548105513Sphk if (l_opt == NULL && first_sector != 0) 549105513Sphk errx(1, "No -L new-lockfile argument and first_sector != 0"); 550105513Sphk else if (l_opt == NULL) { 551105513Sphk first_sector++; 552105513Sphk total_sectors--; 553105513Sphk gl->flags |= 1; 554105513Sphk } 555105513Sphk 556105513Sphk if (total_sectors != (last_sector - first_sector) + 1) 557105513Sphk errx(1, "total_sectors disagree with first_sector and last_sector"); 558105513Sphk if (total_sectors == 0) 559105513Sphk errx(1, "missing last_sector or total_sectors"); 560105513Sphk 561105513Sphk gl->sectorN = (last_sector + 1) * gl->sectorsize; 562105513Sphk 563105513Sphk /* Find a random keyoffset */ 564105513Sphk random_bits(&o, sizeof o); 565105513Sphk o %= (gl->sectorN - gl->sector0); 566105513Sphk o &= ~(gl->sectorsize - 1); 567105513Sphk gl->keyoffset = o; 568105513Sphk 569105513Sphk /* <number_of_keys> */ 570105513Sphk p = property_find(params, "number_of_keys"); 571105513Sphk if (p == NULL) 572105513Sphk errx(1, "Missing number_of_keys property"); 573105513Sphk nkeys = strtoul(p, &q, 0); 574105513Sphk if (!*p || *q) 575105513Sphk errx(1, "number_of_keys not a proper number"); 576105513Sphk if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 577105513Sphk errx(1, "number_of_keys out of range"); 578105513Sphk for (u = 0; u < nkeys; u++) { 579105513Sphk for(;;) { 580105513Sphk do { 581105513Sphk random_bits(&o, sizeof o); 582105513Sphk o %= gl->sectorN; 583105513Sphk o &= ~(gl->sectorsize - 1); 584105513Sphk } while(o < gl->sector0); 585105513Sphk for (u2 = 0; u2 < u; u2++) 586105513Sphk if (o == gl->lsector[u2]) 587105513Sphk break; 588105513Sphk if (u2 < u) 589105513Sphk continue; 590105513Sphk break; 591105513Sphk } 592105513Sphk gl->lsector[u] = o; 593105513Sphk } 594105513Sphk for (; u < G_BDE_MAXKEYS; u++) { 595105513Sphk do 596105513Sphk random_bits(&o, sizeof o); 597105513Sphk while (o < gl->sectorN); 598105513Sphk gl->lsector[u] = o; 599105513Sphk } 600105513Sphk 601105513Sphk /* Flush sector zero if we use it for lockfile data */ 602105513Sphk if (gl->flags & 1) { 603105513Sphk off2 = lseek(dfd, 0, SEEK_SET); 604105513Sphk if (off2 != 0) 605105513Sphk err(1, "lseek(2) to sector 0"); 606105513Sphk random_bits(buf, sector_size); 607105513Sphk i = write(dfd, buf, sector_size); 608105513Sphk if (i != (int)sector_size) 609105513Sphk err(1, "write sector 0"); 610105513Sphk } 611105513Sphk 612105513Sphk /* <random_flush> */ 613105513Sphk p = property_find(params, "random_flush"); 614105513Sphk if (p != NULL) { 615105513Sphk off = first_sector * sector_size; 616105513Sphk off2 = lseek(dfd, off, SEEK_SET); 617105513Sphk if (off2 != off) 618105513Sphk err(1, "lseek(2) to first_sector"); 619105513Sphk off2 = last_sector * sector_size; 620105513Sphk while (off <= off2) { 621105513Sphk random_bits(buf, sector_size); 622105513Sphk i = write(dfd, buf, sector_size); 623105513Sphk if (i != (int)sector_size) 624105513Sphk err(1, "write to $device_name"); 625105513Sphk off += sector_size; 626105513Sphk } 627105513Sphk } 628105513Sphk 629106227Sphk random_bits(gl->mkey, sizeof gl->mkey); 630106227Sphk random_bits(gl->salt, sizeof gl->salt); 631105513Sphk 632105513Sphk return; 633105513Sphk} 634105513Sphk 635105513Sphkstatic enum action { 636105513Sphk ACT_HUH, 637105541Sphk ACT_ATTACH, ACT_DETACH, 638105513Sphk ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 639105513Sphk} action; 640105513Sphk 641105513Sphkint 642105513Sphkmain(int argc, char **argv) 643105513Sphk{ 644105513Sphk const char *opts; 645105513Sphk const char *l_opt, *L_opt; 646105513Sphk const char *p_opt, *P_opt; 647105513Sphk const char *f_opt; 648107455Sphk char *dest; 649107455Sphk int i_opt, n_opt, ch, dfd, doopen; 650107455Sphk u_int nkey; 651105513Sphk int i; 652107455Sphk char *q, buf[BUFSIZ]; 653105513Sphk struct g_bde_key *gl; 654105513Sphk struct g_bde_softc sc; 655105513Sphk 656105513Sphk if (argc < 3) 657105513Sphk usage("Too few arguments\n"); 658105513Sphk 659105513Sphk doopen = 0; 660105513Sphk if (!strcmp(argv[1], "attach")) { 661105513Sphk action = ACT_ATTACH; 662105513Sphk opts = "l:p:"; 663105541Sphk } else if (!strcmp(argv[1], "detach")) { 664105541Sphk action = ACT_DETACH; 665105513Sphk opts = ""; 666105513Sphk } else if (!strcmp(argv[1], "init")) { 667105513Sphk action = ACT_INIT; 668105513Sphk doopen = 1; 669105513Sphk opts = "f:iL:P:"; 670105513Sphk } else if (!strcmp(argv[1], "setkey")) { 671105513Sphk action = ACT_SETKEY; 672105513Sphk doopen = 1; 673105513Sphk opts = "n:l:L:p:P:"; 674105513Sphk } else if (!strcmp(argv[1], "destroy")) { 675105513Sphk action = ACT_DESTROY; 676105513Sphk doopen = 1; 677105513Sphk opts = "l:p:"; 678105513Sphk } else if (!strcmp(argv[1], "nuke")) { 679105513Sphk action = ACT_NUKE; 680105513Sphk doopen = 1; 681105513Sphk opts = "l:p:n:"; 682105513Sphk } else { 683105513Sphk usage("Unknown sub command\n"); 684105513Sphk } 685105513Sphk argc--; 686105513Sphk argv++; 687105513Sphk 688107455Sphk dest = strdup(argv[1]); 689105513Sphk argc--; 690105513Sphk argv++; 691105513Sphk 692105513Sphk p_opt = NULL; 693105513Sphk P_opt = NULL; 694105513Sphk l_opt = NULL; 695105513Sphk L_opt = NULL; 696105513Sphk f_opt = NULL; 697105513Sphk n_opt = 0; 698105513Sphk i_opt = 0; 699105513Sphk 700105513Sphk while((ch = getopt(argc, argv, opts)) != -1) 701105513Sphk switch (ch) { 702105513Sphk case 'f': 703105513Sphk f_opt = optarg; 704105513Sphk break; 705105513Sphk case 'i': 706105513Sphk i_opt = !i_opt; 707105513Sphk case 'l': 708105513Sphk l_opt = optarg; 709105513Sphk break; 710105513Sphk case 'L': 711105513Sphk L_opt = optarg; 712105513Sphk break; 713105513Sphk case 'p': 714105513Sphk p_opt = optarg; 715105513Sphk break; 716105513Sphk case 'P': 717105513Sphk P_opt = optarg; 718105513Sphk break; 719105513Sphk case 'n': 720105513Sphk n_opt = strtoul(optarg, &q, 0); 721105513Sphk if (!*optarg || *q) 722105513Sphk usage("-n argument not numeric\n"); 723105513Sphk if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 724105513Sphk usage("-n argument out of range\n"); 725105513Sphk break; 726105513Sphk default: 727105513Sphk usage("Invalid option\n"); 728105513Sphk } 729105513Sphk 730105513Sphk if (doopen) { 731105513Sphk dfd = open(dest, O_RDWR | O_CREAT, 0644); 732107455Sphk if (dfd < 0) { 733107455Sphk sprintf(buf, "%s%s", _PATH_DEV, dest); 734107455Sphk dfd = open(buf, O_RDWR | O_CREAT, 0644); 735107455Sphk } 736105513Sphk if (dfd < 0) 737105513Sphk err(1, dest); 738107455Sphk } else { 739107455Sphk if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 740107455Sphk strcpy(dest, dest + strlen(_PATH_DEV)); 741107455Sphk if (strchr(dest, '/')) 742107455Sphk usage("\"dest\" argument must be geom-name\n"); 743105513Sphk } 744105513Sphk 745105513Sphk memset(&sc, 0, sizeof sc); 746105513Sphk sc.consumer = (struct g_consumer *)&dfd; 747105513Sphk gl = &sc.key; 748105513Sphk switch(action) { 749105513Sphk case ACT_ATTACH: 750105513Sphk setup_passphrase(&sc, 0, p_opt); 751105513Sphk cmd_attach(&sc, dest, l_opt); 752105513Sphk break; 753105541Sphk case ACT_DETACH: 754105541Sphk cmd_detach(dest); 755105513Sphk break; 756105513Sphk case ACT_INIT: 757105513Sphk cmd_init(gl, dfd, f_opt, i_opt, L_opt); 758105513Sphk setup_passphrase(&sc, 1, P_opt); 759105513Sphk cmd_write(gl, &sc, dfd, 0, L_opt); 760105513Sphk break; 761105513Sphk case ACT_SETKEY: 762105513Sphk setup_passphrase(&sc, 0, p_opt); 763105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 764105513Sphk if (n_opt == 0) 765105513Sphk n_opt = nkey + 1; 766105513Sphk setup_passphrase(&sc, 1, P_opt); 767105513Sphk cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 768105513Sphk break; 769105513Sphk case ACT_DESTROY: 770105513Sphk setup_passphrase(&sc, 0, p_opt); 771105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 772105513Sphk cmd_destroy(gl, nkey); 773105513Sphk reset_passphrase(&sc); 774105513Sphk cmd_write(gl, &sc, dfd, nkey, l_opt); 775105513Sphk break; 776105513Sphk case ACT_NUKE: 777105513Sphk setup_passphrase(&sc, 0, p_opt); 778105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 779105513Sphk if (n_opt == 0) 780105513Sphk n_opt = nkey + 1; 781105513Sphk if (n_opt == -1) { 782105513Sphk for(i = 0; i < G_BDE_MAXKEYS; i++) 783105513Sphk cmd_nuke(gl, dfd, i); 784105513Sphk } else { 785105513Sphk cmd_nuke(gl, dfd, n_opt - 1); 786105513Sphk } 787105513Sphk break; 788105513Sphk default: 789105513Sphk usage("Internal error\n"); 790105513Sphk } 791105513Sphk 792105513Sphk return(0); 793105513Sphk} 794