gbde.c revision 112877
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 112877 2003-03-31 18:38:31Z 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> 50112877Sphk#include <libgeom.h> 51105513Sphk#include <sys/errno.h> 52105513Sphk#include <sys/disk.h> 53106407Sphk#include <sys/stat.h> 54105513Sphk#include <crypto/rijndael/rijndael.h> 55106407Sphk#include <crypto/sha2/sha2.h> 56105513Sphk 57106407Sphk#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0) 58106407Sphk 59105513Sphk#include <geom/geom.h> 60105513Sphk#include <geom/bde/g_bde.h> 61105513Sphk 62105513Sphkextern const char template[]; 63105513Sphk 64106407Sphk 65106407Sphk#if 0 66106407Sphkstatic void 67106407Sphkg_hexdump(void *ptr, int length) 68106407Sphk{ 69106407Sphk int i, j, k; 70106407Sphk unsigned char *cp; 71106407Sphk 72106407Sphk cp = ptr; 73106407Sphk for (i = 0; i < length; i+= 16) { 74106407Sphk printf("%04x ", i); 75106407Sphk for (j = 0; j < 16; j++) { 76106407Sphk k = i + j; 77106407Sphk if (k < length) 78106407Sphk printf(" %02x", cp[k]); 79106407Sphk else 80106407Sphk printf(" "); 81106407Sphk } 82106407Sphk printf(" |"); 83106407Sphk for (j = 0; j < 16; j++) { 84106407Sphk k = i + j; 85106407Sphk if (k >= length) 86106407Sphk printf(" "); 87106407Sphk else if (cp[k] >= ' ' && cp[k] <= '~') 88106407Sphk printf("%c", cp[k]); 89106407Sphk else 90106407Sphk printf("."); 91106407Sphk } 92106407Sphk printf("|\n"); 93106407Sphk } 94106407Sphk} 95106407Sphk#endif 96106407Sphk 97105513Sphkstatic void __dead2 98105513Sphkusage(const char *reason) 99105513Sphk{ 100105513Sphk const char *p; 101105513Sphk 102105513Sphk p = getprogname(); 103105513Sphk fprintf(stderr, "Usage error: %s", reason); 104105513Sphk fprintf(stderr, "Usage:\n"); 105107455Sphk fprintf(stderr, "\t%s attach dest [-l lockfile]\n", p); 106105541Sphk fprintf(stderr, "\t%s detach dest\n", p); 107107455Sphk fprintf(stderr, "\t%s init /dev/dest [-i] [-f filename] [-L lockfile]\n", p); 108107455Sphk fprintf(stderr, "\t%s setkey dest [-n key] [-l lockfile] [-L lockfile]\n", p); 109107455Sphk fprintf(stderr, "\t%s destroy dest [-n key] [-l lockfile] [-L lockfile]\n", p); 110105513Sphk exit (1); 111105513Sphk} 112105513Sphk 113105513Sphkvoid * 114105513Sphkg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 115105513Sphk{ 116105513Sphk void *p; 117105513Sphk int fd, i; 118105513Sphk off_t o2; 119105513Sphk 120105513Sphk p = malloc(length); 121105513Sphk if (p == NULL) 122105513Sphk err(1, "malloc"); 123105513Sphk fd = *(int *)cp; 124105513Sphk o2 = lseek(fd, offset, SEEK_SET); 125105513Sphk if (o2 != offset) 126105513Sphk err(1, "lseek"); 127105513Sphk i = read(fd, p, length); 128105513Sphk if (i != length) 129105513Sphk err(1, "read"); 130105513Sphk if (error != NULL) 131105513Sphk error = 0; 132105513Sphk return (p); 133105513Sphk} 134105513Sphk 135105513Sphkstatic void 136105513Sphkrandom_bits(void *p, u_int len) 137105513Sphk{ 138105513Sphk static int fdr = -1; 139105513Sphk int i; 140105513Sphk 141105513Sphk if (fdr < 0) { 142105513Sphk fdr = open("/dev/urandom", O_RDONLY); 143105513Sphk if (fdr < 0) 144105513Sphk err(1, "/dev/urandom"); 145105513Sphk } 146105513Sphk 147105513Sphk i = read(fdr, p, len); 148105513Sphk if (i != (int)len) 149105513Sphk err(1, "read from /dev/urandom"); 150105513Sphk} 151105513Sphk 152105513Sphk/* XXX: not nice */ 153106407Sphkstatic u_char sha2[SHA512_DIGEST_LENGTH]; 154105513Sphk 155105513Sphkstatic void 156105513Sphkreset_passphrase(struct g_bde_softc *sc) 157105513Sphk{ 158105513Sphk 159106407Sphk memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH); 160105513Sphk} 161105513Sphk 162105513Sphkstatic void 163105513Sphksetup_passphrase(struct g_bde_softc *sc, int sure, const char *input) 164105513Sphk{ 165105513Sphk char buf1[BUFSIZ], buf2[BUFSIZ], *p; 166105513Sphk 167105513Sphk if (input != NULL) { 168106407Sphk g_bde_hash_pass(sc, input, strlen(input)); 169106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 170105513Sphk return; 171105513Sphk } 172105513Sphk for (;;) { 173105513Sphk p = readpassphrase( 174105513Sphk sure ? "Enter new passphrase:" : "Enter passphrase: ", 175105513Sphk buf1, sizeof buf1, 176105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 177105513Sphk if (p == NULL) 178105513Sphk err(1, "readpassphrase"); 179105513Sphk 180105513Sphk if (sure) { 181105513Sphk p = readpassphrase("Reenter new passphrase: ", 182105513Sphk buf2, sizeof buf2, 183105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 184105513Sphk if (p == NULL) 185105513Sphk err(1, "readpassphrase"); 186105513Sphk 187105513Sphk if (strcmp(buf1, buf2)) { 188105513Sphk printf("They didn't match.\n"); 189105513Sphk continue; 190105513Sphk } 191105513Sphk } 192105513Sphk if (strlen(buf1) < 3) { 193105513Sphk printf("Too short passphrase.\n"); 194105513Sphk continue; 195105513Sphk } 196105513Sphk break; 197105513Sphk } 198106407Sphk g_bde_hash_pass(sc, buf1, strlen(buf1)); 199106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 200105513Sphk} 201105513Sphk 202105513Sphkstatic void 203106407Sphkencrypt_sector(void *d, int len, int klen, void *key) 204105513Sphk{ 205105513Sphk keyInstance ki; 206105513Sphk cipherInstance ci; 207105513Sphk int error; 208105513Sphk 209105513Sphk error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 210105513Sphk if (error <= 0) 211105513Sphk errx(1, "rijndael_cipherInit=%d", error); 212106407Sphk error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key); 213105513Sphk if (error <= 0) 214105513Sphk errx(1, "rijndael_makeKeY=%d", error); 215105513Sphk error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 216105513Sphk if (error <= 0) 217105513Sphk errx(1, "rijndael_blockEncrypt=%d", error); 218105513Sphk} 219105513Sphk 220105513Sphkstatic void 221105513Sphkcmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 222105513Sphk{ 223112877Sphk int ffd; 224112877Sphk u_char buf[16]; 225112877Sphk struct gctl_req *r; 226112877Sphk const char *errstr; 227105513Sphk 228112877Sphk r = gctl_get_handle(GCTL_CREATE_GEOM); 229112877Sphk gctl_ro_param(r, "class", -1, "BDE"); 230112877Sphk gctl_ro_param(r, "provider", -1, dest); 231112877Sphk gctl_ro_param(r, "pass", SHA512_DIGEST_LENGTH, sc->sha2); 232105513Sphk if (lfile != NULL) { 233105513Sphk ffd = open(lfile, O_RDONLY, 0); 234105513Sphk if (ffd < 0) 235111296Stjr err(1, "%s", lfile); 236112877Sphk read(ffd, buf, 16); 237112877Sphk gctl_ro_param(r, "key", 16, buf); 238105513Sphk close(ffd); 239105513Sphk } 240112877Sphk /* gctl_dump(r, stdout); */ 241112877Sphk errstr = gctl_issue(r); 242112877Sphk if (errstr != NULL) 243112877Sphk errx(1, "Attach to %s failed: %s\n", dest, errstr); 244105513Sphk 245105513Sphk exit (0); 246105513Sphk} 247105513Sphk 248105513Sphkstatic void 249105541Sphkcmd_detach(const char *dest) 250105513Sphk{ 251112877Sphk struct gctl_req *r; 252112877Sphk const char *errstr; 253112877Sphk char buf[BUFSIZ]; 254105513Sphk 255112877Sphk r = gctl_get_handle(GCTL_DESTROY_GEOM); 256112877Sphk gctl_ro_param(r, "class", -1, "BDE"); 257112877Sphk sprintf(buf, "%s.bde", dest); 258112877Sphk gctl_ro_param(r, "geom", -1, buf); 259112877Sphk /* gctl_dump(r, stdout); */ 260112877Sphk errstr = gctl_issue(r); 261112877Sphk if (errstr != NULL) 262112877Sphk errx(1, "Detach of %s failed: %s\n", dest, errstr); 263105513Sphk exit (0); 264105513Sphk} 265105513Sphk 266105513Sphkstatic void 267106407Sphkcmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey) 268105513Sphk{ 269105513Sphk int error; 270105513Sphk int ffd; 271105513Sphk u_char keyloc[16]; 272106407Sphk u_int sectorsize; 273106407Sphk off_t mediasize; 274106407Sphk struct stat st; 275105513Sphk 276106407Sphk error = ioctl(dfd, DIOCGSECTORSIZE, §orsize); 277106407Sphk if (error) 278106407Sphk sectorsize = 512; 279106407Sphk error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize); 280106407Sphk if (error) { 281106407Sphk error = fstat(dfd, &st); 282106407Sphk if (error == 0 && S_ISREG(st.st_mode)) 283106407Sphk mediasize = st.st_size; 284106407Sphk else 285106407Sphk error = ENOENT; 286106407Sphk } 287106407Sphk if (error) 288106407Sphk mediasize = (off_t)-1; 289105513Sphk if (l_opt != NULL) { 290105513Sphk ffd = open(l_opt, O_RDONLY, 0); 291105513Sphk if (ffd < 0) 292111296Stjr err(1, "%s", l_opt); 293105513Sphk read(ffd, keyloc, sizeof keyloc); 294105513Sphk close(ffd); 295105513Sphk } else { 296105513Sphk memset(keyloc, 0, sizeof keyloc); 297105513Sphk } 298105513Sphk 299106407Sphk error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize, 300106407Sphk sectorsize, nkey); 301105513Sphk if (error == ENOENT) 302105513Sphk errx(1, "Lock was destroyed."); 303105513Sphk if (error == ESRCH) 304105513Sphk errx(1, "Lock was nuked."); 305105513Sphk if (error == ENOTDIR) 306105513Sphk errx(1, "Lock not found"); 307105513Sphk if (error != 0) 308105513Sphk errx(1, "Error %d decrypting lock", error); 309105513Sphk if (nkey) 310105513Sphk printf("Opened with key %u\n", *nkey); 311105513Sphk return; 312105513Sphk} 313105513Sphk 314105513Sphkstatic void 315105513Sphkcmd_nuke(struct g_bde_key *gl, int dfd , int key) 316105513Sphk{ 317105513Sphk int i; 318105513Sphk u_char *sbuf; 319105513Sphk off_t offset, offset2; 320105513Sphk 321105513Sphk sbuf = malloc(gl->sectorsize); 322105513Sphk memset(sbuf, 0, gl->sectorsize); 323105513Sphk offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 324105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 325105513Sphk if (offset2 != offset) 326105513Sphk err(1, "lseek"); 327105513Sphk i = write(dfd, sbuf, gl->sectorsize); 328105513Sphk if (i != (int)gl->sectorsize) 329105513Sphk err(1, "write"); 330105513Sphk printf("Nuked key %d\n", key); 331105513Sphk} 332105513Sphk 333105513Sphkstatic void 334105513Sphkcmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 335105513Sphk{ 336105513Sphk int i, ffd; 337105513Sphk uint64_t off[2]; 338105513Sphk u_char keyloc[16]; 339105513Sphk u_char *sbuf, *q; 340105513Sphk off_t offset, offset2; 341105513Sphk 342105513Sphk sbuf = malloc(gl->sectorsize); 343105513Sphk /* 344105513Sphk * Find the byte-offset in the lock sector where we will put the lock 345105513Sphk * data structure. We can put it any random place as long as the 346105513Sphk * structure fits. 347105513Sphk */ 348105513Sphk for(;;) { 349105513Sphk random_bits(off, sizeof off); 350105513Sphk off[0] &= (gl->sectorsize - 1); 351105513Sphk if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 352105513Sphk continue; 353105513Sphk break; 354105513Sphk } 355105513Sphk 356105513Sphk /* Add the sector offset in bytes */ 357105513Sphk off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 358105513Sphk gl->lsector[key] = off[0]; 359105513Sphk 360105513Sphk i = g_bde_keyloc_encrypt(sc, off, keyloc); 361105513Sphk if (i) 362105513Sphk errx(1, "g_bde_keyloc_encrypt()"); 363105513Sphk if (l_opt != NULL) { 364105513Sphk ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 365105513Sphk if (ffd < 0) 366111296Stjr err(1, "%s", l_opt); 367105513Sphk write(ffd, keyloc, sizeof keyloc); 368105513Sphk close(ffd); 369105513Sphk } else if (gl->flags & 1) { 370105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 371105513Sphk if (offset2 != 0) 372105513Sphk err(1, "lseek"); 373105513Sphk i = read(dfd, sbuf, gl->sectorsize); 374105513Sphk if (i != (int)gl->sectorsize) 375105513Sphk err(1, "read"); 376105513Sphk memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 377105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 378105513Sphk if (offset2 != 0) 379105513Sphk err(1, "lseek"); 380105513Sphk i = write(dfd, sbuf, gl->sectorsize); 381105513Sphk if (i != (int)gl->sectorsize) 382105513Sphk err(1, "write"); 383105513Sphk } else { 384105513Sphk errx(1, "No -L option and no space in sector 0 for lockfile"); 385105513Sphk } 386105513Sphk 387105513Sphk /* Allocate a sectorbuffer and fill it with random junk */ 388105513Sphk if (sbuf == NULL) 389105513Sphk err(1, "malloc"); 390105513Sphk random_bits(sbuf, gl->sectorsize); 391105513Sphk 392105513Sphk /* Fill random bits in the spare field */ 393105513Sphk random_bits(gl->spare, sizeof(gl->spare)); 394105513Sphk 395105513Sphk /* Encode the structure where we want it */ 396105513Sphk q = sbuf + (off[0] % gl->sectorsize); 397106407Sphk i = g_bde_encode_lock(sc, gl, q); 398106407Sphk if (i < 0) 399106407Sphk errx(1, "programming error encoding lock"); 400105513Sphk 401106407Sphk encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); 402105513Sphk offset = gl->lsector[key] & ~(gl->sectorsize - 1); 403105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 404105513Sphk if (offset2 != offset) 405105513Sphk err(1, "lseek"); 406105513Sphk i = write(dfd, sbuf, gl->sectorsize); 407105513Sphk if (i != (int)gl->sectorsize) 408105513Sphk err(1, "write"); 409105513Sphk printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 410108052Sphk#if 0 411108052Sphk printf("s0 = %jd\n", (intmax_t)gl->sector0); 412108052Sphk printf("sN = %jd\n", (intmax_t)gl->sectorN); 413108052Sphk printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]); 414108052Sphk printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]); 415108052Sphk printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]); 416108052Sphk printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]); 417108052Sphk printf("k = %jd\n", (intmax_t)gl->keyoffset); 418108052Sphk printf("ss = %jd\n", (intmax_t)gl->sectorsize); 419108052Sphk#endif 420105513Sphk} 421105513Sphk 422105513Sphkstatic void 423105513Sphkcmd_destroy(struct g_bde_key *gl, int nkey) 424105513Sphk{ 425105513Sphk int i; 426105513Sphk 427105513Sphk bzero(&gl->sector0, sizeof gl->sector0); 428105513Sphk bzero(&gl->sectorN, sizeof gl->sectorN); 429105513Sphk bzero(&gl->keyoffset, sizeof gl->keyoffset); 430105513Sphk bzero(&gl->flags, sizeof gl->flags); 431106227Sphk bzero(gl->mkey, sizeof gl->mkey); 432105513Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) 433105513Sphk if (i != nkey) 434105513Sphk gl->lsector[i] = ~0; 435105513Sphk} 436105513Sphk 437108052Sphkstatic int 438108052Sphksorthelp(const void *a, const void *b) 439108052Sphk{ 440108052Sphk const off_t *oa, *ob; 441108052Sphk 442108052Sphk oa = a; 443108052Sphk ob = b; 444108052Sphk return (*oa - *ob); 445108052Sphk} 446108052Sphk 447105513Sphkstatic void 448105513Sphkcmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 449105513Sphk{ 450105513Sphk int i; 451105513Sphk u_char *buf; 452105513Sphk unsigned sector_size; 453105513Sphk uint64_t first_sector; 454105513Sphk uint64_t last_sector; 455105513Sphk uint64_t total_sectors; 456105513Sphk off_t off, off2; 457105513Sphk unsigned nkeys; 458105513Sphk const char *p; 459105513Sphk char *q, cbuf[BUFSIZ]; 460105513Sphk unsigned u, u2; 461105513Sphk uint64_t o; 462105513Sphk properties params; 463105513Sphk 464105513Sphk bzero(gl, sizeof *gl); 465105513Sphk if (f_opt != NULL) { 466105513Sphk i = open(f_opt, O_RDONLY); 467105513Sphk if (i < 0) 468111296Stjr err(1, "%s", f_opt); 469105513Sphk params = properties_read(i); 470105513Sphk close (i); 471105513Sphk } else { 472105513Sphk /* XXX: Polish */ 473105513Sphk q = strdup("/tmp/temp.XXXXXXXXXX"); 474105513Sphk i = mkstemp(q); 475105513Sphk if (i < 0) 476111296Stjr err(1, "%s", q); 477105513Sphk write(i, template, strlen(template)); 478105513Sphk close (i); 479105513Sphk if (i_opt) { 480105513Sphk p = getenv("EDITOR"); 481105513Sphk if (p == NULL) 482105513Sphk p = "vi"; 483111298Stjr if (snprintf(cbuf, sizeof(cbuf), "%s %s\n", p, q) >= 484111298Stjr (ssize_t)sizeof(cbuf)) 485111298Stjr errx(1, "EDITOR is too long"); 486105513Sphk system(cbuf); 487105513Sphk } 488105513Sphk i = open(q, O_RDONLY); 489105513Sphk if (i < 0) 490111296Stjr err(1, "%s", f_opt); 491105513Sphk params = properties_read(i); 492105513Sphk close (i); 493105513Sphk unlink(q); 494105513Sphk } 495105513Sphk 496105513Sphk /* <sector_size> */ 497105513Sphk p = property_find(params, "sector_size"); 498105513Sphk i = ioctl(dfd, DIOCGSECTORSIZE, &u); 499105513Sphk if (p != NULL) { 500105513Sphk sector_size = strtoul(p, &q, 0); 501105513Sphk if (!*p || *q) 502105513Sphk errx(1, "sector_size not a proper number"); 503108020Sphk } else if (i == 0) { 504108020Sphk sector_size = u; 505108020Sphk } else { 506108020Sphk errx(1, "Missing sector_size property"); 507105513Sphk } 508105513Sphk if (sector_size & (sector_size - 1)) 509105513Sphk errx(1, "sector_size not a power of 2"); 510105513Sphk if (sector_size < 512) 511105513Sphk errx(1, "sector_size is smaller than 512"); 512105513Sphk buf = malloc(sector_size); 513105513Sphk if (buf == NULL) 514105513Sphk err(1, "Failed to malloc sector buffer"); 515105513Sphk gl->sectorsize = sector_size; 516105513Sphk 517105513Sphk i = ioctl(dfd, DIOCGMEDIASIZE, &off); 518105513Sphk if (i == 0) { 519105513Sphk first_sector = 0; 520105513Sphk total_sectors = off / sector_size; 521105513Sphk last_sector = total_sectors - 1; 522105513Sphk } else { 523105513Sphk first_sector = 0; 524105513Sphk last_sector = 0; 525105513Sphk total_sectors = 0; 526105513Sphk } 527105513Sphk 528105513Sphk /* <first_sector> */ 529105513Sphk p = property_find(params, "first_sector"); 530105513Sphk if (p != NULL) { 531105513Sphk first_sector = strtoul(p, &q, 0); 532105513Sphk if (!*p || *q) 533105513Sphk errx(1, "first_sector not a proper number"); 534105513Sphk } 535105513Sphk 536105513Sphk /* <last_sector> */ 537105513Sphk p = property_find(params, "last_sector"); 538105513Sphk if (p != NULL) { 539105513Sphk last_sector = strtoul(p, &q, 0); 540105513Sphk if (!*p || *q) 541105513Sphk errx(1, "last_sector not a proper number"); 542105513Sphk if (last_sector <= first_sector) 543105513Sphk errx(1, "last_sector not larger than first_sector"); 544105513Sphk total_sectors = last_sector + 1; 545105513Sphk } 546105513Sphk 547105513Sphk /* <total_sectors> */ 548105513Sphk p = property_find(params, "total_sectors"); 549105513Sphk if (p != NULL) { 550105513Sphk total_sectors = strtoul(p, &q, 0); 551105513Sphk if (!*p || *q) 552105513Sphk errx(1, "total_sectors not a proper number"); 553105513Sphk if (last_sector == 0) 554105513Sphk last_sector = first_sector + total_sectors - 1; 555105513Sphk } 556105513Sphk 557105513Sphk if (l_opt == NULL && first_sector != 0) 558105513Sphk errx(1, "No -L new-lockfile argument and first_sector != 0"); 559105513Sphk else if (l_opt == NULL) { 560105513Sphk first_sector++; 561105513Sphk total_sectors--; 562105513Sphk gl->flags |= 1; 563105513Sphk } 564108060Sphk gl->sector0 = first_sector * gl->sectorsize; 565105513Sphk 566105513Sphk if (total_sectors != (last_sector - first_sector) + 1) 567105513Sphk errx(1, "total_sectors disagree with first_sector and last_sector"); 568105513Sphk if (total_sectors == 0) 569105513Sphk errx(1, "missing last_sector or total_sectors"); 570105513Sphk 571105513Sphk gl->sectorN = (last_sector + 1) * gl->sectorsize; 572105513Sphk 573105513Sphk /* Find a random keyoffset */ 574105513Sphk random_bits(&o, sizeof o); 575105513Sphk o %= (gl->sectorN - gl->sector0); 576105513Sphk o &= ~(gl->sectorsize - 1); 577105513Sphk gl->keyoffset = o; 578105513Sphk 579105513Sphk /* <number_of_keys> */ 580105513Sphk p = property_find(params, "number_of_keys"); 581105513Sphk if (p == NULL) 582105513Sphk errx(1, "Missing number_of_keys property"); 583105513Sphk nkeys = strtoul(p, &q, 0); 584105513Sphk if (!*p || *q) 585105513Sphk errx(1, "number_of_keys not a proper number"); 586105513Sphk if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 587105513Sphk errx(1, "number_of_keys out of range"); 588105513Sphk for (u = 0; u < nkeys; u++) { 589105513Sphk for(;;) { 590105513Sphk do { 591105513Sphk random_bits(&o, sizeof o); 592105513Sphk o %= gl->sectorN; 593105513Sphk o &= ~(gl->sectorsize - 1); 594105513Sphk } while(o < gl->sector0); 595105513Sphk for (u2 = 0; u2 < u; u2++) 596105513Sphk if (o == gl->lsector[u2]) 597105513Sphk break; 598105513Sphk if (u2 < u) 599105513Sphk continue; 600105513Sphk break; 601105513Sphk } 602105513Sphk gl->lsector[u] = o; 603105513Sphk } 604105513Sphk for (; u < G_BDE_MAXKEYS; u++) { 605105513Sphk do 606105513Sphk random_bits(&o, sizeof o); 607105513Sphk while (o < gl->sectorN); 608105513Sphk gl->lsector[u] = o; 609105513Sphk } 610108052Sphk qsort(gl->lsector, G_BDE_MAXKEYS, sizeof gl->lsector[0], sorthelp); 611105513Sphk 612105513Sphk /* Flush sector zero if we use it for lockfile data */ 613105513Sphk if (gl->flags & 1) { 614105513Sphk off2 = lseek(dfd, 0, SEEK_SET); 615105513Sphk if (off2 != 0) 616105513Sphk err(1, "lseek(2) to sector 0"); 617105513Sphk random_bits(buf, sector_size); 618105513Sphk i = write(dfd, buf, sector_size); 619105513Sphk if (i != (int)sector_size) 620105513Sphk err(1, "write sector 0"); 621105513Sphk } 622105513Sphk 623105513Sphk /* <random_flush> */ 624105513Sphk p = property_find(params, "random_flush"); 625105513Sphk if (p != NULL) { 626105513Sphk off = first_sector * sector_size; 627105513Sphk off2 = lseek(dfd, off, SEEK_SET); 628105513Sphk if (off2 != off) 629105513Sphk err(1, "lseek(2) to first_sector"); 630105513Sphk off2 = last_sector * sector_size; 631105513Sphk while (off <= off2) { 632105513Sphk random_bits(buf, sector_size); 633105513Sphk i = write(dfd, buf, sector_size); 634105513Sphk if (i != (int)sector_size) 635105513Sphk err(1, "write to $device_name"); 636105513Sphk off += sector_size; 637105513Sphk } 638105513Sphk } 639105513Sphk 640106227Sphk random_bits(gl->mkey, sizeof gl->mkey); 641106227Sphk random_bits(gl->salt, sizeof gl->salt); 642105513Sphk 643105513Sphk return; 644105513Sphk} 645105513Sphk 646105513Sphkstatic enum action { 647105513Sphk ACT_HUH, 648105541Sphk ACT_ATTACH, ACT_DETACH, 649105513Sphk ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 650105513Sphk} action; 651105513Sphk 652105513Sphkint 653105513Sphkmain(int argc, char **argv) 654105513Sphk{ 655105513Sphk const char *opts; 656105513Sphk const char *l_opt, *L_opt; 657105513Sphk const char *p_opt, *P_opt; 658105513Sphk const char *f_opt; 659107455Sphk char *dest; 660107455Sphk int i_opt, n_opt, ch, dfd, doopen; 661107455Sphk u_int nkey; 662105513Sphk int i; 663107455Sphk char *q, buf[BUFSIZ]; 664105513Sphk struct g_bde_key *gl; 665105513Sphk struct g_bde_softc sc; 666105513Sphk 667105513Sphk if (argc < 3) 668105513Sphk usage("Too few arguments\n"); 669105513Sphk 670105513Sphk doopen = 0; 671105513Sphk if (!strcmp(argv[1], "attach")) { 672105513Sphk action = ACT_ATTACH; 673105513Sphk opts = "l:p:"; 674105541Sphk } else if (!strcmp(argv[1], "detach")) { 675105541Sphk action = ACT_DETACH; 676105513Sphk opts = ""; 677105513Sphk } else if (!strcmp(argv[1], "init")) { 678105513Sphk action = ACT_INIT; 679105513Sphk doopen = 1; 680105513Sphk opts = "f:iL:P:"; 681105513Sphk } else if (!strcmp(argv[1], "setkey")) { 682105513Sphk action = ACT_SETKEY; 683105513Sphk doopen = 1; 684105513Sphk opts = "n:l:L:p:P:"; 685105513Sphk } else if (!strcmp(argv[1], "destroy")) { 686105513Sphk action = ACT_DESTROY; 687105513Sphk doopen = 1; 688105513Sphk opts = "l:p:"; 689105513Sphk } else if (!strcmp(argv[1], "nuke")) { 690105513Sphk action = ACT_NUKE; 691105513Sphk doopen = 1; 692105513Sphk opts = "l:p:n:"; 693105513Sphk } else { 694105513Sphk usage("Unknown sub command\n"); 695105513Sphk } 696105513Sphk argc--; 697105513Sphk argv++; 698105513Sphk 699107455Sphk dest = strdup(argv[1]); 700105513Sphk argc--; 701105513Sphk argv++; 702105513Sphk 703105513Sphk p_opt = NULL; 704105513Sphk P_opt = NULL; 705105513Sphk l_opt = NULL; 706105513Sphk L_opt = NULL; 707105513Sphk f_opt = NULL; 708105513Sphk n_opt = 0; 709105513Sphk i_opt = 0; 710105513Sphk 711105513Sphk while((ch = getopt(argc, argv, opts)) != -1) 712105513Sphk switch (ch) { 713105513Sphk case 'f': 714105513Sphk f_opt = optarg; 715105513Sphk break; 716105513Sphk case 'i': 717105513Sphk i_opt = !i_opt; 718105513Sphk case 'l': 719105513Sphk l_opt = optarg; 720105513Sphk break; 721105513Sphk case 'L': 722105513Sphk L_opt = optarg; 723105513Sphk break; 724105513Sphk case 'p': 725105513Sphk p_opt = optarg; 726105513Sphk break; 727105513Sphk case 'P': 728105513Sphk P_opt = optarg; 729105513Sphk break; 730105513Sphk case 'n': 731105513Sphk n_opt = strtoul(optarg, &q, 0); 732105513Sphk if (!*optarg || *q) 733105513Sphk usage("-n argument not numeric\n"); 734105513Sphk if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 735107982Sphk usage("-n argument out of range\n"); break; 736105513Sphk default: 737105513Sphk usage("Invalid option\n"); 738105513Sphk } 739105513Sphk 740105513Sphk if (doopen) { 741105513Sphk dfd = open(dest, O_RDWR | O_CREAT, 0644); 742107455Sphk if (dfd < 0) { 743111298Stjr if (snprintf(buf, sizeof(buf), "%s%s", 744111298Stjr _PATH_DEV, dest) >= (ssize_t)sizeof(buf)) 745111298Stjr errno = ENAMETOOLONG; 746111298Stjr else 747111298Stjr dfd = open(buf, O_RDWR | O_CREAT, 0644); 748107455Sphk } 749105513Sphk if (dfd < 0) 750111296Stjr err(1, "%s", dest); 751107455Sphk } else { 752107455Sphk if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 753107455Sphk strcpy(dest, dest + strlen(_PATH_DEV)); 754107455Sphk if (strchr(dest, '/')) 755107455Sphk usage("\"dest\" argument must be geom-name\n"); 756105513Sphk } 757105513Sphk 758105513Sphk memset(&sc, 0, sizeof sc); 759107982Sphk sc.consumer = (void *)&dfd; 760105513Sphk gl = &sc.key; 761105513Sphk switch(action) { 762105513Sphk case ACT_ATTACH: 763105513Sphk setup_passphrase(&sc, 0, p_opt); 764105513Sphk cmd_attach(&sc, dest, l_opt); 765105513Sphk break; 766105541Sphk case ACT_DETACH: 767105541Sphk cmd_detach(dest); 768105513Sphk break; 769105513Sphk case ACT_INIT: 770105513Sphk cmd_init(gl, dfd, f_opt, i_opt, L_opt); 771105513Sphk setup_passphrase(&sc, 1, P_opt); 772105513Sphk cmd_write(gl, &sc, dfd, 0, L_opt); 773105513Sphk break; 774105513Sphk case ACT_SETKEY: 775105513Sphk setup_passphrase(&sc, 0, p_opt); 776105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 777105513Sphk if (n_opt == 0) 778105513Sphk n_opt = nkey + 1; 779105513Sphk setup_passphrase(&sc, 1, P_opt); 780105513Sphk cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 781105513Sphk break; 782105513Sphk case ACT_DESTROY: 783105513Sphk setup_passphrase(&sc, 0, p_opt); 784105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 785105513Sphk cmd_destroy(gl, nkey); 786105513Sphk reset_passphrase(&sc); 787105513Sphk cmd_write(gl, &sc, dfd, nkey, l_opt); 788105513Sphk break; 789105513Sphk case ACT_NUKE: 790105513Sphk setup_passphrase(&sc, 0, p_opt); 791105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 792105513Sphk if (n_opt == 0) 793105513Sphk n_opt = nkey + 1; 794105513Sphk if (n_opt == -1) { 795105513Sphk for(i = 0; i < G_BDE_MAXKEYS; i++) 796105513Sphk cmd_nuke(gl, dfd, i); 797105513Sphk } else { 798105513Sphk cmd_nuke(gl, dfd, n_opt - 1); 799105513Sphk } 800105513Sphk break; 801105513Sphk default: 802105513Sphk usage("Internal error\n"); 803105513Sphk } 804105513Sphk 805105513Sphk return(0); 806105513Sphk} 807