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$ 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> 86143431Sume#include <crypto/rijndael/rijndael-api-fst.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 133141769Sruusage(void) 134105513Sphk{ 135105513Sphk 136141769Sru (void)fprintf(stderr, 137155453Scperciva"usage: gbde attach destination [-k keyfile] [-l lockfile] [-p pass-phrase]\n" 138141769Sru" gbde detach destination\n" 139155453Scperciva" gbde init destination [-i] [-f filename] [-K new-keyfile]\n" 140141769Sru" [-L new-lockfile] [-P new-pass-phrase]\n" 141155453Scperciva" gbde setkey destination [-n key]\n" 142155453Scperciva" [-k keyfile] [-l lockfile] [-p pass-phrase]\n" 143155453Scperciva" [-K new-keyfile] [-L new-lockfile] [-P new-pass-phrase]\n" 144155453Scperciva" gbde nuke destination [-n key]\n" 145155453Scperciva" [-k keyfile] [-l lockfile] [-p pass-phrase]\n" 146155453Scperciva" gbde destroy destination [-k keyfile] [-l lockfile] [-p pass-phrase]\n"); 147141769Sru exit(1); 148105513Sphk} 149105513Sphk 150105513Sphkvoid * 151105513Sphkg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 152105513Sphk{ 153105513Sphk void *p; 154105513Sphk int fd, i; 155105513Sphk off_t o2; 156105513Sphk 157105513Sphk p = malloc(length); 158105513Sphk if (p == NULL) 159105513Sphk err(1, "malloc"); 160105513Sphk fd = *(int *)cp; 161105513Sphk o2 = lseek(fd, offset, SEEK_SET); 162105513Sphk if (o2 != offset) 163105513Sphk err(1, "lseek"); 164105513Sphk i = read(fd, p, length); 165105513Sphk if (i != length) 166105513Sphk err(1, "read"); 167105513Sphk if (error != NULL) 168105513Sphk error = 0; 169105513Sphk return (p); 170105513Sphk} 171105513Sphk 172105513Sphkstatic void 173105513Sphkrandom_bits(void *p, u_int len) 174105513Sphk{ 175105513Sphk static int fdr = -1; 176105513Sphk int i; 177105513Sphk 178105513Sphk if (fdr < 0) { 179105513Sphk fdr = open("/dev/urandom", O_RDONLY); 180105513Sphk if (fdr < 0) 181105513Sphk err(1, "/dev/urandom"); 182105513Sphk } 183125387Sdes 184105513Sphk i = read(fdr, p, len); 185105513Sphk if (i != (int)len) 186105513Sphk err(1, "read from /dev/urandom"); 187105513Sphk} 188105513Sphk 189105513Sphk/* XXX: not nice */ 190106407Sphkstatic u_char sha2[SHA512_DIGEST_LENGTH]; 191105513Sphk 192105513Sphkstatic void 193105513Sphkreset_passphrase(struct g_bde_softc *sc) 194105513Sphk{ 195105513Sphk 196106407Sphk memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH); 197105513Sphk} 198105513Sphk 199105513Sphkstatic void 200155453Scpercivasetup_passphrase(struct g_bde_softc *sc, int sure, const char *input, 201155453Scperciva const char *keyfile) 202105513Sphk{ 203155453Scperciva char buf1[BUFSIZ + SHA512_DIGEST_LENGTH]; 204155453Scperciva char buf2[BUFSIZ + SHA512_DIGEST_LENGTH]; 205155453Scperciva char *p; 206155453Scperciva int kfd, klen, bpos = 0; 207105513Sphk 208155453Scperciva if (keyfile != NULL) { 209155453Scperciva /* Read up to BUFSIZ bytes from keyfile */ 210155453Scperciva kfd = open(keyfile, O_RDONLY, 0); 211155453Scperciva if (kfd < 0) 212155453Scperciva err(1, "%s", keyfile); 213155453Scperciva klen = read(kfd, buf1, BUFSIZ); 214155453Scperciva if (klen == -1) 215155453Scperciva err(1, "%s", keyfile); 216155453Scperciva close(kfd); 217155453Scperciva 218155453Scperciva /* Prepend the passphrase with the hash of the key read */ 219155453Scperciva g_bde_hash_pass(sc, buf1, klen); 220155453Scperciva memcpy(buf1, sc->sha2, SHA512_DIGEST_LENGTH); 221155453Scperciva memcpy(buf2, sc->sha2, SHA512_DIGEST_LENGTH); 222155453Scperciva bpos = SHA512_DIGEST_LENGTH; 223155453Scperciva } 224155453Scperciva 225105513Sphk if (input != NULL) { 226155453Scperciva if (strlen(input) >= BUFSIZ) 227155453Scperciva errx(1, "Passphrase too long"); 228155453Scperciva strcpy(buf1 + bpos, input); 229155453Scperciva 230155453Scperciva g_bde_hash_pass(sc, buf1, strlen(buf1 + bpos) + bpos); 231106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 232105513Sphk return; 233105513Sphk } 234105513Sphk for (;;) { 235105513Sphk p = readpassphrase( 236105513Sphk sure ? "Enter new passphrase:" : "Enter passphrase: ", 237155453Scperciva buf1 + bpos, sizeof buf1 - bpos, 238105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 239105513Sphk if (p == NULL) 240105513Sphk err(1, "readpassphrase"); 241105513Sphk 242105513Sphk if (sure) { 243105513Sphk p = readpassphrase("Reenter new passphrase: ", 244155453Scperciva buf2 + bpos, sizeof buf2 - bpos, 245105513Sphk RPP_ECHO_OFF | RPP_REQUIRE_TTY); 246105513Sphk if (p == NULL) 247105513Sphk err(1, "readpassphrase"); 248105513Sphk 249155453Scperciva if (strcmp(buf1 + bpos, buf2 + bpos)) { 250105513Sphk printf("They didn't match.\n"); 251105513Sphk continue; 252105513Sphk } 253105513Sphk } 254155453Scperciva if (strlen(buf1 + bpos) < 3) { 255105513Sphk printf("Too short passphrase.\n"); 256105513Sphk continue; 257105513Sphk } 258105513Sphk break; 259105513Sphk } 260155453Scperciva g_bde_hash_pass(sc, buf1, strlen(buf1 + bpos) + bpos); 261106407Sphk memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 262105513Sphk} 263105513Sphk 264105513Sphkstatic void 265106407Sphkencrypt_sector(void *d, int len, int klen, void *key) 266105513Sphk{ 267105513Sphk keyInstance ki; 268105513Sphk cipherInstance ci; 269105513Sphk int error; 270125387Sdes 271105513Sphk error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 272105513Sphk if (error <= 0) 273105513Sphk errx(1, "rijndael_cipherInit=%d", error); 274106407Sphk error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key); 275105513Sphk if (error <= 0) 276105513Sphk errx(1, "rijndael_makeKeY=%d", error); 277105513Sphk error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 278105513Sphk if (error <= 0) 279105513Sphk errx(1, "rijndael_blockEncrypt=%d", error); 280105513Sphk} 281105513Sphk 282105513Sphkstatic void 283105513Sphkcmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 284105513Sphk{ 285112877Sphk int ffd; 286112877Sphk u_char buf[16]; 287112877Sphk struct gctl_req *r; 288112877Sphk const char *errstr; 289105513Sphk 290115624Sphk r = gctl_get_handle(); 291115624Sphk gctl_ro_param(r, "verb", -1, "create geom"); 292112877Sphk gctl_ro_param(r, "class", -1, "BDE"); 293112877Sphk gctl_ro_param(r, "provider", -1, dest); 294112877Sphk gctl_ro_param(r, "pass", SHA512_DIGEST_LENGTH, sc->sha2); 295105513Sphk if (lfile != NULL) { 296105513Sphk ffd = open(lfile, O_RDONLY, 0); 297105513Sphk if (ffd < 0) 298111296Stjr err(1, "%s", lfile); 299112877Sphk read(ffd, buf, 16); 300112877Sphk gctl_ro_param(r, "key", 16, buf); 301105513Sphk close(ffd); 302105513Sphk } 303112877Sphk /* gctl_dump(r, stdout); */ 304112877Sphk errstr = gctl_issue(r); 305112877Sphk if (errstr != NULL) 306125386Sdes errx(1, "Attach to %s failed: %s", dest, errstr); 307105513Sphk 308105513Sphk exit (0); 309105513Sphk} 310105513Sphk 311105513Sphkstatic void 312105541Sphkcmd_detach(const char *dest) 313105513Sphk{ 314112877Sphk struct gctl_req *r; 315112877Sphk const char *errstr; 316112877Sphk char buf[BUFSIZ]; 317105513Sphk 318115624Sphk r = gctl_get_handle(); 319115624Sphk gctl_ro_param(r, "verb", -1, "destroy geom"); 320112877Sphk gctl_ro_param(r, "class", -1, "BDE"); 321112877Sphk sprintf(buf, "%s.bde", dest); 322112877Sphk gctl_ro_param(r, "geom", -1, buf); 323112877Sphk /* gctl_dump(r, stdout); */ 324112877Sphk errstr = gctl_issue(r); 325112877Sphk if (errstr != NULL) 326125386Sdes errx(1, "Detach of %s failed: %s", dest, errstr); 327105513Sphk exit (0); 328105513Sphk} 329105513Sphk 330105513Sphkstatic void 331106407Sphkcmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey) 332105513Sphk{ 333105513Sphk int error; 334105513Sphk int ffd; 335105513Sphk u_char keyloc[16]; 336106407Sphk u_int sectorsize; 337106407Sphk off_t mediasize; 338106407Sphk struct stat st; 339105513Sphk 340106407Sphk error = ioctl(dfd, DIOCGSECTORSIZE, §orsize); 341106407Sphk if (error) 342106407Sphk sectorsize = 512; 343106407Sphk error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize); 344106407Sphk if (error) { 345106407Sphk error = fstat(dfd, &st); 346106407Sphk if (error == 0 && S_ISREG(st.st_mode)) 347106407Sphk mediasize = st.st_size; 348106407Sphk else 349106407Sphk error = ENOENT; 350106407Sphk } 351106407Sphk if (error) 352106407Sphk mediasize = (off_t)-1; 353105513Sphk if (l_opt != NULL) { 354105513Sphk ffd = open(l_opt, O_RDONLY, 0); 355105513Sphk if (ffd < 0) 356111296Stjr err(1, "%s", l_opt); 357105513Sphk read(ffd, keyloc, sizeof keyloc); 358105513Sphk close(ffd); 359105513Sphk } else { 360105513Sphk memset(keyloc, 0, sizeof keyloc); 361105513Sphk } 362105513Sphk 363106407Sphk error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize, 364106407Sphk sectorsize, nkey); 365105513Sphk if (error == ENOENT) 366105513Sphk errx(1, "Lock was destroyed."); 367105513Sphk if (error == ESRCH) 368105513Sphk errx(1, "Lock was nuked."); 369105513Sphk if (error == ENOTDIR) 370105513Sphk errx(1, "Lock not found"); 371105513Sphk if (error != 0) 372105513Sphk errx(1, "Error %d decrypting lock", error); 373105513Sphk if (nkey) 374105513Sphk printf("Opened with key %u\n", *nkey); 375105513Sphk return; 376105513Sphk} 377105513Sphk 378105513Sphkstatic void 379105513Sphkcmd_nuke(struct g_bde_key *gl, int dfd , int key) 380105513Sphk{ 381105513Sphk int i; 382105513Sphk u_char *sbuf; 383105513Sphk off_t offset, offset2; 384105513Sphk 385105513Sphk sbuf = malloc(gl->sectorsize); 386105513Sphk memset(sbuf, 0, gl->sectorsize); 387105513Sphk offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 388105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 389105513Sphk if (offset2 != offset) 390105513Sphk err(1, "lseek"); 391105513Sphk i = write(dfd, sbuf, gl->sectorsize); 392125473Spjd free(sbuf); 393105513Sphk if (i != (int)gl->sectorsize) 394105513Sphk err(1, "write"); 395105513Sphk printf("Nuked key %d\n", key); 396105513Sphk} 397105513Sphk 398105513Sphkstatic void 399105513Sphkcmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 400105513Sphk{ 401105513Sphk int i, ffd; 402105513Sphk uint64_t off[2]; 403105513Sphk u_char keyloc[16]; 404105513Sphk u_char *sbuf, *q; 405105513Sphk off_t offset, offset2; 406105513Sphk 407105513Sphk sbuf = malloc(gl->sectorsize); 408105513Sphk /* 409105513Sphk * Find the byte-offset in the lock sector where we will put the lock 410105513Sphk * data structure. We can put it any random place as long as the 411105513Sphk * structure fits. 412105513Sphk */ 413105513Sphk for(;;) { 414105513Sphk random_bits(off, sizeof off); 415105513Sphk off[0] &= (gl->sectorsize - 1); 416105513Sphk if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 417105513Sphk continue; 418105513Sphk break; 419105513Sphk } 420105513Sphk 421105513Sphk /* Add the sector offset in bytes */ 422105513Sphk off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 423105513Sphk gl->lsector[key] = off[0]; 424105513Sphk 425120876Sphk i = g_bde_keyloc_encrypt(sc->sha2, off[0], off[1], keyloc); 426105513Sphk if (i) 427105513Sphk errx(1, "g_bde_keyloc_encrypt()"); 428105513Sphk if (l_opt != NULL) { 429105513Sphk ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 430105513Sphk if (ffd < 0) 431111296Stjr err(1, "%s", l_opt); 432105513Sphk write(ffd, keyloc, sizeof keyloc); 433105513Sphk close(ffd); 434120876Sphk } else if (gl->flags & GBDE_F_SECT0) { 435105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 436105513Sphk if (offset2 != 0) 437105513Sphk err(1, "lseek"); 438105513Sphk i = read(dfd, sbuf, gl->sectorsize); 439105513Sphk if (i != (int)gl->sectorsize) 440105513Sphk err(1, "read"); 441105513Sphk memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 442105513Sphk offset2 = lseek(dfd, 0, SEEK_SET); 443105513Sphk if (offset2 != 0) 444105513Sphk err(1, "lseek"); 445105513Sphk i = write(dfd, sbuf, gl->sectorsize); 446105513Sphk if (i != (int)gl->sectorsize) 447105513Sphk err(1, "write"); 448105513Sphk } else { 449105513Sphk errx(1, "No -L option and no space in sector 0 for lockfile"); 450105513Sphk } 451105513Sphk 452105513Sphk /* Allocate a sectorbuffer and fill it with random junk */ 453105513Sphk if (sbuf == NULL) 454105513Sphk err(1, "malloc"); 455105513Sphk random_bits(sbuf, gl->sectorsize); 456105513Sphk 457105513Sphk /* Fill random bits in the spare field */ 458105513Sphk random_bits(gl->spare, sizeof(gl->spare)); 459105513Sphk 460105513Sphk /* Encode the structure where we want it */ 461105513Sphk q = sbuf + (off[0] % gl->sectorsize); 462120876Sphk i = g_bde_encode_lock(sc->sha2, gl, q); 463106407Sphk if (i < 0) 464106407Sphk errx(1, "programming error encoding lock"); 465105513Sphk 466106407Sphk encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); 467105513Sphk offset = gl->lsector[key] & ~(gl->sectorsize - 1); 468105513Sphk offset2 = lseek(dfd, offset, SEEK_SET); 469105513Sphk if (offset2 != offset) 470105513Sphk err(1, "lseek"); 471105513Sphk i = write(dfd, sbuf, gl->sectorsize); 472105513Sphk if (i != (int)gl->sectorsize) 473105513Sphk err(1, "write"); 474125473Spjd free(sbuf); 475108052Sphk#if 0 476135035Sphk printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 477108052Sphk printf("s0 = %jd\n", (intmax_t)gl->sector0); 478108052Sphk printf("sN = %jd\n", (intmax_t)gl->sectorN); 479108052Sphk printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]); 480108052Sphk printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]); 481108052Sphk printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]); 482108052Sphk printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]); 483108052Sphk printf("k = %jd\n", (intmax_t)gl->keyoffset); 484108052Sphk printf("ss = %jd\n", (intmax_t)gl->sectorsize); 485108052Sphk#endif 486105513Sphk} 487105513Sphk 488105513Sphkstatic void 489105513Sphkcmd_destroy(struct g_bde_key *gl, int nkey) 490105513Sphk{ 491105513Sphk int i; 492105513Sphk 493105513Sphk bzero(&gl->sector0, sizeof gl->sector0); 494105513Sphk bzero(&gl->sectorN, sizeof gl->sectorN); 495105513Sphk bzero(&gl->keyoffset, sizeof gl->keyoffset); 496105513Sphk bzero(&gl->flags, sizeof gl->flags); 497106227Sphk bzero(gl->mkey, sizeof gl->mkey); 498105513Sphk for (i = 0; i < G_BDE_MAXKEYS; i++) 499105513Sphk if (i != nkey) 500105513Sphk gl->lsector[i] = ~0; 501105513Sphk} 502105513Sphk 503108052Sphkstatic int 504108052Sphksorthelp(const void *a, const void *b) 505108052Sphk{ 506135035Sphk const uint64_t *oa, *ob; 507108052Sphk 508108052Sphk oa = a; 509108052Sphk ob = b; 510131101Ssobomax if (*oa > *ob) 511131101Ssobomax return 1; 512131101Ssobomax if (*oa < *ob) 513131101Ssobomax return -1; 514131101Ssobomax return 0; 515108052Sphk} 516108052Sphk 517105513Sphkstatic void 518105513Sphkcmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 519105513Sphk{ 520105513Sphk int i; 521105513Sphk u_char *buf; 522105513Sphk unsigned sector_size; 523105513Sphk uint64_t first_sector; 524105513Sphk uint64_t last_sector; 525105513Sphk uint64_t total_sectors; 526105513Sphk off_t off, off2; 527105513Sphk unsigned nkeys; 528105513Sphk const char *p; 529105513Sphk char *q, cbuf[BUFSIZ]; 530105513Sphk unsigned u, u2; 531105513Sphk uint64_t o; 532105513Sphk properties params; 533105513Sphk 534105513Sphk bzero(gl, sizeof *gl); 535105513Sphk if (f_opt != NULL) { 536105513Sphk i = open(f_opt, O_RDONLY); 537105513Sphk if (i < 0) 538111296Stjr err(1, "%s", f_opt); 539105513Sphk params = properties_read(i); 540105513Sphk close (i); 541125477Sdes } else if (i_opt) { 542105513Sphk /* XXX: Polish */ 543125477Sdes asprintf(&q, "%stemp.XXXXXXXXXX", _PATH_TMP); 544125477Sdes if (q == NULL) 545125477Sdes err(1, "asprintf"); 546105513Sphk i = mkstemp(q); 547105513Sphk if (i < 0) 548111296Stjr err(1, "%s", q); 549105513Sphk write(i, template, strlen(template)); 550105513Sphk close (i); 551125477Sdes p = getenv("EDITOR"); 552125477Sdes if (p == NULL) 553125477Sdes p = "vi"; 554125477Sdes if (snprintf(cbuf, sizeof(cbuf), "%s %s\n", p, q) >= 555125477Sdes (ssize_t)sizeof(cbuf)) { 556125477Sdes unlink(q); 557125477Sdes errx(1, "EDITOR is too long"); 558105513Sphk } 559125477Sdes system(cbuf); 560105513Sphk i = open(q, O_RDONLY); 561105513Sphk if (i < 0) 562111296Stjr err(1, "%s", f_opt); 563105513Sphk params = properties_read(i); 564105513Sphk close (i); 565105513Sphk unlink(q); 566125473Spjd free(q); 567125477Sdes } else { 568125477Sdes /* XXX: Hack */ 569125477Sdes i = open(_PATH_DEVNULL, O_RDONLY); 570125477Sdes if (i < 0) 571125477Sdes err(1, "%s", _PATH_DEVNULL); 572125477Sdes params = properties_read(i); 573125477Sdes close (i); 574105513Sphk } 575105513Sphk 576105513Sphk /* <sector_size> */ 577105513Sphk p = property_find(params, "sector_size"); 578105513Sphk i = ioctl(dfd, DIOCGSECTORSIZE, &u); 579105513Sphk if (p != NULL) { 580105513Sphk sector_size = strtoul(p, &q, 0); 581105513Sphk if (!*p || *q) 582105513Sphk errx(1, "sector_size not a proper number"); 583108020Sphk } else if (i == 0) { 584108020Sphk sector_size = u; 585108020Sphk } else { 586108020Sphk errx(1, "Missing sector_size property"); 587105513Sphk } 588105513Sphk if (sector_size & (sector_size - 1)) 589105513Sphk errx(1, "sector_size not a power of 2"); 590105513Sphk if (sector_size < 512) 591105513Sphk errx(1, "sector_size is smaller than 512"); 592105513Sphk buf = malloc(sector_size); 593105513Sphk if (buf == NULL) 594105513Sphk err(1, "Failed to malloc sector buffer"); 595105513Sphk gl->sectorsize = sector_size; 596105513Sphk 597105513Sphk i = ioctl(dfd, DIOCGMEDIASIZE, &off); 598105513Sphk if (i == 0) { 599105513Sphk first_sector = 0; 600105513Sphk total_sectors = off / sector_size; 601105513Sphk last_sector = total_sectors - 1; 602105513Sphk } else { 603105513Sphk first_sector = 0; 604105513Sphk last_sector = 0; 605105513Sphk total_sectors = 0; 606105513Sphk } 607105513Sphk 608105513Sphk /* <first_sector> */ 609105513Sphk p = property_find(params, "first_sector"); 610105513Sphk if (p != NULL) { 611105513Sphk first_sector = strtoul(p, &q, 0); 612105513Sphk if (!*p || *q) 613105513Sphk errx(1, "first_sector not a proper number"); 614105513Sphk } 615105513Sphk 616105513Sphk /* <last_sector> */ 617105513Sphk p = property_find(params, "last_sector"); 618105513Sphk if (p != NULL) { 619105513Sphk last_sector = strtoul(p, &q, 0); 620105513Sphk if (!*p || *q) 621105513Sphk errx(1, "last_sector not a proper number"); 622105513Sphk if (last_sector <= first_sector) 623105513Sphk errx(1, "last_sector not larger than first_sector"); 624105513Sphk total_sectors = last_sector + 1; 625105513Sphk } 626105513Sphk 627105513Sphk /* <total_sectors> */ 628105513Sphk p = property_find(params, "total_sectors"); 629105513Sphk if (p != NULL) { 630105513Sphk total_sectors = strtoul(p, &q, 0); 631105513Sphk if (!*p || *q) 632105513Sphk errx(1, "total_sectors not a proper number"); 633125387Sdes if (last_sector == 0) 634105513Sphk last_sector = first_sector + total_sectors - 1; 635105513Sphk } 636105513Sphk 637105513Sphk if (l_opt == NULL && first_sector != 0) 638105513Sphk errx(1, "No -L new-lockfile argument and first_sector != 0"); 639105513Sphk else if (l_opt == NULL) { 640105513Sphk first_sector++; 641105513Sphk total_sectors--; 642120876Sphk gl->flags |= GBDE_F_SECT0; 643105513Sphk } 644108060Sphk gl->sector0 = first_sector * gl->sectorsize; 645105513Sphk 646105513Sphk if (total_sectors != (last_sector - first_sector) + 1) 647105513Sphk errx(1, "total_sectors disagree with first_sector and last_sector"); 648105513Sphk if (total_sectors == 0) 649105513Sphk errx(1, "missing last_sector or total_sectors"); 650105513Sphk 651105513Sphk gl->sectorN = (last_sector + 1) * gl->sectorsize; 652105513Sphk 653105513Sphk /* Find a random keyoffset */ 654105513Sphk random_bits(&o, sizeof o); 655105513Sphk o %= (gl->sectorN - gl->sector0); 656105513Sphk o &= ~(gl->sectorsize - 1); 657105513Sphk gl->keyoffset = o; 658105513Sphk 659105513Sphk /* <number_of_keys> */ 660105513Sphk p = property_find(params, "number_of_keys"); 661125477Sdes if (p != NULL) { 662125477Sdes nkeys = strtoul(p, &q, 0); 663125477Sdes if (!*p || *q) 664125477Sdes errx(1, "number_of_keys not a proper number"); 665125477Sdes if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 666125477Sdes errx(1, "number_of_keys out of range"); 667125477Sdes } else { 668125477Sdes nkeys = 4; 669125477Sdes } 670105513Sphk for (u = 0; u < nkeys; u++) { 671105513Sphk for(;;) { 672105513Sphk do { 673105513Sphk random_bits(&o, sizeof o); 674105513Sphk o %= gl->sectorN; 675105513Sphk o &= ~(gl->sectorsize - 1); 676105513Sphk } while(o < gl->sector0); 677105513Sphk for (u2 = 0; u2 < u; u2++) 678105513Sphk if (o == gl->lsector[u2]) 679105513Sphk break; 680105513Sphk if (u2 < u) 681105513Sphk continue; 682105513Sphk break; 683105513Sphk } 684105513Sphk gl->lsector[u] = o; 685125387Sdes } 686105513Sphk for (; u < G_BDE_MAXKEYS; u++) { 687125387Sdes do 688105513Sphk random_bits(&o, sizeof o); 689105513Sphk while (o < gl->sectorN); 690105513Sphk gl->lsector[u] = o; 691105513Sphk } 692108052Sphk qsort(gl->lsector, G_BDE_MAXKEYS, sizeof gl->lsector[0], sorthelp); 693105513Sphk 694105513Sphk /* Flush sector zero if we use it for lockfile data */ 695120876Sphk if (gl->flags & GBDE_F_SECT0) { 696105513Sphk off2 = lseek(dfd, 0, SEEK_SET); 697105513Sphk if (off2 != 0) 698105513Sphk err(1, "lseek(2) to sector 0"); 699105513Sphk random_bits(buf, sector_size); 700105513Sphk i = write(dfd, buf, sector_size); 701105513Sphk if (i != (int)sector_size) 702105513Sphk err(1, "write sector 0"); 703105513Sphk } 704105513Sphk 705105513Sphk /* <random_flush> */ 706105513Sphk p = property_find(params, "random_flush"); 707105513Sphk if (p != NULL) { 708105513Sphk off = first_sector * sector_size; 709105513Sphk off2 = lseek(dfd, off, SEEK_SET); 710105513Sphk if (off2 != off) 711105513Sphk err(1, "lseek(2) to first_sector"); 712105513Sphk off2 = last_sector * sector_size; 713105513Sphk while (off <= off2) { 714105513Sphk random_bits(buf, sector_size); 715105513Sphk i = write(dfd, buf, sector_size); 716105513Sphk if (i != (int)sector_size) 717105513Sphk err(1, "write to $device_name"); 718105513Sphk off += sector_size; 719105513Sphk } 720105513Sphk } 721105513Sphk 722106227Sphk random_bits(gl->mkey, sizeof gl->mkey); 723106227Sphk random_bits(gl->salt, sizeof gl->salt); 724125387Sdes 725105513Sphk return; 726105513Sphk} 727105513Sphk 728105513Sphkstatic enum action { 729105513Sphk ACT_HUH, 730105541Sphk ACT_ATTACH, ACT_DETACH, 731105513Sphk ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 732105513Sphk} action; 733105513Sphk 734105513Sphkint 735105513Sphkmain(int argc, char **argv) 736105513Sphk{ 737105513Sphk const char *opts; 738155453Scperciva const char *k_opt, *K_opt; 739105513Sphk const char *l_opt, *L_opt; 740105513Sphk const char *p_opt, *P_opt; 741105513Sphk const char *f_opt; 742107455Sphk char *dest; 743107455Sphk int i_opt, n_opt, ch, dfd, doopen; 744107455Sphk u_int nkey; 745105513Sphk int i; 746107455Sphk char *q, buf[BUFSIZ]; 747105513Sphk struct g_bde_key *gl; 748105513Sphk struct g_bde_softc sc; 749105513Sphk 750105513Sphk if (argc < 3) 751141769Sru usage(); 752105513Sphk 753209052Suqs if (modfind("g_bde") < 0) { 754141214Spjd /* need to load the gbde module */ 755141214Spjd if (kldload(GBDEMOD) < 0 || modfind("g_bde") < 0) 756141769Sru err(1, GBDEMOD ": Kernel module not available"); 757141214Spjd } 758105513Sphk doopen = 0; 759105513Sphk if (!strcmp(argv[1], "attach")) { 760105513Sphk action = ACT_ATTACH; 761155453Scperciva opts = "k:l:p:"; 762105541Sphk } else if (!strcmp(argv[1], "detach")) { 763105541Sphk action = ACT_DETACH; 764105513Sphk opts = ""; 765105513Sphk } else if (!strcmp(argv[1], "init")) { 766105513Sphk action = ACT_INIT; 767105513Sphk doopen = 1; 768155453Scperciva opts = "f:iK:L:P:"; 769105513Sphk } else if (!strcmp(argv[1], "setkey")) { 770105513Sphk action = ACT_SETKEY; 771105513Sphk doopen = 1; 772155453Scperciva opts = "k:K:l:L:n:p:P:"; 773105513Sphk } else if (!strcmp(argv[1], "destroy")) { 774105513Sphk action = ACT_DESTROY; 775105513Sphk doopen = 1; 776155453Scperciva opts = "k:l:p:"; 777105513Sphk } else if (!strcmp(argv[1], "nuke")) { 778105513Sphk action = ACT_NUKE; 779105513Sphk doopen = 1; 780155453Scperciva opts = "k:l:n:p:"; 781105513Sphk } else { 782141769Sru usage(); 783105513Sphk } 784105513Sphk argc--; 785105513Sphk argv++; 786105513Sphk 787107455Sphk dest = strdup(argv[1]); 788105513Sphk argc--; 789105513Sphk argv++; 790105513Sphk 791105513Sphk p_opt = NULL; 792105513Sphk P_opt = NULL; 793155453Scperciva k_opt = NULL; 794155453Scperciva K_opt = NULL; 795105513Sphk l_opt = NULL; 796105513Sphk L_opt = NULL; 797105513Sphk f_opt = NULL; 798105513Sphk n_opt = 0; 799105513Sphk i_opt = 0; 800105513Sphk 801105513Sphk while((ch = getopt(argc, argv, opts)) != -1) 802105513Sphk switch (ch) { 803105513Sphk case 'f': 804105513Sphk f_opt = optarg; 805105513Sphk break; 806105513Sphk case 'i': 807105513Sphk i_opt = !i_opt; 808264808Sbrueffer break; 809155453Scperciva case 'k': 810155453Scperciva k_opt = optarg; 811155453Scperciva break; 812155453Scperciva case 'K': 813155453Scperciva K_opt = optarg; 814155453Scperciva break; 815105513Sphk case 'l': 816105513Sphk l_opt = optarg; 817105513Sphk break; 818105513Sphk case 'L': 819105513Sphk L_opt = optarg; 820105513Sphk break; 821141216Spjd case 'n': 822141216Spjd n_opt = strtoul(optarg, &q, 0); 823141216Spjd if (!*optarg || *q) 824141769Sru errx(1, "-n argument not numeric"); 825141216Spjd if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 826141769Sru errx(1, "-n argument out of range"); 827141216Spjd break; 828105513Sphk case 'p': 829105513Sphk p_opt = optarg; 830105513Sphk break; 831105513Sphk case 'P': 832105513Sphk P_opt = optarg; 833105513Sphk break; 834105513Sphk default: 835141769Sru usage(); 836105513Sphk } 837105513Sphk 838105513Sphk if (doopen) { 839141198Spjd dfd = open(dest, O_RDWR); 840141198Spjd if (dfd < 0 && dest[0] != '/') { 841111298Stjr if (snprintf(buf, sizeof(buf), "%s%s", 842111298Stjr _PATH_DEV, dest) >= (ssize_t)sizeof(buf)) 843111298Stjr errno = ENAMETOOLONG; 844111298Stjr else 845141198Spjd dfd = open(buf, O_RDWR); 846107455Sphk } 847105513Sphk if (dfd < 0) 848111296Stjr err(1, "%s", dest); 849107455Sphk } else { 850107455Sphk if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 851107455Sphk strcpy(dest, dest + strlen(_PATH_DEV)); 852105513Sphk } 853105513Sphk 854105513Sphk memset(&sc, 0, sizeof sc); 855107982Sphk sc.consumer = (void *)&dfd; 856105513Sphk gl = &sc.key; 857105513Sphk switch(action) { 858105513Sphk case ACT_ATTACH: 859155453Scperciva setup_passphrase(&sc, 0, p_opt, k_opt); 860105513Sphk cmd_attach(&sc, dest, l_opt); 861105513Sphk break; 862105541Sphk case ACT_DETACH: 863105541Sphk cmd_detach(dest); 864105513Sphk break; 865105513Sphk case ACT_INIT: 866105513Sphk cmd_init(gl, dfd, f_opt, i_opt, L_opt); 867155453Scperciva setup_passphrase(&sc, 1, P_opt, K_opt); 868105513Sphk cmd_write(gl, &sc, dfd, 0, L_opt); 869105513Sphk break; 870105513Sphk case ACT_SETKEY: 871155453Scperciva setup_passphrase(&sc, 0, p_opt, k_opt); 872105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 873105513Sphk if (n_opt == 0) 874105513Sphk n_opt = nkey + 1; 875155453Scperciva setup_passphrase(&sc, 1, P_opt, K_opt); 876105513Sphk cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 877105513Sphk break; 878105513Sphk case ACT_DESTROY: 879155453Scperciva setup_passphrase(&sc, 0, p_opt, k_opt); 880105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 881105513Sphk cmd_destroy(gl, nkey); 882105513Sphk reset_passphrase(&sc); 883105513Sphk cmd_write(gl, &sc, dfd, nkey, l_opt); 884105513Sphk break; 885105513Sphk case ACT_NUKE: 886155453Scperciva setup_passphrase(&sc, 0, p_opt, k_opt); 887105513Sphk cmd_open(&sc, dfd, l_opt, &nkey); 888105513Sphk if (n_opt == 0) 889105513Sphk n_opt = nkey + 1; 890105513Sphk if (n_opt == -1) { 891105513Sphk for(i = 0; i < G_BDE_MAXKEYS; i++) 892105513Sphk cmd_nuke(gl, dfd, i); 893105513Sphk } else { 894105513Sphk cmd_nuke(gl, dfd, n_opt - 1); 895105513Sphk } 896105513Sphk break; 897105513Sphk default: 898141769Sru errx(1, "internal error"); 899105513Sphk } 900105513Sphk 901105513Sphk return(0); 902105513Sphk} 903