gbde.c revision 111298
1249423Sdim/*- 2193323Sed * Copyright (c) 2002 Poul-Henning Kamp 3353358Sdim * Copyright (c) 2002 Networks Associates Technology, Inc. 4353358Sdim * All rights reserved. 5353358Sdim * 6193323Sed * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7193323Sed * and NAI Labs, the Security Research Division of Network Associates, Inc. 8327952Sdim * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9296417Sdim * DARPA CHATS research program. 10296417Sdim * 11296417Sdim * Redistribution and use in source and binary forms, with or without 12327952Sdim * modification, are permitted provided that the following conditions 13193323Sed * are met: 14193323Sed * 1. Redistributions of source code must retain the above copyright 15309124Sdim * notice, this list of conditions and the following disclaimer. 16234353Sdim * 2. Redistributions in binary form must reproduce the above copyright 17327952Sdim * notice, this list of conditions and the following disclaimer in the 18243830Sdim * documentation and/or other materials provided with the distribution. 19327952Sdim * 20327952Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22249423Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23296417Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24296417Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25327952Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26249423Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29327952Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30353358Sdim * SUCH DAMAGE. 31327952Sdim * 32296417Sdim * $FreeBSD: head/sbin/gbde/gbde.c 111298 2003-02-23 07:37:47Z tjr $ 33327952Sdim */ 34327952Sdim 35327952Sdim#include <sys/types.h> 36327952Sdim#include <sys/queue.h> 37327952Sdim#include <sys/mutex.h> 38327952Sdim#include <md5.h> 39327952Sdim#include <readpassphrase.h> 40276479Sdim#include <string.h> 41327952Sdim#include <stdint.h> 42327952Sdim#include <unistd.h> 43327952Sdim#include <fcntl.h> 44344779Sdim#include <paths.h> 45327952Sdim#include <strings.h> 46327952Sdim#include <stdlib.h> 47327952Sdim#include <err.h> 48327952Sdim#include <stdio.h> 49327952Sdim#include <libutil.h> 50327952Sdim#include <sys/errno.h> 51360784Sdim#include <sys/disk.h> 52327952Sdim#include <sys/stat.h> 53327952Sdim#include <crypto/rijndael/rijndael.h> 54327952Sdim#include <crypto/sha2/sha2.h> 55327952Sdim 56296417Sdim#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0) 57327952Sdim 58296417Sdim#include <geom/geom.h> 59321369Sdim#include <geom/bde/g_bde.h> 60327952Sdim 61327952Sdimextern const char template[]; 62327952Sdim 63327952Sdim 64327952Sdim#if 0 65193323Sedstatic void 66193323Sedg_hexdump(void *ptr, int length) 67276479Sdim{ 68276479Sdim int i, j, k; 69193323Sed unsigned char *cp; 70193323Sed 71344779Sdim cp = ptr; 72193323Sed for (i = 0; i < length; i+= 16) { 73314564Sdim printf("%04x ", i); 74261991Sdim for (j = 0; j < 16; j++) { 75261991Sdim k = i + j; 76193323Sed if (k < length) 77296417Sdim printf(" %02x", cp[k]); 78296417Sdim else 79341825Sdim printf(" "); 80353358Sdim } 81193323Sed printf(" |"); 82321369Sdim for (j = 0; j < 16; j++) { 83360784Sdim k = i + j; 84321369Sdim if (k >= length) 85321369Sdim printf(" "); 86321369Sdim else if (cp[k] >= ' ' && cp[k] <= '~') 87341825Sdim printf("%c", cp[k]); 88341825Sdim else 89341825Sdim printf("."); 90341825Sdim } 91353358Sdim printf("|\n"); 92353358Sdim } 93353358Sdim} 94353358Sdim#endif 95193323Sed 96193323Sedstatic void __dead2 97327952Sdimusage(const char *reason) 98327952Sdim{ 99327952Sdim const char *p; 100327952Sdim 101321369Sdim p = getprogname(); 102321369Sdim fprintf(stderr, "Usage error: %s", reason); 103321369Sdim fprintf(stderr, "Usage:\n"); 104321369Sdim fprintf(stderr, "\t%s attach dest [-l lockfile]\n", p); 105321369Sdim fprintf(stderr, "\t%s detach dest\n", p); 106321369Sdim fprintf(stderr, "\t%s init /dev/dest [-i] [-f filename] [-L lockfile]\n", p); 107321369Sdim fprintf(stderr, "\t%s setkey dest [-n key] [-l lockfile] [-L lockfile]\n", p); 108321369Sdim fprintf(stderr, "\t%s destroy dest [-n key] [-l lockfile] [-L lockfile]\n", p); 109321369Sdim exit (1); 110321369Sdim} 111296417Sdim 112296417Sdimvoid * 113296417Sdimg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 114296417Sdim{ 115296417Sdim void *p; 116249423Sdim int fd, i; 117321369Sdim off_t o2; 118296417Sdim 119296417Sdim p = malloc(length); 120249423Sdim if (p == NULL) 121344779Sdim err(1, "malloc"); 122344779Sdim fd = *(int *)cp; 123344779Sdim o2 = lseek(fd, offset, SEEK_SET); 124344779Sdim if (o2 != offset) 125296417Sdim err(1, "lseek"); 126296417Sdim i = read(fd, p, length); 127249423Sdim if (i != length) 128296417Sdim err(1, "read"); 129296417Sdim if (error != NULL) 130344779Sdim error = 0; 131296417Sdim return (p); 132296417Sdim} 133261991Sdim 134296417Sdimstatic void 135296417Sdimrandom_bits(void *p, u_int len) 136344779Sdim{ 137309124Sdim static int fdr = -1; 138309124Sdim int i; 139309124Sdim 140309124Sdim if (fdr < 0) { 141344779Sdim fdr = open("/dev/urandom", O_RDONLY); 142344779Sdim if (fdr < 0) 143296417Sdim err(1, "/dev/urandom"); 144344779Sdim } 145327952Sdim 146249423Sdim i = read(fdr, p, len); 147296417Sdim if (i != (int)len) 148327952Sdim err(1, "read from /dev/urandom"); 149296417Sdim} 150249423Sdim 151296417Sdim/* XXX: not nice */ 152344779Sdimstatic u_char sha2[SHA512_DIGEST_LENGTH]; 153327952Sdim 154344779Sdimstatic void 155296417Sdimreset_passphrase(struct g_bde_softc *sc) 156327952Sdim{ 157296417Sdim 158296417Sdim memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH); 159296417Sdim} 160249423Sdim 161296417Sdimstatic void 162296417Sdimsetup_passphrase(struct g_bde_softc *sc, int sure, const char *input) 163344779Sdim{ 164296417Sdim char buf1[BUFSIZ], buf2[BUFSIZ], *p; 165296417Sdim 166296417Sdim if (input != NULL) { 167296417Sdim g_bde_hash_pass(sc, input, strlen(input)); 168193323Sed memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 169296417Sdim return; 170296417Sdim } 171344779Sdim for (;;) { 172193323Sed p = readpassphrase( 173296417Sdim sure ? "Enter new passphrase:" : "Enter passphrase: ", 174296417Sdim buf1, sizeof buf1, 175296417Sdim RPP_ECHO_OFF | RPP_REQUIRE_TTY); 176296417Sdim if (p == NULL) 177193323Sed err(1, "readpassphrase"); 178327952Sdim 179344779Sdim if (sure) { 180344779Sdim p = readpassphrase("Reenter new passphrase: ", 181327952Sdim buf2, sizeof buf2, 182296417Sdim RPP_ECHO_OFF | RPP_REQUIRE_TTY); 183296417Sdim if (p == NULL) 184296417Sdim err(1, "readpassphrase"); 185296417Sdim 186296417Sdim if (strcmp(buf1, buf2)) { 187296417Sdim printf("They didn't match.\n"); 188296417Sdim continue; 189296417Sdim } 190296417Sdim } 191296417Sdim if (strlen(buf1) < 3) { 192296417Sdim printf("Too short passphrase.\n"); 193296417Sdim continue; 194296417Sdim } 195296417Sdim break; 196296417Sdim } 197296417Sdim g_bde_hash_pass(sc, buf1, strlen(buf1)); 198296417Sdim memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 199296417Sdim} 200296417Sdim 201296417Sdimstatic void 202296417Sdimencrypt_sector(void *d, int len, int klen, void *key) 203296417Sdim{ 204296417Sdim keyInstance ki; 205296417Sdim cipherInstance ci; 206193323Sed int error; 207296417Sdim 208296417Sdim error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 209344779Sdim if (error <= 0) 210344779Sdim errx(1, "rijndael_cipherInit=%d", error); 211344779Sdim error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key); 212193323Sed if (error <= 0) 213296417Sdim errx(1, "rijndael_makeKeY=%d", error); 214296417Sdim error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 215296417Sdim if (error <= 0) 216193323Sed errx(1, "rijndael_blockEncrypt=%d", error); 217344779Sdim} 218344779Sdim 219344779Sdimstatic void 220344779Sdimcmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 221344779Sdim{ 222344779Sdim int gfd, i, ffd; 223344779Sdim struct geomconfiggeom gcg; 224296417Sdim u_char buf[256 + 16]; 225296417Sdim 226193323Sed gfd = open("/dev/geom.ctl", O_RDWR); 227321369Sdim if (gfd < 0) 228321369Sdim err(1, "/dev/geom.ctl"); 229321369Sdim memset(&gcg, 0, sizeof gcg); 230321369Sdim gcg.class.u.name = "BDE"; 231321369Sdim gcg.class.len = strlen(gcg.class.u.name); 232296417Sdim gcg.provider.u.name = dest; 233296417Sdim gcg.provider.len = strlen(gcg.provider.u.name); 234321369Sdim gcg.flag = GCFG_CREATE; 235193323Sed gcg.len = sizeof buf; 236193323Sed gcg.ptr = buf; 237193323Sed 238344779Sdim if (lfile != NULL) { 239296417Sdim ffd = open(lfile, O_RDONLY, 0); 240296417Sdim if (ffd < 0) 241296417Sdim err(1, "%s", lfile); 242193323Sed read(ffd, buf + sizeof(sc->sha2), 16); 243321369Sdim close(ffd); 244321369Sdim } else { 245321369Sdim memset(buf + sizeof(sc->sha2), 0, 16); 246321369Sdim } 247321369Sdim memcpy(buf, sc->sha2, sizeof(sc->sha2)); 248296417Sdim 249193323Sed i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 250296417Sdim if (i != 0) 251193323Sed err(1, "ioctl(GEOMCONFIGGEOM)"); 252296417Sdim exit (0); 253344779Sdim} 254344779Sdim 255344779Sdimstatic void 256296417Sdimcmd_detach(const char *dest) 257296417Sdim{ 258296417Sdim int i, gfd; 259193323Sed struct geomconfiggeom gcg; 260193323Sed 261193323Sed gfd = open("/dev/geom.ctl", O_RDWR); 262353358Sdim if (gfd < 0) 263353358Sdim err(1, "/dev/geom.ctl"); 264353358Sdim memset(&gcg, 0, sizeof gcg); 265353358Sdim gcg.class.u.name = "BDE"; 266353358Sdim gcg.class.len = strlen(gcg.class.u.name); 267193323Sed gcg.provider.u.name = dest; 268193323Sed gcg.provider.len = strlen(gcg.provider.u.name); 269193323Sed gcg.flag = GCFG_DISMANTLE; 270344779Sdim 271296417Sdim i = ioctl(gfd, GEOMCONFIGGEOM, &gcg); 272193323Sed if (i != 0) 273193323Sed err(1, "ioctl(GEOMCONFIGGEOM)"); 274193323Sed exit (0); 275193323Sed} 276193323Sed 277193323Sedstatic void 278193323Sedcmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey) 279193323Sed{ 280344779Sdim int error; 281344779Sdim int ffd; 282344779Sdim u_char keyloc[16]; 283193323Sed u_int sectorsize; 284193323Sed off_t mediasize; 285193323Sed struct stat st; 286321369Sdim 287321369Sdim error = ioctl(dfd, DIOCGSECTORSIZE, §orsize); 288344779Sdim if (error) 289193323Sed sectorsize = 512; 290344779Sdim error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize); 291344779Sdim if (error) { 292344779Sdim error = fstat(dfd, &st); 293344779Sdim if (error == 0 && S_ISREG(st.st_mode)) 294344779Sdim mediasize = st.st_size; 295344779Sdim else 296344779Sdim error = ENOENT; 297193323Sed } 298344779Sdim if (error) 299344779Sdim mediasize = (off_t)-1; 300344779Sdim if (l_opt != NULL) { 301344779Sdim ffd = open(l_opt, O_RDONLY, 0); 302193323Sed if (ffd < 0) 303344779Sdim err(1, "%s", l_opt); 304344779Sdim read(ffd, keyloc, sizeof keyloc); 305344779Sdim close(ffd); 306193323Sed } else { 307193323Sed memset(keyloc, 0, sizeof keyloc); 308193323Sed } 309193323Sed 310193323Sed error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize, 311193323Sed sectorsize, nkey); 312193323Sed if (error == ENOENT) 313193323Sed errx(1, "Lock was destroyed."); 314234353Sdim if (error == ESRCH) 315327952Sdim errx(1, "Lock was nuked."); 316296417Sdim if (error == ENOTDIR) 317296417Sdim errx(1, "Lock not found"); 318296417Sdim if (error != 0) 319296417Sdim errx(1, "Error %d decrypting lock", error); 320296417Sdim if (nkey) 321296417Sdim printf("Opened with key %u\n", *nkey); 322296417Sdim return; 323234353Sdim} 324296417Sdim 325296417Sdimstatic void 326296417Sdimcmd_nuke(struct g_bde_key *gl, int dfd , int key) 327327952Sdim{ 328234353Sdim int i; 329296417Sdim u_char *sbuf; 330234353Sdim off_t offset, offset2; 331296417Sdim 332296417Sdim sbuf = malloc(gl->sectorsize); 333296417Sdim memset(sbuf, 0, gl->sectorsize); 334296417Sdim offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 335296417Sdim offset2 = lseek(dfd, offset, SEEK_SET); 336296417Sdim if (offset2 != offset) 337296417Sdim err(1, "lseek"); 338234353Sdim i = write(dfd, sbuf, gl->sectorsize); 339296417Sdim if (i != (int)gl->sectorsize) 340296417Sdim err(1, "write"); 341234353Sdim printf("Nuked key %d\n", key); 342327952Sdim} 343234353Sdim 344296417Sdimstatic void 345296417Sdimcmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 346296417Sdim{ 347234353Sdim int i, ffd; 348296417Sdim uint64_t off[2]; 349296417Sdim u_char keyloc[16]; 350296417Sdim u_char *sbuf, *q; 351296417Sdim off_t offset, offset2; 352296417Sdim 353296417Sdim sbuf = malloc(gl->sectorsize); 354296417Sdim /* 355234353Sdim * Find the byte-offset in the lock sector where we will put the lock 356296417Sdim * data structure. We can put it any random place as long as the 357296417Sdim * structure fits. 358296417Sdim */ 359296417Sdim for(;;) { 360327952Sdim random_bits(off, sizeof off); 361234353Sdim off[0] &= (gl->sectorsize - 1); 362296417Sdim if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 363234353Sdim continue; 364296417Sdim break; 365296417Sdim } 366296417Sdim 367296417Sdim /* Add the sector offset in bytes */ 368296417Sdim off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 369296417Sdim gl->lsector[key] = off[0]; 370234353Sdim 371296417Sdim i = g_bde_keyloc_encrypt(sc, off, keyloc); 372309124Sdim if (i) 373296417Sdim errx(1, "g_bde_keyloc_encrypt()"); 374296417Sdim if (l_opt != NULL) { 375296417Sdim ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 376234353Sdim if (ffd < 0) 377296417Sdim err(1, "%s", l_opt); 378296417Sdim write(ffd, keyloc, sizeof keyloc); 379296417Sdim close(ffd); 380296417Sdim } else if (gl->flags & 1) { 381296417Sdim offset2 = lseek(dfd, 0, SEEK_SET); 382296417Sdim if (offset2 != 0) 383296417Sdim err(1, "lseek"); 384296417Sdim i = read(dfd, sbuf, gl->sectorsize); 385296417Sdim if (i != (int)gl->sectorsize) 386296417Sdim err(1, "read"); 387296417Sdim memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 388296417Sdim offset2 = lseek(dfd, 0, SEEK_SET); 389296417Sdim if (offset2 != 0) 390296417Sdim err(1, "lseek"); 391296417Sdim i = write(dfd, sbuf, gl->sectorsize); 392296417Sdim if (i != (int)gl->sectorsize) 393296417Sdim err(1, "write"); 394296417Sdim } else { 395296417Sdim errx(1, "No -L option and no space in sector 0 for lockfile"); 396296417Sdim } 397234353Sdim 398234353Sdim /* Allocate a sectorbuffer and fill it with random junk */ 399296417Sdim if (sbuf == NULL) 400296417Sdim err(1, "malloc"); 401296417Sdim random_bits(sbuf, gl->sectorsize); 402296417Sdim 403296417Sdim /* Fill random bits in the spare field */ 404234353Sdim random_bits(gl->spare, sizeof(gl->spare)); 405296417Sdim 406296417Sdim /* Encode the structure where we want it */ 407296417Sdim q = sbuf + (off[0] % gl->sectorsize); 408296417Sdim i = g_bde_encode_lock(sc, gl, q); 409327952Sdim if (i < 0) 410327952Sdim errx(1, "programming error encoding lock"); 411296417Sdim 412327952Sdim encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); 413327952Sdim offset = gl->lsector[key] & ~(gl->sectorsize - 1); 414327952Sdim offset2 = lseek(dfd, offset, SEEK_SET); 415296417Sdim if (offset2 != offset) 416296417Sdim err(1, "lseek"); 417234353Sdim i = write(dfd, sbuf, gl->sectorsize); 418327952Sdim if (i != (int)gl->sectorsize) 419327952Sdim err(1, "write"); 420234353Sdim printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 421327952Sdim#if 0 422296417Sdim printf("s0 = %jd\n", (intmax_t)gl->sector0); 423327952Sdim printf("sN = %jd\n", (intmax_t)gl->sectorN); 424327952Sdim printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]); 425234353Sdim printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]); 426314564Sdim printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]); 427314564Sdim printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]); 428314564Sdim printf("k = %jd\n", (intmax_t)gl->keyoffset); 429296417Sdim printf("ss = %jd\n", (intmax_t)gl->sectorsize); 430327952Sdim#endif 431296417Sdim} 432296417Sdim 433314564Sdimstatic void 434327952Sdimcmd_destroy(struct g_bde_key *gl, int nkey) 435296417Sdim{ 436296417Sdim int i; 437296417Sdim 438327952Sdim bzero(&gl->sector0, sizeof gl->sector0); 439296417Sdim bzero(&gl->sectorN, sizeof gl->sectorN); 440296417Sdim bzero(&gl->keyoffset, sizeof gl->keyoffset); 441234353Sdim bzero(&gl->flags, sizeof gl->flags); 442327952Sdim bzero(gl->mkey, sizeof gl->mkey); 443327952Sdim for (i = 0; i < G_BDE_MAXKEYS; i++) 444296417Sdim if (i != nkey) 445261991Sdim gl->lsector[i] = ~0; 446261991Sdim} 447296417Sdim 448296417Sdimstatic int 449341825Sdimsorthelp(const void *a, const void *b) 450296417Sdim{ 451276479Sdim const off_t *oa, *ob; 452276479Sdim 453276479Sdim oa = a; 454276479Sdim ob = b; 455261991Sdim return (*oa - *ob); 456261991Sdim} 457261991Sdim 458276479Sdimstatic void 459276479Sdimcmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 460276479Sdim{ 461261991Sdim int i; 462261991Sdim u_char *buf; 463261991Sdim unsigned sector_size; 464261991Sdim uint64_t first_sector; 465261991Sdim uint64_t last_sector; 466261991Sdim uint64_t total_sectors; 467261991Sdim off_t off, off2; 468261991Sdim unsigned nkeys; 469261991Sdim const char *p; 470261991Sdim char *q, cbuf[BUFSIZ]; 471261991Sdim unsigned u, u2; 472276479Sdim uint64_t o; 473261991Sdim properties params; 474276479Sdim 475280031Sdim bzero(gl, sizeof *gl); 476276479Sdim if (f_opt != NULL) { 477261991Sdim i = open(f_opt, O_RDONLY); 478261991Sdim if (i < 0) 479261991Sdim err(1, "%s", f_opt); 480261991Sdim params = properties_read(i); 481276479Sdim close (i); 482276479Sdim } else { 483276479Sdim /* XXX: Polish */ 484276479Sdim q = strdup("/tmp/temp.XXXXXXXXXX"); 485276479Sdim i = mkstemp(q); 486276479Sdim if (i < 0) 487276479Sdim err(1, "%s", q); 488276479Sdim write(i, template, strlen(template)); 489280031Sdim close (i); 490276479Sdim if (i_opt) { 491276479Sdim p = getenv("EDITOR"); 492276479Sdim if (p == NULL) 493261991Sdim p = "vi"; 494276479Sdim if (snprintf(cbuf, sizeof(cbuf), "%s %s\n", p, q) >= 495276479Sdim (ssize_t)sizeof(cbuf)) 496261991Sdim errx(1, "EDITOR is too long"); 497276479Sdim system(cbuf); 498261991Sdim } 499261991Sdim i = open(q, O_RDONLY); 500261991Sdim if (i < 0) 501261991Sdim err(1, "%s", f_opt); 502261991Sdim params = properties_read(i); 503276479Sdim close (i); 504261991Sdim unlink(q); 505261991Sdim } 506261991Sdim 507261991Sdim /* <sector_size> */ 508261991Sdim p = property_find(params, "sector_size"); 509296417Sdim i = ioctl(dfd, DIOCGSECTORSIZE, &u); 510296417Sdim if (p != NULL) { 511296417Sdim sector_size = strtoul(p, &q, 0); 512296417Sdim if (!*p || *q) 513296417Sdim errx(1, "sector_size not a proper number"); 514296417Sdim } else if (i == 0) { 515296417Sdim sector_size = u; 516296417Sdim } else { 517296417Sdim errx(1, "Missing sector_size property"); 518296417Sdim } 519296417Sdim if (sector_size & (sector_size - 1)) 520296417Sdim errx(1, "sector_size not a power of 2"); 521296417Sdim if (sector_size < 512) 522296417Sdim errx(1, "sector_size is smaller than 512"); 523296417Sdim buf = malloc(sector_size); 524296417Sdim if (buf == NULL) 525296417Sdim err(1, "Failed to malloc sector buffer"); 526296417Sdim gl->sectorsize = sector_size; 527261991Sdim 528296417Sdim i = ioctl(dfd, DIOCGMEDIASIZE, &off); 529296417Sdim if (i == 0) { 530296417Sdim first_sector = 0; 531296417Sdim total_sectors = off / sector_size; 532296417Sdim last_sector = total_sectors - 1; 533296417Sdim } else { 534296417Sdim first_sector = 0; 535314564Sdim last_sector = 0; 536314564Sdim total_sectors = 0; 537296417Sdim } 538296417Sdim 539296417Sdim /* <first_sector> */ 540296417Sdim p = property_find(params, "first_sector"); 541296417Sdim if (p != NULL) { 542296417Sdim first_sector = strtoul(p, &q, 0); 543296417Sdim if (!*p || *q) 544296417Sdim errx(1, "first_sector not a proper number"); 545296417Sdim } 546296417Sdim 547276479Sdim /* <last_sector> */ 548261991Sdim p = property_find(params, "last_sector"); 549261991Sdim if (p != NULL) { 550261991Sdim last_sector = strtoul(p, &q, 0); 551261991Sdim if (!*p || *q) 552309124Sdim errx(1, "last_sector not a proper number"); 553309124Sdim if (last_sector <= first_sector) 554309124Sdim errx(1, "last_sector not larger than first_sector"); 555309124Sdim total_sectors = last_sector + 1; 556309124Sdim } 557261991Sdim 558261991Sdim /* <total_sectors> */ 559261991Sdim p = property_find(params, "total_sectors"); 560261991Sdim if (p != NULL) { 561261991Sdim total_sectors = strtoul(p, &q, 0); 562261991Sdim if (!*p || *q) 563261991Sdim errx(1, "total_sectors not a proper number"); 564261991Sdim if (last_sector == 0) 565261991Sdim last_sector = first_sector + total_sectors - 1; 566261991Sdim } 567261991Sdim 568261991Sdim if (l_opt == NULL && first_sector != 0) 569261991Sdim errx(1, "No -L new-lockfile argument and first_sector != 0"); 570261991Sdim else if (l_opt == NULL) { 571261991Sdim first_sector++; 572314564Sdim total_sectors--; 573314564Sdim gl->flags |= 1; 574314564Sdim } 575314564Sdim gl->sector0 = first_sector * gl->sectorsize; 576314564Sdim 577314564Sdim if (total_sectors != (last_sector - first_sector) + 1) 578314564Sdim errx(1, "total_sectors disagree with first_sector and last_sector"); 579314564Sdim if (total_sectors == 0) 580314564Sdim errx(1, "missing last_sector or total_sectors"); 581314564Sdim 582314564Sdim gl->sectorN = (last_sector + 1) * gl->sectorsize; 583314564Sdim 584314564Sdim /* Find a random keyoffset */ 585314564Sdim random_bits(&o, sizeof o); 586314564Sdim o %= (gl->sectorN - gl->sector0); 587314564Sdim o &= ~(gl->sectorsize - 1); 588327952Sdim gl->keyoffset = o; 589327952Sdim 590314564Sdim /* <number_of_keys> */ 591314564Sdim p = property_find(params, "number_of_keys"); 592314564Sdim if (p == NULL) 593314564Sdim errx(1, "Missing number_of_keys property"); 594314564Sdim nkeys = strtoul(p, &q, 0); 595314564Sdim if (!*p || *q) 596314564Sdim errx(1, "number_of_keys not a proper number"); 597314564Sdim if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 598314564Sdim errx(1, "number_of_keys out of range"); 599314564Sdim for (u = 0; u < nkeys; u++) { 600314564Sdim for(;;) { 601314564Sdim do { 602314564Sdim random_bits(&o, sizeof o); 603314564Sdim o %= gl->sectorN; 604314564Sdim o &= ~(gl->sectorsize - 1); 605314564Sdim } while(o < gl->sector0); 606314564Sdim for (u2 = 0; u2 < u; u2++) 607314564Sdim if (o == gl->lsector[u2]) 608314564Sdim break; 609314564Sdim if (u2 < u) 610314564Sdim continue; 611314564Sdim break; 612314564Sdim } 613321369Sdim gl->lsector[u] = o; 614314564Sdim } 615314564Sdim for (; u < G_BDE_MAXKEYS; u++) { 616314564Sdim do 617314564Sdim random_bits(&o, sizeof o); 618314564Sdim while (o < gl->sectorN); 619314564Sdim gl->lsector[u] = o; 620314564Sdim } 621314564Sdim qsort(gl->lsector, G_BDE_MAXKEYS, sizeof gl->lsector[0], sorthelp); 622321369Sdim 623321369Sdim /* Flush sector zero if we use it for lockfile data */ 624321369Sdim if (gl->flags & 1) { 625321369Sdim off2 = lseek(dfd, 0, SEEK_SET); 626321369Sdim if (off2 != 0) 627321369Sdim err(1, "lseek(2) to sector 0"); 628321369Sdim random_bits(buf, sector_size); 629321369Sdim i = write(dfd, buf, sector_size); 630321369Sdim if (i != (int)sector_size) 631321369Sdim err(1, "write sector 0"); 632321369Sdim } 633321369Sdim 634321369Sdim /* <random_flush> */ 635321369Sdim p = property_find(params, "random_flush"); 636321369Sdim if (p != NULL) { 637321369Sdim off = first_sector * sector_size; 638321369Sdim off2 = lseek(dfd, off, SEEK_SET); 639321369Sdim if (off2 != off) 640321369Sdim err(1, "lseek(2) to first_sector"); 641321369Sdim off2 = last_sector * sector_size; 642321369Sdim while (off <= off2) { 643321369Sdim random_bits(buf, sector_size); 644321369Sdim i = write(dfd, buf, sector_size); 645321369Sdim if (i != (int)sector_size) 646321369Sdim err(1, "write to $device_name"); 647321369Sdim off += sector_size; 648321369Sdim } 649321369Sdim } 650321369Sdim 651321369Sdim random_bits(gl->mkey, sizeof gl->mkey); 652321369Sdim random_bits(gl->salt, sizeof gl->salt); 653321369Sdim 654321369Sdim return; 655321369Sdim} 656321369Sdim 657321369Sdimstatic enum action { 658321369Sdim ACT_HUH, 659321369Sdim ACT_ATTACH, ACT_DETACH, 660321369Sdim ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 661341825Sdim} action; 662321369Sdim 663321369Sdimint 664321369Sdimmain(int argc, char **argv) 665360784Sdim{ 666360784Sdim const char *opts; 667360784Sdim const char *l_opt, *L_opt; 668360784Sdim const char *p_opt, *P_opt; 669360784Sdim const char *f_opt; 670360784Sdim char *dest; 671360784Sdim int i_opt, n_opt, ch, dfd, doopen; 672360784Sdim u_int nkey; 673360784Sdim int i; 674360784Sdim char *q, buf[BUFSIZ]; 675360784Sdim struct g_bde_key *gl; 676360784Sdim struct g_bde_softc sc; 677360784Sdim 678360784Sdim if (argc < 3) 679360784Sdim usage("Too few arguments\n"); 680360784Sdim 681360784Sdim doopen = 0; 682360784Sdim if (!strcmp(argv[1], "attach")) { 683360784Sdim action = ACT_ATTACH; 684296417Sdim opts = "l:p:"; 685296417Sdim } else if (!strcmp(argv[1], "detach")) { 686193323Sed action = ACT_DETACH; 687193323Sed opts = ""; 688234353Sdim } else if (!strcmp(argv[1], "init")) { 689234353Sdim action = ACT_INIT; 690193323Sed doopen = 1; 691193323Sed opts = "f:iL:P:"; 692296417Sdim } else if (!strcmp(argv[1], "setkey")) { 693309124Sdim action = ACT_SETKEY; 694309124Sdim doopen = 1; 695309124Sdim opts = "n:l:L:p:P:"; 696309124Sdim } else if (!strcmp(argv[1], "destroy")) { 697193323Sed action = ACT_DESTROY; 698193323Sed doopen = 1; 699321369Sdim opts = "l:p:"; 700321369Sdim } else if (!strcmp(argv[1], "nuke")) { 701234353Sdim action = ACT_NUKE; 702234353Sdim doopen = 1; 703234353Sdim opts = "l:p:n:"; 704234353Sdim } else { 705296417Sdim usage("Unknown sub command\n"); 706296417Sdim } 707234353Sdim argc--; 708321369Sdim argv++; 709234353Sdim 710234353Sdim dest = strdup(argv[1]); 711234353Sdim argc--; 712234353Sdim argv++; 713234353Sdim 714234353Sdim p_opt = NULL; 715234353Sdim P_opt = NULL; 716296417Sdim l_opt = NULL; 717296417Sdim L_opt = NULL; 718296417Sdim f_opt = NULL; 719296417Sdim n_opt = 0; 720261991Sdim i_opt = 0; 721261991Sdim 722234353Sdim while((ch = getopt(argc, argv, opts)) != -1) 723296417Sdim switch (ch) { 724234353Sdim case 'f': 725234353Sdim f_opt = optarg; 726234353Sdim break; 727321369Sdim case 'i': 728234353Sdim i_opt = !i_opt; 729234353Sdim case 'l': 730234353Sdim l_opt = optarg; 731234353Sdim break; 732234353Sdim case 'L': 733234353Sdim L_opt = optarg; 734296417Sdim break; 735309124Sdim case 'p': 736309124Sdim p_opt = optarg; 737309124Sdim break; 738261991Sdim case 'P': 739261991Sdim P_opt = optarg; 740234353Sdim break; 741234353Sdim case 'n': 742234353Sdim n_opt = strtoul(optarg, &q, 0); 743234353Sdim if (!*optarg || *q) 744261991Sdim usage("-n argument not numeric\n"); 745261991Sdim if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 746261991Sdim usage("-n argument out of range\n"); break; 747261991Sdim default: 748261991Sdim usage("Invalid option\n"); 749296417Sdim } 750296417Sdim 751296417Sdim if (doopen) { 752360784Sdim dfd = open(dest, O_RDWR | O_CREAT, 0644); 753360784Sdim if (dfd < 0) { 754261991Sdim if (snprintf(buf, sizeof(buf), "%s%s", 755261991Sdim _PATH_DEV, dest) >= (ssize_t)sizeof(buf)) 756234353Sdim errno = ENAMETOOLONG; 757234353Sdim else 758234353Sdim dfd = open(buf, O_RDWR | O_CREAT, 0644); 759234353Sdim } 760234353Sdim if (dfd < 0) 761234353Sdim err(1, "%s", dest); 762234353Sdim } else { 763234353Sdim if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 764234353Sdim strcpy(dest, dest + strlen(_PATH_DEV)); 765296417Sdim if (strchr(dest, '/')) 766276479Sdim usage("\"dest\" argument must be geom-name\n"); 767234353Sdim } 768296417Sdim 769296417Sdim memset(&sc, 0, sizeof sc); 770234353Sdim sc.consumer = (void *)&dfd; 771234353Sdim gl = &sc.key; 772234353Sdim switch(action) { 773234353Sdim case ACT_ATTACH: 774261991Sdim setup_passphrase(&sc, 0, p_opt); 775321369Sdim cmd_attach(&sc, dest, l_opt); 776193323Sed break; 777193323Sed case ACT_DETACH: 778193323Sed cmd_detach(dest); 779234353Sdim break; 780234353Sdim case ACT_INIT: 781234353Sdim cmd_init(gl, dfd, f_opt, i_opt, L_opt); 782234353Sdim setup_passphrase(&sc, 1, P_opt); 783276479Sdim cmd_write(gl, &sc, dfd, 0, L_opt); 784276479Sdim break; 785234353Sdim case ACT_SETKEY: 786234353Sdim setup_passphrase(&sc, 0, p_opt); 787234353Sdim cmd_open(&sc, dfd, l_opt, &nkey); 788234353Sdim if (n_opt == 0) 789234353Sdim n_opt = nkey + 1; 790234353Sdim setup_passphrase(&sc, 1, P_opt); 791296417Sdim cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 792296417Sdim break; 793234353Sdim case ACT_DESTROY: 794296417Sdim setup_passphrase(&sc, 0, p_opt); 795234353Sdim cmd_open(&sc, dfd, l_opt, &nkey); 796234353Sdim cmd_destroy(gl, nkey); 797309124Sdim reset_passphrase(&sc); 798309124Sdim cmd_write(gl, &sc, dfd, nkey, l_opt); 799234353Sdim break; 800234353Sdim case ACT_NUKE: 801276479Sdim setup_passphrase(&sc, 0, p_opt); 802276479Sdim cmd_open(&sc, dfd, l_opt, &nkey); 803234353Sdim if (n_opt == 0) 804309124Sdim n_opt = nkey + 1; 805309124Sdim if (n_opt == -1) { 806234353Sdim for(i = 0; i < G_BDE_MAXKEYS; i++) 807234353Sdim cmd_nuke(gl, dfd, i); 808234353Sdim } else { 809234353Sdim cmd_nuke(gl, dfd, n_opt - 1); 810234353Sdim } 811234353Sdim break; 812296417Sdim default: 813296417Sdim usage("Internal error\n"); 814234353Sdim } 815234353Sdim 816234353Sdim return(0); 817321369Sdim} 818234353Sdim