gbde.c revision 125387
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 125387 2004-02-03 11:12:29Z des $ 33121073Sphk * 34121073Sphk * XXX: Future stuff 35125387Sdes * 36121073Sphk * Replace the template file options (-i & -f) with command-line variables 37121073Sphk * "-v property=foo" 38121073Sphk * 39121073Sphk * Introduce -e, extra entropy source (XOR with /dev/random) 40121073Sphk * 41121073Sphk * Introduce -E, alternate entropy source (instead of /dev/random) 42121073Sphk * 43125387Sdes * Introduce -i take IV from keyboard or 44121073Sphk * 45121073Sphk * Introduce -I take IV from file/cmd 46121073Sphk * 47121073Sphk * Introduce -m/-M store encrypted+encoded masterkey in file 48121073Sphk * 49121073Sphk * Introduce -k/-K get pass-phrase part from file/cmd 50121073Sphk * 51121073Sphk * Introduce -d add more dest-devices to worklist. 52121073Sphk * 53121073Sphk * Add key-option: selfdestruct bit. 54121073Sphk * 55121073Sphk * New/changed verbs: 56121073Sphk * "onetime" attach with onetime nonstored locksector 57121073Sphk * "key"/"unkey" to blast memory copy of key without orphaning 58121073Sphk * "nuke" blow away everything attached, crash/halt/power-off if possible. 59121073Sphk * "blast" destroy all copies of the masterkey 60121073Sphk * "destroy" destroy one copy of the masterkey 61121073Sphk * "backup"/"restore" of masterkey sectors. 62121073Sphk * 63121073Sphk * Make all verbs work on both attached/detached devices. 64121073Sphk * 65105513Sphk */ 66105513Sphk 67105513Sphk#include <sys/types.h> 68105513Sphk#include <sys/queue.h> 69105513Sphk#include <sys/mutex.h> 70105513Sphk#include <md5.h> 71105513Sphk#include <readpassphrase.h> 72105513Sphk#include <string.h> 73105513Sphk#include <stdint.h> 74105513Sphk#include <unistd.h> 75105513Sphk#include <fcntl.h> 76107455Sphk#include <paths.h> 77105513Sphk#include <strings.h> 78105513Sphk#include <stdlib.h> 79105513Sphk#include <err.h> 80105513Sphk#include <stdio.h> 81105513Sphk#include <libutil.h> 82112877Sphk#include <libgeom.h> 83105513Sphk#include <sys/errno.h> 84105513Sphk#include <sys/disk.h> 85106407Sphk#include <sys/stat.h> 86105513Sphk#include <crypto/rijndael/rijndael.h> 87106407Sphk#include <crypto/sha2/sha2.h> 88120877Sphk#include <sys/param.h> 89120877Sphk#include <sys/linker.h> 90105513Sphk 91120877Sphk#define GBDEMOD "geom_bde" 92106407Sphk#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0) 93106407Sphk 94105513Sphk#include <geom/geom.h> 95105513Sphk#include <geom/bde/g_bde.h> 96105513Sphk 97105513Sphkextern const char template[]; 98105513Sphk 99106407Sphk 100106407Sphk#if 0 101106407Sphkstatic void 102106407Sphkg_hexdump(void *ptr, int length) 103106407Sphk{ 104106407Sphk int i, j, k; 105106407Sphk unsigned char *cp; 106106407Sphk 107106407Sphk cp = ptr; 108106407Sphk for (i = 0; i < length; i+= 16) { 109106407Sphk printf("%04x ", i); 110106407Sphk for (j = 0; j < 16; j++) { 111106407Sphk k = i + j; 112106407Sphk if (k < length) 113106407Sphk printf(" %02x", cp[k]); 114106407Sphk else 115106407Sphk printf(" "); 116106407Sphk } 117106407Sphk printf(" |"); 118106407Sphk for (j = 0; j < 16; j++) { 119106407Sphk k = i + j; 120106407Sphk if (k >= length) 121106407Sphk printf(" "); 122106407Sphk else if (cp[k] >= ' ' && cp[k] <= '~') 123106407Sphk printf("%c", cp[k]); 124106407Sphk else 125106407Sphk printf("."); 126106407Sphk } 127106407Sphk printf("|\n"); 128106407Sphk } 129106407Sphk} 130106407Sphk#endif 131106407Sphk 132105513Sphkstatic void __dead2 133105513Sphkusage(const char *reason) 134105513Sphk{ 135105513Sphk const char *p; 136105513Sphk 137105513Sphk p = getprogname(); 138105513Sphk fprintf(stderr, "Usage error: %s", reason); 139105513Sphk fprintf(stderr, "Usage:\n"); 140107455Sphk fprintf(stderr, "\t%s attach dest [-l lockfile]\n", p); 141105541Sphk fprintf(stderr, "\t%s detach dest\n", p); 142107455Sphk fprintf(stderr, "\t%s init /dev/dest [-i] [-f filename] [-L lockfile]\n", p); 143107455Sphk fprintf(stderr, "\t%s setkey dest [-n key] [-l lockfile] [-L lockfile]\n", p); 144107455Sphk fprintf(stderr, "\t%s destroy dest [-n key] [-l lockfile] [-L lockfile]\n", p); 145105513Sphk exit (1); 146105513Sphk} 147105513Sphk 148105513Sphkvoid * 149105513Sphkg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 150105513Sphk{ 151105513Sphk void *p; 152105513Sphk int fd, i; 153105513Sphk off_t o2; 154105513Sphk 155105513Sphk p = malloc(length); 156105513Sphk if (p == NULL) 157105513Sphk err(1, "malloc"); 158105513Sphk fd = *(int *)cp; 159105513Sphk o2 = lseek(fd, offset, SEEK_SET); 160105513Sphk if (o2 != offset) 161105513Sphk err(1, "lseek"); 162105513Sphk i = read(fd, p, length); 163105513Sphk if (i != length) 164105513Sphk err(1, "read"); 165105513Sphk if (error != NULL) 166105513Sphk error = 0; 167105513Sphk return (p); 168105513Sphk} 169105513Sphk 170105513Sphkstatic void 171105513Sphkrandom_bits(void *p, u_int len) 172105513Sphk{ 173105513Sphk static int fdr = -1; 174105513Sphk int i; 175105513Sphk 176105513Sphk if (fdr < 0) { 177105513Sphk fdr = open("/dev/urandom", O_RDONLY); 178105513Sphk if (fdr < 0) 179105513Sphk err(1, "/dev/urandom"); 180105513Sphk } 181125387Sdes 182105513Sphk i = read(fdr, p, len); 183105513Sphk if (i != (int)len) 184105513Sphk err(1, "read from /dev/urandom"); 185105513Sphk} 186105513Sphk 187105513Sphk/* XXX: not nice */ 188106407Sphkstatic u_char sha2[SHA512_DIGEST_LENGTH]; 189105513Sphk 190105513Sphkstatic void 191105513Sphkreset_passphrase(struct g_bde_softc *sc) 192105513Sphk{ 193105513Sphk 194106407Sphk memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH); 195105513Sphk} 196105513Sphk 197105513Sphkstatic void 198105513Sphksetup_passphrase(struct g_bde_softc *sc, int sure, const char *input) 199105513Sphk{ 200105513Sphk char buf1[BUFSIZ], buf2[BUFSIZ], *p; 201105513Sphk 202105513Sphk if (input != NULL) { 203106407Sphk g_bde_hash_pass(sc, input, strlen(input)); 204106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 205105513Sphk return; 206105513Sphk } 207105513Sphk for (;;) { 208105513Sphk p = readpassphrase( 209105513Sphk sure ? "Enter new passphrase:" : "Enter passphrase: ", 210105513Sphk buf1, sizeof buf1, 211105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 212105513Sphk if (p == NULL) 213105513Sphk err(1, "readpassphrase"); 214105513Sphk 215105513Sphk if (sure) { 216105513Sphk p = readpassphrase("Reenter new passphrase: ", 217105513Sphk buf2, sizeof buf2, 218105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 219105513Sphk if (p == NULL) 220105513Sphk err(1, "readpassphrase"); 221105513Sphk 222105513Sphk if (strcmp(buf1, buf2)) { 223105513Sphk printf("They didn't match.\n"); 224105513Sphk continue; 225105513Sphk } 226105513Sphk } 227105513Sphk if (strlen(buf1) < 3) { 228105513Sphk printf("Too short passphrase.\n"); 229105513Sphk continue; 230105513Sphk } 231105513Sphk break; 232105513Sphk } 233106407Sphk g_bde_hash_pass(sc, buf1, strlen(buf1)); 234106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 235105513Sphk} 236105513Sphk 237105513Sphkstatic void 238106407Sphkencrypt_sector(void *d, int len, int klen, void *key) 239105513Sphk{ 240105513Sphk keyInstance ki; 241105513Sphk cipherInstance ci; 242105513Sphk int error; 243125387Sdes 244105513Sphk error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 245105513Sphk if (error <= 0) 246105513Sphk errx(1, "rijndael_cipherInit=%d", error); 247106407Sphk error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key); 248105513Sphk if (error <= 0) 249105513Sphk errx(1, "rijndael_makeKeY=%d", error); 250105513Sphk error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 251105513Sphk if (error <= 0) 252105513Sphk errx(1, "rijndael_blockEncrypt=%d", error); 253105513Sphk} 254105513Sphk 255105513Sphkstatic void 256105513Sphkcmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 257105513Sphk{ 258112877Sphk int ffd; 259112877Sphk u_char buf[16]; 260112877Sphk struct gctl_req *r; 261112877Sphk const char *errstr; 262105513Sphk 263115624Sphk r = gctl_get_handle(); 264115624Sphk gctl_ro_param(r, "verb", -1, "create geom"); 265112877Sphk gctl_ro_param(r, "class", -1, "BDE"); 266112877Sphk gctl_ro_param(r, "provider", -1, dest); 267112877Sphk gctl_ro_param(r, "pass", SHA512_DIGEST_LENGTH, sc->sha2); 268105513Sphk if (lfile != NULL) { 269105513Sphk ffd = open(lfile, O_RDONLY, 0); 270105513Sphk if (ffd < 0) 271111296Stjr err(1, "%s", lfile); 272112877Sphk read(ffd, buf, 16); 273112877Sphk gctl_ro_param(r, "key", 16, buf); 274105513Sphk close(ffd); 275105513Sphk } 276112877Sphk /* gctl_dump(r, stdout); */ 277112877Sphk errstr = gctl_issue(r); 278112877Sphk if (errstr != NULL) 279125386Sdes errx(1, "Attach to %s failed: %s", dest, errstr); 280105513Sphk 281105513Sphk exit (0); 282105513Sphk} 283105513Sphk 284105513Sphkstatic void 285105541Sphkcmd_detach(const char *dest) 286105513Sphk{ 287112877Sphk struct gctl_req *r; 288112877Sphk const char *errstr; 289112877Sphk char buf[BUFSIZ]; 290105513Sphk 291115624Sphk r = gctl_get_handle(); 292115624Sphk gctl_ro_param(r, "verb", -1, "destroy geom"); 293112877Sphk gctl_ro_param(r, "class", -1, "BDE"); 294112877Sphk sprintf(buf, "%s.bde", dest); 295112877Sphk gctl_ro_param(r, "geom", -1, buf); 296112877Sphk /* gctl_dump(r, stdout); */ 297112877Sphk errstr = gctl_issue(r); 298112877Sphk if (errstr != NULL) 299125386Sdes errx(1, "Detach of %s failed: %s", dest, errstr); 300105513Sphk exit (0); 301105513Sphk} 302105513Sphk 303105513Sphkstatic void 304106407Sphkcmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey) 305105513Sphk{ 306105513Sphk int error; 307105513Sphk int ffd; 308105513Sphk u_char keyloc[16]; 309106407Sphk u_int sectorsize; 310106407Sphk off_t mediasize; 311106407Sphk struct stat st; 312105513Sphk 313106407Sphk error = ioctl(dfd, DIOCGSECTORSIZE, §orsize); 314106407Sphk if (error) 315106407Sphk sectorsize = 512; 316106407Sphk error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize); 317106407Sphk if (error) { 318106407Sphk error = fstat(dfd, &st); 319106407Sphk if (error == 0 && S_ISREG(st.st_mode)) 320106407Sphk mediasize = st.st_size; 321106407Sphk else 322106407Sphk error = ENOENT; 323106407Sphk } 324106407Sphk if (error) 325106407Sphk mediasize = (off_t)-1; 326105513Sphk if (l_opt != NULL) { 327105513Sphk ffd = open(l_opt, O_RDONLY, 0); 328105513Sphk if (ffd < 0) 329111296Stjr err(1, "%s", l_opt); 330105513Sphk read(ffd, keyloc, sizeof keyloc); 331105513Sphk close(ffd); 332105513Sphk } else { 333105513Sphk memset(keyloc, 0, sizeof keyloc); 334105513Sphk } 335105513Sphk 336106407Sphk error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize, 337106407Sphk sectorsize, nkey); 338105513Sphk if (error == ENOENT) 339105513Sphk errx(1, "Lock was destroyed."); 340105513Sphk if (error == ESRCH) 341105513Sphk errx(1, "Lock was nuked."); 342105513Sphk if (error == ENOTDIR) 343105513Sphk errx(1, "Lock not found"); 344105513Sphk if (error != 0) 345105513Sphk errx(1, "Error %d decrypting lock", error); 346105513Sphk if (nkey) 347105513Sphk printf("Opened with key %u\n", *nkey); 348105513Sphk return; 349105513Sphk} 350105513Sphk 351105513Sphkstatic void 352105513Sphkcmd_nuke(struct g_bde_key *gl, int dfd , int key) 353105513Sphk{ 354105513Sphk int i; 355105513Sphk u_char *sbuf; 356105513Sphk off_t offset, offset2; 357105513Sphk 358105513Sphk sbuf = malloc(gl->sectorsize); 359105513Sphk memset(sbuf, 0, gl->sectorsize); 360105513Sphk offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 361105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 362105513Sphk if (offset2 != offset) 363105513Sphk err(1, "lseek"); 364105513Sphk i = write(dfd, sbuf, gl->sectorsize); 365105513Sphk if (i != (int)gl->sectorsize) 366105513Sphk err(1, "write"); 367105513Sphk printf("Nuked key %d\n", key); 368105513Sphk} 369105513Sphk 370105513Sphkstatic void 371105513Sphkcmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 372105513Sphk{ 373105513Sphk int i, ffd; 374105513Sphk uint64_t off[2]; 375105513Sphk u_char keyloc[16]; 376105513Sphk u_char *sbuf, *q; 377105513Sphk off_t offset, offset2; 378105513Sphk 379105513Sphk sbuf = malloc(gl->sectorsize); 380105513Sphk /* 381105513Sphk * Find the byte-offset in the lock sector where we will put the lock 382105513Sphk * data structure. We can put it any random place as long as the 383105513Sphk * structure fits. 384105513Sphk */ 385105513Sphk for(;;) { 386105513Sphk random_bits(off, sizeof off); 387105513Sphk off[0] &= (gl->sectorsize - 1); 388105513Sphk if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 389105513Sphk continue; 390105513Sphk break; 391105513Sphk } 392105513Sphk 393105513Sphk /* Add the sector offset in bytes */ 394105513Sphk off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 395105513Sphk gl->lsector[key] = off[0]; 396105513Sphk 397120876Sphk i = g_bde_keyloc_encrypt(sc->sha2, off[0], off[1], keyloc); 398105513Sphk if (i) 399105513Sphk errx(1, "g_bde_keyloc_encrypt()"); 400105513Sphk if (l_opt != NULL) { 401105513Sphk ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 402105513Sphk if (ffd < 0) 403111296Stjr err(1, "%s", l_opt); 404105513Sphk write(ffd, keyloc, sizeof keyloc); 405105513Sphk close(ffd); 406120876Sphk } else if (gl->flags & GBDE_F_SECT0) { 407105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 408105513Sphk if (offset2 != 0) 409105513Sphk err(1, "lseek"); 410105513Sphk i = read(dfd, sbuf, gl->sectorsize); 411105513Sphk if (i != (int)gl->sectorsize) 412105513Sphk err(1, "read"); 413105513Sphk memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 414105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 415105513Sphk if (offset2 != 0) 416105513Sphk err(1, "lseek"); 417105513Sphk i = write(dfd, sbuf, gl->sectorsize); 418105513Sphk if (i != (int)gl->sectorsize) 419105513Sphk err(1, "write"); 420105513Sphk } else { 421105513Sphk errx(1, "No -L option and no space in sector 0 for lockfile"); 422105513Sphk } 423105513Sphk 424105513Sphk /* Allocate a sectorbuffer and fill it with random junk */ 425105513Sphk if (sbuf == NULL) 426105513Sphk err(1, "malloc"); 427105513Sphk random_bits(sbuf, gl->sectorsize); 428105513Sphk 429105513Sphk /* Fill random bits in the spare field */ 430105513Sphk random_bits(gl->spare, sizeof(gl->spare)); 431105513Sphk 432105513Sphk /* Encode the structure where we want it */ 433105513Sphk q = sbuf + (off[0] % gl->sectorsize); 434120876Sphk i = g_bde_encode_lock(sc->sha2, gl, q); 435106407Sphk if (i < 0) 436106407Sphk errx(1, "programming error encoding lock"); 437105513Sphk 438106407Sphk encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); 439105513Sphk offset = gl->lsector[key] & ~(gl->sectorsize - 1); 440105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 441105513Sphk if (offset2 != offset) 442105513Sphk err(1, "lseek"); 443105513Sphk i = write(dfd, sbuf, gl->sectorsize); 444105513Sphk if (i != (int)gl->sectorsize) 445105513Sphk err(1, "write"); 446105513Sphk printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 447108052Sphk#if 0 448108052Sphk printf("s0 = %jd\n", (intmax_t)gl->sector0); 449108052Sphk printf("sN = %jd\n", (intmax_t)gl->sectorN); 450108052Sphk printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]); 451108052Sphk printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]); 452108052Sphk printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]); 453108052Sphk printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]); 454108052Sphk printf("k = %jd\n", (intmax_t)gl->keyoffset); 455108052Sphk printf("ss = %jd\n", (intmax_t)gl->sectorsize); 456108052Sphk#endif 457105513Sphk} 458105513Sphk 459105513Sphkstatic void 460105513Sphkcmd_destroy(struct g_bde_key *gl, int nkey) 461105513Sphk{ 462105513Sphk int i; 463105513Sphk 464105513Sphk bzero(&gl->sector0, sizeof gl->sector0); 465105513Sphk bzero(&gl->sectorN, sizeof gl->sectorN); 466105513Sphk bzero(&gl->keyoffset, sizeof gl->keyoffset); 467105513Sphk bzero(&gl->flags, sizeof gl->flags); 468106227Sphk bzero(gl->mkey, sizeof gl->mkey); 469105513Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) 470105513Sphk if (i != nkey) 471105513Sphk gl->lsector[i] = ~0; 472105513Sphk} 473105513Sphk 474108052Sphkstatic int 475108052Sphksorthelp(const void *a, const void *b) 476108052Sphk{ 477108052Sphk const off_t *oa, *ob; 478108052Sphk 479108052Sphk oa = a; 480108052Sphk ob = b; 481113466Sphk return (*oa > *ob); 482108052Sphk} 483108052Sphk 484105513Sphkstatic void 485105513Sphkcmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 486105513Sphk{ 487105513Sphk int i; 488105513Sphk u_char *buf; 489105513Sphk unsigned sector_size; 490105513Sphk uint64_t first_sector; 491105513Sphk uint64_t last_sector; 492105513Sphk uint64_t total_sectors; 493105513Sphk off_t off, off2; 494105513Sphk unsigned nkeys; 495105513Sphk const char *p; 496105513Sphk char *q, cbuf[BUFSIZ]; 497105513Sphk unsigned u, u2; 498105513Sphk uint64_t o; 499105513Sphk properties params; 500105513Sphk 501105513Sphk bzero(gl, sizeof *gl); 502105513Sphk if (f_opt != NULL) { 503105513Sphk i = open(f_opt, O_RDONLY); 504105513Sphk if (i < 0) 505111296Stjr err(1, "%s", f_opt); 506105513Sphk params = properties_read(i); 507105513Sphk close (i); 508105513Sphk } else { 509105513Sphk /* XXX: Polish */ 510105513Sphk q = strdup("/tmp/temp.XXXXXXXXXX"); 511105513Sphk i = mkstemp(q); 512105513Sphk if (i < 0) 513111296Stjr err(1, "%s", q); 514105513Sphk write(i, template, strlen(template)); 515105513Sphk close (i); 516105513Sphk if (i_opt) { 517105513Sphk p = getenv("EDITOR"); 518105513Sphk if (p == NULL) 519105513Sphk p = "vi"; 520111298Stjr if (snprintf(cbuf, sizeof(cbuf), "%s %s\n", p, q) >= 521111298Stjr (ssize_t)sizeof(cbuf)) 522111298Stjr errx(1, "EDITOR is too long"); 523105513Sphk system(cbuf); 524105513Sphk } 525105513Sphk i = open(q, O_RDONLY); 526105513Sphk if (i < 0) 527111296Stjr err(1, "%s", f_opt); 528105513Sphk params = properties_read(i); 529105513Sphk close (i); 530105513Sphk unlink(q); 531105513Sphk } 532105513Sphk 533105513Sphk /* <sector_size> */ 534105513Sphk p = property_find(params, "sector_size"); 535105513Sphk i = ioctl(dfd, DIOCGSECTORSIZE, &u); 536105513Sphk if (p != NULL) { 537105513Sphk sector_size = strtoul(p, &q, 0); 538105513Sphk if (!*p || *q) 539105513Sphk errx(1, "sector_size not a proper number"); 540108020Sphk } else if (i == 0) { 541108020Sphk sector_size = u; 542108020Sphk } else { 543108020Sphk errx(1, "Missing sector_size property"); 544105513Sphk } 545105513Sphk if (sector_size & (sector_size - 1)) 546105513Sphk errx(1, "sector_size not a power of 2"); 547105513Sphk if (sector_size < 512) 548105513Sphk errx(1, "sector_size is smaller than 512"); 549105513Sphk buf = malloc(sector_size); 550105513Sphk if (buf == NULL) 551105513Sphk err(1, "Failed to malloc sector buffer"); 552105513Sphk gl->sectorsize = sector_size; 553105513Sphk 554105513Sphk i = ioctl(dfd, DIOCGMEDIASIZE, &off); 555105513Sphk if (i == 0) { 556105513Sphk first_sector = 0; 557105513Sphk total_sectors = off / sector_size; 558105513Sphk last_sector = total_sectors - 1; 559105513Sphk } else { 560105513Sphk first_sector = 0; 561105513Sphk last_sector = 0; 562105513Sphk total_sectors = 0; 563105513Sphk } 564105513Sphk 565105513Sphk /* <first_sector> */ 566105513Sphk p = property_find(params, "first_sector"); 567105513Sphk if (p != NULL) { 568105513Sphk first_sector = strtoul(p, &q, 0); 569105513Sphk if (!*p || *q) 570105513Sphk errx(1, "first_sector not a proper number"); 571105513Sphk } 572105513Sphk 573105513Sphk /* <last_sector> */ 574105513Sphk p = property_find(params, "last_sector"); 575105513Sphk if (p != NULL) { 576105513Sphk last_sector = strtoul(p, &q, 0); 577105513Sphk if (!*p || *q) 578105513Sphk errx(1, "last_sector not a proper number"); 579105513Sphk if (last_sector <= first_sector) 580105513Sphk errx(1, "last_sector not larger than first_sector"); 581105513Sphk total_sectors = last_sector + 1; 582105513Sphk } 583105513Sphk 584105513Sphk /* <total_sectors> */ 585105513Sphk p = property_find(params, "total_sectors"); 586105513Sphk if (p != NULL) { 587105513Sphk total_sectors = strtoul(p, &q, 0); 588105513Sphk if (!*p || *q) 589105513Sphk errx(1, "total_sectors not a proper number"); 590125387Sdes if (last_sector == 0) 591105513Sphk last_sector = first_sector + total_sectors - 1; 592105513Sphk } 593105513Sphk 594105513Sphk if (l_opt == NULL && first_sector != 0) 595105513Sphk errx(1, "No -L new-lockfile argument and first_sector != 0"); 596105513Sphk else if (l_opt == NULL) { 597105513Sphk first_sector++; 598105513Sphk total_sectors--; 599120876Sphk gl->flags |= GBDE_F_SECT0; 600105513Sphk } 601108060Sphk gl->sector0 = first_sector * gl->sectorsize; 602105513Sphk 603105513Sphk if (total_sectors != (last_sector - first_sector) + 1) 604105513Sphk errx(1, "total_sectors disagree with first_sector and last_sector"); 605105513Sphk if (total_sectors == 0) 606105513Sphk errx(1, "missing last_sector or total_sectors"); 607105513Sphk 608105513Sphk gl->sectorN = (last_sector + 1) * gl->sectorsize; 609105513Sphk 610105513Sphk /* Find a random keyoffset */ 611105513Sphk random_bits(&o, sizeof o); 612105513Sphk o %= (gl->sectorN - gl->sector0); 613105513Sphk o &= ~(gl->sectorsize - 1); 614105513Sphk gl->keyoffset = o; 615105513Sphk 616105513Sphk /* <number_of_keys> */ 617105513Sphk p = property_find(params, "number_of_keys"); 618105513Sphk if (p == NULL) 619105513Sphk errx(1, "Missing number_of_keys property"); 620105513Sphk nkeys = strtoul(p, &q, 0); 621105513Sphk if (!*p || *q) 622105513Sphk errx(1, "number_of_keys not a proper number"); 623105513Sphk if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 624105513Sphk errx(1, "number_of_keys out of range"); 625105513Sphk for (u = 0; u < nkeys; u++) { 626105513Sphk for(;;) { 627105513Sphk do { 628105513Sphk random_bits(&o, sizeof o); 629105513Sphk o %= gl->sectorN; 630105513Sphk o &= ~(gl->sectorsize - 1); 631105513Sphk } while(o < gl->sector0); 632105513Sphk for (u2 = 0; u2 < u; u2++) 633105513Sphk if (o == gl->lsector[u2]) 634105513Sphk break; 635105513Sphk if (u2 < u) 636105513Sphk continue; 637105513Sphk break; 638105513Sphk } 639105513Sphk gl->lsector[u] = o; 640125387Sdes } 641105513Sphk for (; u < G_BDE_MAXKEYS; u++) { 642125387Sdes do 643105513Sphk random_bits(&o, sizeof o); 644105513Sphk while (o < gl->sectorN); 645105513Sphk gl->lsector[u] = o; 646105513Sphk } 647108052Sphk qsort(gl->lsector, G_BDE_MAXKEYS, sizeof gl->lsector[0], sorthelp); 648105513Sphk 649105513Sphk /* Flush sector zero if we use it for lockfile data */ 650120876Sphk if (gl->flags & GBDE_F_SECT0) { 651105513Sphk off2 = lseek(dfd, 0, SEEK_SET); 652105513Sphk if (off2 != 0) 653105513Sphk err(1, "lseek(2) to sector 0"); 654105513Sphk random_bits(buf, sector_size); 655105513Sphk i = write(dfd, buf, sector_size); 656105513Sphk if (i != (int)sector_size) 657105513Sphk err(1, "write sector 0"); 658105513Sphk } 659105513Sphk 660105513Sphk /* <random_flush> */ 661105513Sphk p = property_find(params, "random_flush"); 662105513Sphk if (p != NULL) { 663105513Sphk off = first_sector * sector_size; 664105513Sphk off2 = lseek(dfd, off, SEEK_SET); 665105513Sphk if (off2 != off) 666105513Sphk err(1, "lseek(2) to first_sector"); 667105513Sphk off2 = last_sector * sector_size; 668105513Sphk while (off <= off2) { 669105513Sphk random_bits(buf, sector_size); 670105513Sphk i = write(dfd, buf, sector_size); 671105513Sphk if (i != (int)sector_size) 672105513Sphk err(1, "write to $device_name"); 673105513Sphk off += sector_size; 674105513Sphk } 675105513Sphk } 676105513Sphk 677106227Sphk random_bits(gl->mkey, sizeof gl->mkey); 678106227Sphk random_bits(gl->salt, sizeof gl->salt); 679125387Sdes 680105513Sphk return; 681105513Sphk} 682105513Sphk 683105513Sphkstatic enum action { 684105513Sphk ACT_HUH, 685105541Sphk ACT_ATTACH, ACT_DETACH, 686105513Sphk ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 687105513Sphk} action; 688105513Sphk 689105513Sphkint 690105513Sphkmain(int argc, char **argv) 691105513Sphk{ 692105513Sphk const char *opts; 693105513Sphk const char *l_opt, *L_opt; 694105513Sphk const char *p_opt, *P_opt; 695105513Sphk const char *f_opt; 696107455Sphk char *dest; 697107455Sphk int i_opt, n_opt, ch, dfd, doopen; 698107455Sphk u_int nkey; 699105513Sphk int i; 700107455Sphk char *q, buf[BUFSIZ]; 701105513Sphk struct g_bde_key *gl; 702105513Sphk struct g_bde_softc sc; 703105513Sphk 704105513Sphk if (argc < 3) 705105513Sphk usage("Too few arguments\n"); 706105513Sphk 707120969Sphk if ((i = modfind("g_bde")) < 0) { 708125387Sdes /* need to load the gbde module */ 709125387Sdes if (kldload(GBDEMOD) < 0 || modfind("g_bde") < 0) { 710125387Sdes usage(GBDEMOD ": Kernel module not available"); 711125387Sdes } 712120877Sphk } 713105513Sphk doopen = 0; 714105513Sphk if (!strcmp(argv[1], "attach")) { 715105513Sphk action = ACT_ATTACH; 716105513Sphk opts = "l:p:"; 717105541Sphk } else if (!strcmp(argv[1], "detach")) { 718105541Sphk action = ACT_DETACH; 719105513Sphk opts = ""; 720105513Sphk } else if (!strcmp(argv[1], "init")) { 721105513Sphk action = ACT_INIT; 722105513Sphk doopen = 1; 723105513Sphk opts = "f:iL:P:"; 724105513Sphk } else if (!strcmp(argv[1], "setkey")) { 725105513Sphk action = ACT_SETKEY; 726105513Sphk doopen = 1; 727105513Sphk opts = "n:l:L:p:P:"; 728105513Sphk } else if (!strcmp(argv[1], "destroy")) { 729105513Sphk action = ACT_DESTROY; 730105513Sphk doopen = 1; 731105513Sphk opts = "l:p:"; 732105513Sphk } else if (!strcmp(argv[1], "nuke")) { 733105513Sphk action = ACT_NUKE; 734105513Sphk doopen = 1; 735105513Sphk opts = "l:p:n:"; 736105513Sphk } else { 737105513Sphk usage("Unknown sub command\n"); 738105513Sphk } 739105513Sphk argc--; 740105513Sphk argv++; 741105513Sphk 742107455Sphk dest = strdup(argv[1]); 743105513Sphk argc--; 744105513Sphk argv++; 745105513Sphk 746105513Sphk p_opt = NULL; 747105513Sphk P_opt = NULL; 748105513Sphk l_opt = NULL; 749105513Sphk L_opt = NULL; 750105513Sphk f_opt = NULL; 751105513Sphk n_opt = 0; 752105513Sphk i_opt = 0; 753105513Sphk 754105513Sphk while((ch = getopt(argc, argv, opts)) != -1) 755105513Sphk switch (ch) { 756105513Sphk case 'f': 757105513Sphk f_opt = optarg; 758105513Sphk break; 759105513Sphk case 'i': 760105513Sphk i_opt = !i_opt; 761105513Sphk case 'l': 762105513Sphk l_opt = optarg; 763105513Sphk break; 764105513Sphk case 'L': 765105513Sphk L_opt = optarg; 766105513Sphk break; 767105513Sphk case 'p': 768105513Sphk p_opt = optarg; 769105513Sphk break; 770105513Sphk case 'P': 771105513Sphk P_opt = optarg; 772105513Sphk break; 773105513Sphk case 'n': 774105513Sphk n_opt = strtoul(optarg, &q, 0); 775105513Sphk if (!*optarg || *q) 776105513Sphk usage("-n argument not numeric\n"); 777105513Sphk if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 778107982Sphk usage("-n argument out of range\n"); break; 779105513Sphk default: 780105513Sphk usage("Invalid option\n"); 781105513Sphk } 782105513Sphk 783105513Sphk if (doopen) { 784105513Sphk dfd = open(dest, O_RDWR | O_CREAT, 0644); 785107455Sphk if (dfd < 0) { 786111298Stjr if (snprintf(buf, sizeof(buf), "%s%s", 787111298Stjr _PATH_DEV, dest) >= (ssize_t)sizeof(buf)) 788111298Stjr errno = ENAMETOOLONG; 789111298Stjr else 790111298Stjr dfd = open(buf, O_RDWR | O_CREAT, 0644); 791107455Sphk } 792105513Sphk if (dfd < 0) 793111296Stjr err(1, "%s", dest); 794107455Sphk } else { 795107455Sphk if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 796107455Sphk strcpy(dest, dest + strlen(_PATH_DEV)); 797107455Sphk if (strchr(dest, '/')) 798107455Sphk usage("\"dest\" argument must be geom-name\n"); 799105513Sphk } 800105513Sphk 801105513Sphk memset(&sc, 0, sizeof sc); 802107982Sphk sc.consumer = (void *)&dfd; 803105513Sphk gl = &sc.key; 804105513Sphk switch(action) { 805105513Sphk case ACT_ATTACH: 806105513Sphk setup_passphrase(&sc, 0, p_opt); 807105513Sphk cmd_attach(&sc, dest, l_opt); 808105513Sphk break; 809105541Sphk case ACT_DETACH: 810105541Sphk cmd_detach(dest); 811105513Sphk break; 812105513Sphk case ACT_INIT: 813105513Sphk cmd_init(gl, dfd, f_opt, i_opt, L_opt); 814105513Sphk setup_passphrase(&sc, 1, P_opt); 815105513Sphk cmd_write(gl, &sc, dfd, 0, L_opt); 816105513Sphk break; 817105513Sphk case ACT_SETKEY: 818105513Sphk setup_passphrase(&sc, 0, p_opt); 819105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 820105513Sphk if (n_opt == 0) 821105513Sphk n_opt = nkey + 1; 822105513Sphk setup_passphrase(&sc, 1, P_opt); 823105513Sphk cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 824105513Sphk break; 825105513Sphk case ACT_DESTROY: 826105513Sphk setup_passphrase(&sc, 0, p_opt); 827105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 828105513Sphk cmd_destroy(gl, nkey); 829105513Sphk reset_passphrase(&sc); 830105513Sphk cmd_write(gl, &sc, dfd, nkey, l_opt); 831105513Sphk break; 832105513Sphk case ACT_NUKE: 833105513Sphk setup_passphrase(&sc, 0, p_opt); 834105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 835105513Sphk if (n_opt == 0) 836105513Sphk n_opt = nkey + 1; 837105513Sphk if (n_opt == -1) { 838105513Sphk for(i = 0; i < G_BDE_MAXKEYS; i++) 839105513Sphk cmd_nuke(gl, dfd, i); 840105513Sphk } else { 841105513Sphk cmd_nuke(gl, dfd, n_opt - 1); 842105513Sphk } 843105513Sphk break; 844105513Sphk default: 845105513Sphk usage("Internal error\n"); 846105513Sphk } 847105513Sphk 848105513Sphk return(0); 849105513Sphk} 850