gbde.c revision 125477
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 2002 Poul-Henning Kamp 31590Srgrimes * Copyright (c) 2002 Networks Associates Technology, Inc. 41590Srgrimes * All rights reserved. 51590Srgrimes * 61590Srgrimes * This software was developed for the FreeBSD Project by Poul-Henning Kamp 71590Srgrimes * and NAI Labs, the Security Research Division of Network Associates, Inc. 81590Srgrimes * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 91590Srgrimes * DARPA CHATS research program. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30114594Sobrien * SUCH DAMAGE. 311590Srgrimes * 3228564Scharnier * $FreeBSD: head/sbin/gbde/gbde.c 125477 2004-02-05 10:57:29Z des $ 331590Srgrimes * 341590Srgrimes * XXX: Future stuff 351590Srgrimes * 361590Srgrimes * Replace the template file options (-i & -f) with command-line variables 371590Srgrimes * "-v property=foo" 381590Srgrimes * 3996438Smike * Introduce -e, extra entropy source (XOR with /dev/random) 4028564Scharnier * 4196438Smike * Introduce -E, alternate entropy source (instead of /dev/random) 4296438Smike * 4396438Smike * Introduce -i take IV from keyboard or 441590Srgrimes * 451590Srgrimes * Introduce -I take IV from file/cmd 461590Srgrimes * 471590Srgrimes * Introduce -m/-M store encrypted+encoded masterkey in file 481590Srgrimes * 491590Srgrimes * Introduce -k/-K get pass-phrase part from file/cmd 501590Srgrimes * 5191661Sjmallett * Introduce -d add more dest-devices to worklist. 521590Srgrimes * 531590Srgrimes * Add key-option: selfdestruct bit. 5491661Sjmallett * 5591661Sjmallett * New/changed verbs: 56214010Sedwin * "onetime" attach with onetime nonstored locksector 5728564Scharnier * "key"/"unkey" to blast memory copy of key without orphaning 58106275Sfanf * "nuke" blow away everything attached, crash/halt/power-off if possible. 59106275Sfanf * "blast" destroy all copies of the masterkey 60111588Sfanf * "destroy" destroy one copy of the masterkey 611590Srgrimes * "backup"/"restore" of masterkey sectors. 6291661Sjmallett * 631590Srgrimes * Make all verbs work on both attached/detached devices. 6428564Scharnier * 651590Srgrimes */ 6628564Scharnier 671590Srgrimes#include <sys/types.h> 68106280Sfanf#include <sys/queue.h> 69106280Sfanf#include <sys/mutex.h> 70111588Sfanf#include <md5.h> 711590Srgrimes#include <readpassphrase.h> 72106280Sfanf#include <string.h> 73106280Sfanf#include <stdint.h> 74106280Sfanf#include <unistd.h> 75106280Sfanf#include <fcntl.h> 76106280Sfanf#include <paths.h> 7719078Swosch#include <strings.h> 781590Srgrimes#include <stdlib.h> 7996386Salfred#include <err.h> 801590Srgrimes#include <stdio.h> 8119078Swosch#include <libutil.h> 821590Srgrimes#include <libgeom.h> 83111588Sfanf#include <sys/errno.h> 84111588Sfanf#include <sys/disk.h> 85111588Sfanf#include <sys/stat.h> 86111588Sfanf#include <crypto/rijndael/rijndael.h> 87214002Sedwin#include <crypto/sha2/sha2.h> 8819078Swosch#include <sys/param.h> 89111588Sfanf#include <sys/linker.h> 9089882Smike 9119078Swosch#define GBDEMOD "geom_bde" 9219078Swosch#define KASSERT(foo, bar) do { if(!(foo)) { warn bar ; exit (1); } } while (0) 9332780Swosch 9432780Swosch#include <geom/geom.h> 9532780Swosch#include <geom/bde/g_bde.h> 96111588Sfanf 97111588Sfanfextern const char template[]; 98111588Sfanf 9989882Smike 100111588Sfanf#if 0 10189882Smikestatic void 10289882Smikeg_hexdump(void *ptr, int length) 10389882Smike{ 10489882Smike int i, j, k; 10589882Smike unsigned char *cp; 10619078Swosch 10789882Smike cp = ptr; 10889882Smike for (i = 0; i < length; i+= 16) { 10919078Swosch printf("%04x ", i); 11019078Swosch for (j = 0; j < 16; j++) { 111111588Sfanf k = i + j; 112111588Sfanf if (k < length) 113111588Sfanf printf(" %02x", cp[k]); 114111588Sfanf else 115111588Sfanf printf(" "); 11632780Swosch } 11789882Smike printf(" |"); 11889882Smike for (j = 0; j < 16; j++) { 11932780Swosch k = i + j; 12032780Swosch if (k >= length) 12119078Swosch printf(" "); 12228564Scharnier else if (cp[k] >= ' ' && cp[k] <= '~') 12319078Swosch printf("%c", cp[k]); 12419078Swosch else 125214002Sedwin printf("."); 126214002Sedwin } 12719078Swosch printf("|\n"); 128214002Sedwin } 1291590Srgrimes} 1301590Srgrimes#endif 131106280Sfanf 132106274Sfanfstatic void __dead2 13328564Scharnierusage(const char *reason) 1341590Srgrimes{ 1351590Srgrimes const char *p; 1361590Srgrimes 1371590Srgrimes p = getprogname(); 138106274Sfanf fprintf(stderr, "Usage error: %s", reason); 1391590Srgrimes fprintf(stderr, "Usage:\n"); 1401590Srgrimes fprintf(stderr, "\t%s attach dest [-l lockfile]\n", p); 141106280Sfanf fprintf(stderr, "\t%s detach dest\n", p); 142106274Sfanf fprintf(stderr, "\t%s init /dev/dest [-i] [-f filename] [-L lockfile]\n", p); 1431590Srgrimes fprintf(stderr, "\t%s setkey dest [-n key] [-l lockfile] [-L lockfile]\n", p); 1441590Srgrimes fprintf(stderr, "\t%s destroy dest [-n key] [-l lockfile] [-L lockfile]\n", p); 1451590Srgrimes exit (1); 1461590Srgrimes} 1471590Srgrimes 148106280Sfanfvoid * 14996438Smikeg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 1501590Srgrimes{ 151103200Sfanf void *p; 15219078Swosch int fd, i; 153111588Sfanf off_t o2; 154111588Sfanf 155111588Sfanf p = malloc(length); 156111588Sfanf if (p == NULL) 157111588Sfanf err(1, "malloc"); 158111588Sfanf fd = *(int *)cp; 159111588Sfanf o2 = lseek(fd, offset, SEEK_SET); 160111588Sfanf if (o2 != offset) 161111588Sfanf err(1, "lseek"); 162103200Sfanf i = read(fd, p, length); 163103200Sfanf if (i != length) 164106280Sfanf err(1, "read"); 165103200Sfanf if (error != NULL) 166103200Sfanf error = 0; 167103200Sfanf return (p); 168103200Sfanf} 169103200Sfanf 17019078Swoschstatic void 171103200Sfanfrandom_bits(void *p, u_int len) 172103200Sfanf{ 17319078Swosch static int fdr = -1; 17419078Swosch int i; 175106280Sfanf 176103200Sfanf if (fdr < 0) { 17719078Swosch fdr = open("/dev/urandom", O_RDONLY); 178111588Sfanf if (fdr < 0) 179106280Sfanf err(1, "/dev/urandom"); 180106280Sfanf } 181106280Sfanf 1821590Srgrimes i = read(fdr, p, len); 183103200Sfanf if (i != (int)len) 184214002Sedwin err(1, "read from /dev/urandom"); 1851590Srgrimes} 186103195Sfanf 1871590Srgrimes/* XXX: not nice */ 188103200Sfanfstatic u_char sha2[SHA512_DIGEST_LENGTH]; 189106274Sfanf 190103200Sfanfstatic void 191103200Sfanfreset_passphrase(struct g_bde_softc *sc) 192103200Sfanf{ 193103200Sfanf 194103200Sfanf memcpy(sc->sha2, sha2, SHA512_DIGEST_LENGTH); 195103200Sfanf} 196103200Sfanf 197103200Sfanfstatic void 198103200Sfanfsetup_passphrase(struct g_bde_softc *sc, int sure, const char *input) 199103200Sfanf{ 200103200Sfanf char buf1[BUFSIZ], buf2[BUFSIZ], *p; 201103200Sfanf 202103200Sfanf if (input != NULL) { 203103200Sfanf g_bde_hash_pass(sc, input, strlen(input)); 204103200Sfanf memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 205103200Sfanf return; 206103200Sfanf } 207103200Sfanf for (;;) { 208103200Sfanf p = readpassphrase( 209103200Sfanf sure ? "Enter new passphrase:" : "Enter passphrase: ", 210103200Sfanf buf1, sizeof buf1, 211103200Sfanf RPP_ECHO_OFF | RPP_REQUIRE_TTY); 21219078Swosch if (p == NULL) 213106280Sfanf err(1, "readpassphrase"); 214106280Sfanf 215106280Sfanf if (sure) { 216103200Sfanf p = readpassphrase("Reenter new passphrase: ", 21791661Sjmallett buf2, sizeof buf2, 218106280Sfanf RPP_ECHO_OFF | RPP_REQUIRE_TTY); 219106280Sfanf if (p == NULL) 2201590Srgrimes err(1, "readpassphrase"); 221106280Sfanf 222103200Sfanf if (strcmp(buf1, buf2)) { 223103200Sfanf printf("They didn't match.\n"); 224103200Sfanf continue; 225103200Sfanf } 226103200Sfanf } 227103200Sfanf if (strlen(buf1) < 3) { 228103200Sfanf printf("Too short passphrase.\n"); 229103200Sfanf continue; 230103200Sfanf } 23132780Swosch break; 232103200Sfanf } 233106280Sfanf g_bde_hash_pass(sc, buf1, strlen(buf1)); 234106280Sfanf memcpy(sha2, sc->sha2, SHA512_DIGEST_LENGTH); 235106280Sfanf} 236106280Sfanf 237106280Sfanfstatic void 238106280Sfanfencrypt_sector(void *d, int len, int klen, void *key) 239106280Sfanf{ 240106280Sfanf keyInstance ki; 241106280Sfanf cipherInstance ci; 242106280Sfanf int error; 243106280Sfanf 244106280Sfanf error = rijndael_cipherInit(&ci, MODE_CBC, NULL); 2451590Srgrimes if (error <= 0) 246112377Sfanf errx(1, "rijndael_cipherInit=%d", error); 247103200Sfanf error = rijndael_makeKey(&ki, DIR_ENCRYPT, klen, key); 248103200Sfanf if (error <= 0) 249103200Sfanf errx(1, "rijndael_makeKeY=%d", error); 250106280Sfanf error = rijndael_blockEncrypt(&ci, &ki, d, len * 8, d); 2511590Srgrimes if (error <= 0) 252106280Sfanf errx(1, "rijndael_blockEncrypt=%d", error); 253106280Sfanf} 2541590Srgrimes 255111586Sfanfstatic void 256111586Sfanfcmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) 257106275Sfanf{ 258106275Sfanf int ffd; 259214002Sedwin u_char buf[16]; 260106280Sfanf struct gctl_req *r; 261106275Sfanf const char *errstr; 262106280Sfanf 263106275Sfanf r = gctl_get_handle(); 264106275Sfanf gctl_ro_param(r, "verb", -1, "create geom"); 265106275Sfanf gctl_ro_param(r, "class", -1, "BDE"); 266106275Sfanf gctl_ro_param(r, "provider", -1, dest); 267106275Sfanf gctl_ro_param(r, "pass", SHA512_DIGEST_LENGTH, sc->sha2); 268106275Sfanf if (lfile != NULL) { 269106280Sfanf ffd = open(lfile, O_RDONLY, 0); 270106275Sfanf if (ffd < 0) 271106280Sfanf err(1, "%s", lfile); 272106275Sfanf read(ffd, buf, 16); 273106275Sfanf gctl_ro_param(r, "key", 16, buf); 274106280Sfanf close(ffd); 275106275Sfanf } 276106275Sfanf /* gctl_dump(r, stdout); */ 277106275Sfanf errstr = gctl_issue(r); 278106275Sfanf if (errstr != NULL) 279106275Sfanf errx(1, "Attach to %s failed: %s", dest, errstr); 280106275Sfanf 281106275Sfanf exit (0); 282106280Sfanf} 283106275Sfanf 284106275Sfanfstatic void 285106275Sfanfcmd_detach(const char *dest) 286106280Sfanf{ 287106275Sfanf struct gctl_req *r; 288103200Sfanf const char *errstr; 289106280Sfanf char buf[BUFSIZ]; 290106280Sfanf 291106280Sfanf r = gctl_get_handle(); 292103197Sfanf gctl_ro_param(r, "verb", -1, "destroy geom"); 29332780Swosch gctl_ro_param(r, "class", -1, "BDE"); 2941590Srgrimes sprintf(buf, "%s.bde", dest); 2951590Srgrimes gctl_ro_param(r, "geom", -1, buf); 296103203Sfanf /* gctl_dump(r, stdout); */ 297106280Sfanf errstr = gctl_issue(r); 298106280Sfanf if (errstr != NULL) 299106280Sfanf errx(1, "Detach of %s failed: %s", dest, errstr); 300106280Sfanf exit (0); 301103203Sfanf} 302106280Sfanf 303111596Sfanfstatic void 304111596Sfanfcmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey) 305214002Sedwin{ 306111596Sfanf int error; 307111596Sfanf int ffd; 308111884Sfanf u_char keyloc[16]; 309111596Sfanf u_int sectorsize; 310111596Sfanf off_t mediasize; 311111596Sfanf struct stat st; 312111596Sfanf 313111596Sfanf error = ioctl(dfd, DIOCGSECTORSIZE, §orsize); 314111596Sfanf if (error) 315111596Sfanf sectorsize = 512; 316111596Sfanf error = ioctl(dfd, DIOCGMEDIASIZE, &mediasize); 317111596Sfanf if (error) { 318111596Sfanf error = fstat(dfd, &st); 319111596Sfanf if (error == 0 && S_ISREG(st.st_mode)) 320111596Sfanf mediasize = st.st_size; 321111596Sfanf else 322111596Sfanf error = ENOENT; 323111596Sfanf } 324111596Sfanf if (error) 325111596Sfanf mediasize = (off_t)-1; 326111596Sfanf if (l_opt != NULL) { 327111596Sfanf ffd = open(l_opt, O_RDONLY, 0); 328111596Sfanf if (ffd < 0) 329111596Sfanf err(1, "%s", l_opt); 330111596Sfanf read(ffd, keyloc, sizeof keyloc); 331111596Sfanf close(ffd); 332111596Sfanf } else { 333106280Sfanf memset(keyloc, 0, sizeof keyloc); 334106280Sfanf } 335106280Sfanf 336106280Sfanf error = g_bde_decrypt_lock(sc, sc->sha2, keyloc, mediasize, 337106280Sfanf sectorsize, nkey); 338106280Sfanf if (error == ENOENT) 3391590Srgrimes errx(1, "Lock was destroyed."); 3401590Srgrimes if (error == ESRCH) 341111596Sfanf errx(1, "Lock was nuked."); 342214002Sedwin if (error == ENOTDIR) 343214002Sedwin errx(1, "Lock not found"); 344214002Sedwin if (error != 0) 345214002Sedwin errx(1, "Error %d decrypting lock", error); 3461590Srgrimes if (nkey) 347103203Sfanf printf("Opened with key %u\n", *nkey); 348214002Sedwin return; 349214002Sedwin} 35022887Swosch 351103204Sfanfstatic void 352103204Sfanfcmd_nuke(struct g_bde_key *gl, int dfd , int key) 353106280Sfanf{ 354214002Sedwin int i; 355103204Sfanf u_char *sbuf; 35622887Swosch off_t offset, offset2; 3571590Srgrimes 358103210Smike sbuf = malloc(gl->sectorsize); 3591590Srgrimes memset(sbuf, 0, gl->sectorsize); 3601590Srgrimes offset = (gl->lsector[key] & ~(gl->sectorsize - 1)); 361111596Sfanf offset2 = lseek(dfd, offset, SEEK_SET); 362103210Smike if (offset2 != offset) 3631590Srgrimes err(1, "lseek"); 364103210Smike i = write(dfd, sbuf, gl->sectorsize); 365103210Smike free(sbuf); 366102890Sfanf if (i != (int)gl->sectorsize) 367214002Sedwin err(1, "write"); 368214002Sedwin printf("Nuked key %d\n", key); 36922887Swosch} 3701590Srgrimes 371106274Sfanfstatic void 3721590Srgrimescmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) 373106274Sfanf{ 3741590Srgrimes int i, ffd; 375106274Sfanf uint64_t off[2]; 376214002Sedwin u_char keyloc[16]; 377103210Smike u_char *sbuf, *q; 37822887Swosch off_t offset, offset2; 379103206Smike 3801590Srgrimes sbuf = malloc(gl->sectorsize); 381106274Sfanf /* 3821590Srgrimes * Find the byte-offset in the lock sector where we will put the lock 383103210Smike * data structure. We can put it any random place as long as the 384102890Sfanf * structure fits. 385214002Sedwin */ 386214002Sedwin for(;;) { 38722887Swosch random_bits(off, sizeof off); 3881590Srgrimes off[0] &= (gl->sectorsize - 1); 389106274Sfanf if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) 3901590Srgrimes continue; 391103210Smike break; 392102890Sfanf } 393214002Sedwin 394214002Sedwin /* Add the sector offset in bytes */ 3951590Srgrimes off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); 396106274Sfanf gl->lsector[key] = off[0]; 3971590Srgrimes 3981590Srgrimes i = g_bde_keyloc_encrypt(sc->sha2, off[0], off[1], keyloc); 3991590Srgrimes if (i) 400111596Sfanf errx(1, "g_bde_keyloc_encrypt()"); 401214002Sedwin if (l_opt != NULL) { 402214002Sedwin ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); 403214002Sedwin if (ffd < 0) 404214002Sedwin err(1, "%s", l_opt); 405214002Sedwin write(ffd, keyloc, sizeof keyloc); 406214002Sedwin close(ffd); 4071590Srgrimes } else if (gl->flags & GBDE_F_SECT0) { 4081590Srgrimes offset2 = lseek(dfd, 0, SEEK_SET); 4091590Srgrimes if (offset2 != 0) 410106280Sfanf err(1, "lseek"); 411106280Sfanf i = read(dfd, sbuf, gl->sectorsize); 41291661Sjmallett if (i != (int)gl->sectorsize) 413214010Sedwin err(1, "read"); 414214010Sedwin memcpy(sbuf + key * 16, keyloc, sizeof keyloc); 415106280Sfanf offset2 = lseek(dfd, 0, SEEK_SET); 416214010Sedwin if (offset2 != 0) 41791661Sjmallett err(1, "lseek"); 418214010Sedwin i = write(dfd, sbuf, gl->sectorsize); 419103203Sfanf if (i != (int)gl->sectorsize) 420214010Sedwin err(1, "write"); 421214010Sedwin } else { 422214010Sedwin errx(1, "No -L option and no space in sector 0 for lockfile"); 423214010Sedwin } 424214010Sedwin 425214010Sedwin /* Allocate a sectorbuffer and fill it with random junk */ 426214010Sedwin if (sbuf == NULL) 427103203Sfanf err(1, "malloc"); 428214010Sedwin random_bits(sbuf, gl->sectorsize); 429214010Sedwin 430214010Sedwin /* Fill random bits in the spare field */ 431214010Sedwin random_bits(gl->spare, sizeof(gl->spare)); 432214010Sedwin 433214010Sedwin /* Encode the structure where we want it */ 434214010Sedwin q = sbuf + (off[0] % gl->sectorsize); 435214010Sedwin i = g_bde_encode_lock(sc->sha2, gl, q); 436214010Sedwin if (i < 0) 437214010Sedwin errx(1, "programming error encoding lock"); 438214010Sedwin 439214010Sedwin encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); 440214010Sedwin offset = gl->lsector[key] & ~(gl->sectorsize - 1); 441214010Sedwin offset2 = lseek(dfd, offset, SEEK_SET); 442214010Sedwin if (offset2 != offset) 443214010Sedwin err(1, "lseek"); 444214010Sedwin i = write(dfd, sbuf, gl->sectorsize); 445214010Sedwin if (i != (int)gl->sectorsize) 446214010Sedwin err(1, "write"); 447106280Sfanf printf("Wrote key %d at %jd\n", key, (intmax_t)offset); 448214002Sedwin free(sbuf); 449111596Sfanf#if 0 450111596Sfanf printf("s0 = %jd\n", (intmax_t)gl->sector0); 451106280Sfanf printf("sN = %jd\n", (intmax_t)gl->sectorN); 452103203Sfanf printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]); 453214002Sedwin printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]); 45491661Sjmallett printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]); 45591661Sjmallett printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]); 45628564Scharnier printf("k = %jd\n", (intmax_t)gl->keyoffset); 45796438Smike printf("ss = %jd\n", (intmax_t)gl->sectorsize); 4581590Srgrimes#endif 459214002Sedwin} 46096943Sjmallett 461214002Sedwinstatic void 462214002Sedwincmd_destroy(struct g_bde_key *gl, int nkey) 463214002Sedwin{ 464214002Sedwin int i; 4651590Srgrimes 4661590Srgrimes bzero(&gl->sector0, sizeof gl->sector0); 467 bzero(&gl->sectorN, sizeof gl->sectorN); 468 bzero(&gl->keyoffset, sizeof gl->keyoffset); 469 bzero(&gl->flags, sizeof gl->flags); 470 bzero(gl->mkey, sizeof gl->mkey); 471 for (i = 0; i < G_BDE_MAXKEYS; i++) 472 if (i != nkey) 473 gl->lsector[i] = ~0; 474} 475 476static int 477sorthelp(const void *a, const void *b) 478{ 479 const off_t *oa, *ob; 480 481 oa = a; 482 ob = b; 483 return (*oa > *ob); 484} 485 486static void 487cmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt) 488{ 489 int i; 490 u_char *buf; 491 unsigned sector_size; 492 uint64_t first_sector; 493 uint64_t last_sector; 494 uint64_t total_sectors; 495 off_t off, off2; 496 unsigned nkeys; 497 const char *p; 498 char *q, cbuf[BUFSIZ]; 499 unsigned u, u2; 500 uint64_t o; 501 properties params; 502 503 bzero(gl, sizeof *gl); 504 if (f_opt != NULL) { 505 i = open(f_opt, O_RDONLY); 506 if (i < 0) 507 err(1, "%s", f_opt); 508 params = properties_read(i); 509 close (i); 510 } else if (i_opt) { 511 /* XXX: Polish */ 512 asprintf(&q, "%stemp.XXXXXXXXXX", _PATH_TMP); 513 if (q == NULL) 514 err(1, "asprintf"); 515 i = mkstemp(q); 516 if (i < 0) 517 err(1, "%s", q); 518 write(i, template, strlen(template)); 519 close (i); 520 p = getenv("EDITOR"); 521 if (p == NULL) 522 p = "vi"; 523 if (snprintf(cbuf, sizeof(cbuf), "%s %s\n", p, q) >= 524 (ssize_t)sizeof(cbuf)) { 525 unlink(q); 526 errx(1, "EDITOR is too long"); 527 } 528 system(cbuf); 529 i = open(q, O_RDONLY); 530 if (i < 0) 531 err(1, "%s", f_opt); 532 params = properties_read(i); 533 close (i); 534 unlink(q); 535 free(q); 536 } else { 537 /* XXX: Hack */ 538 i = open(_PATH_DEVNULL, O_RDONLY); 539 if (i < 0) 540 err(1, "%s", _PATH_DEVNULL); 541 params = properties_read(i); 542 close (i); 543 } 544 545 /* <sector_size> */ 546 p = property_find(params, "sector_size"); 547 i = ioctl(dfd, DIOCGSECTORSIZE, &u); 548 if (p != NULL) { 549 sector_size = strtoul(p, &q, 0); 550 if (!*p || *q) 551 errx(1, "sector_size not a proper number"); 552 } else if (i == 0) { 553 sector_size = u; 554 } else { 555 errx(1, "Missing sector_size property"); 556 } 557 if (sector_size & (sector_size - 1)) 558 errx(1, "sector_size not a power of 2"); 559 if (sector_size < 512) 560 errx(1, "sector_size is smaller than 512"); 561 buf = malloc(sector_size); 562 if (buf == NULL) 563 err(1, "Failed to malloc sector buffer"); 564 gl->sectorsize = sector_size; 565 566 i = ioctl(dfd, DIOCGMEDIASIZE, &off); 567 if (i == 0) { 568 first_sector = 0; 569 total_sectors = off / sector_size; 570 last_sector = total_sectors - 1; 571 } else { 572 first_sector = 0; 573 last_sector = 0; 574 total_sectors = 0; 575 } 576 577 /* <first_sector> */ 578 p = property_find(params, "first_sector"); 579 if (p != NULL) { 580 first_sector = strtoul(p, &q, 0); 581 if (!*p || *q) 582 errx(1, "first_sector not a proper number"); 583 } 584 585 /* <last_sector> */ 586 p = property_find(params, "last_sector"); 587 if (p != NULL) { 588 last_sector = strtoul(p, &q, 0); 589 if (!*p || *q) 590 errx(1, "last_sector not a proper number"); 591 if (last_sector <= first_sector) 592 errx(1, "last_sector not larger than first_sector"); 593 total_sectors = last_sector + 1; 594 } 595 596 /* <total_sectors> */ 597 p = property_find(params, "total_sectors"); 598 if (p != NULL) { 599 total_sectors = strtoul(p, &q, 0); 600 if (!*p || *q) 601 errx(1, "total_sectors not a proper number"); 602 if (last_sector == 0) 603 last_sector = first_sector + total_sectors - 1; 604 } 605 606 if (l_opt == NULL && first_sector != 0) 607 errx(1, "No -L new-lockfile argument and first_sector != 0"); 608 else if (l_opt == NULL) { 609 first_sector++; 610 total_sectors--; 611 gl->flags |= GBDE_F_SECT0; 612 } 613 gl->sector0 = first_sector * gl->sectorsize; 614 615 if (total_sectors != (last_sector - first_sector) + 1) 616 errx(1, "total_sectors disagree with first_sector and last_sector"); 617 if (total_sectors == 0) 618 errx(1, "missing last_sector or total_sectors"); 619 620 gl->sectorN = (last_sector + 1) * gl->sectorsize; 621 622 /* Find a random keyoffset */ 623 random_bits(&o, sizeof o); 624 o %= (gl->sectorN - gl->sector0); 625 o &= ~(gl->sectorsize - 1); 626 gl->keyoffset = o; 627 628 /* <number_of_keys> */ 629 p = property_find(params, "number_of_keys"); 630 if (p != NULL) { 631 nkeys = strtoul(p, &q, 0); 632 if (!*p || *q) 633 errx(1, "number_of_keys not a proper number"); 634 if (nkeys < 1 || nkeys > G_BDE_MAXKEYS) 635 errx(1, "number_of_keys out of range"); 636 } else { 637 nkeys = 4; 638 } 639 for (u = 0; u < nkeys; u++) { 640 for(;;) { 641 do { 642 random_bits(&o, sizeof o); 643 o %= gl->sectorN; 644 o &= ~(gl->sectorsize - 1); 645 } while(o < gl->sector0); 646 for (u2 = 0; u2 < u; u2++) 647 if (o == gl->lsector[u2]) 648 break; 649 if (u2 < u) 650 continue; 651 break; 652 } 653 gl->lsector[u] = o; 654 } 655 for (; u < G_BDE_MAXKEYS; u++) { 656 do 657 random_bits(&o, sizeof o); 658 while (o < gl->sectorN); 659 gl->lsector[u] = o; 660 } 661 qsort(gl->lsector, G_BDE_MAXKEYS, sizeof gl->lsector[0], sorthelp); 662 663 /* Flush sector zero if we use it for lockfile data */ 664 if (gl->flags & GBDE_F_SECT0) { 665 off2 = lseek(dfd, 0, SEEK_SET); 666 if (off2 != 0) 667 err(1, "lseek(2) to sector 0"); 668 random_bits(buf, sector_size); 669 i = write(dfd, buf, sector_size); 670 if (i != (int)sector_size) 671 err(1, "write sector 0"); 672 } 673 674 /* <random_flush> */ 675 p = property_find(params, "random_flush"); 676 if (p != NULL) { 677 off = first_sector * sector_size; 678 off2 = lseek(dfd, off, SEEK_SET); 679 if (off2 != off) 680 err(1, "lseek(2) to first_sector"); 681 off2 = last_sector * sector_size; 682 while (off <= off2) { 683 random_bits(buf, sector_size); 684 i = write(dfd, buf, sector_size); 685 if (i != (int)sector_size) 686 err(1, "write to $device_name"); 687 off += sector_size; 688 } 689 } 690 691 random_bits(gl->mkey, sizeof gl->mkey); 692 random_bits(gl->salt, sizeof gl->salt); 693 694 return; 695} 696 697static enum action { 698 ACT_HUH, 699 ACT_ATTACH, ACT_DETACH, 700 ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE 701} action; 702 703int 704main(int argc, char **argv) 705{ 706 const char *opts; 707 const char *l_opt, *L_opt; 708 const char *p_opt, *P_opt; 709 const char *f_opt; 710 char *dest; 711 int i_opt, n_opt, ch, dfd, doopen; 712 u_int nkey; 713 int i; 714 char *q, buf[BUFSIZ]; 715 struct g_bde_key *gl; 716 struct g_bde_softc sc; 717 718 if (argc < 3) 719 usage("Too few arguments\n"); 720 721 if ((i = modfind("g_bde")) < 0) { 722 /* need to load the gbde module */ 723 if (kldload(GBDEMOD) < 0 || modfind("g_bde") < 0) { 724 usage(GBDEMOD ": Kernel module not available"); 725 } 726 } 727 doopen = 0; 728 if (!strcmp(argv[1], "attach")) { 729 action = ACT_ATTACH; 730 opts = "l:p:"; 731 } else if (!strcmp(argv[1], "detach")) { 732 action = ACT_DETACH; 733 opts = ""; 734 } else if (!strcmp(argv[1], "init")) { 735 action = ACT_INIT; 736 doopen = 1; 737 opts = "f:iL:P:"; 738 } else if (!strcmp(argv[1], "setkey")) { 739 action = ACT_SETKEY; 740 doopen = 1; 741 opts = "n:l:L:p:P:"; 742 } else if (!strcmp(argv[1], "destroy")) { 743 action = ACT_DESTROY; 744 doopen = 1; 745 opts = "l:p:"; 746 } else if (!strcmp(argv[1], "nuke")) { 747 action = ACT_NUKE; 748 doopen = 1; 749 opts = "l:p:n:"; 750 } else { 751 usage("Unknown sub command\n"); 752 } 753 argc--; 754 argv++; 755 756 dest = strdup(argv[1]); 757 argc--; 758 argv++; 759 760 p_opt = NULL; 761 P_opt = NULL; 762 l_opt = NULL; 763 L_opt = NULL; 764 f_opt = NULL; 765 n_opt = 0; 766 i_opt = 0; 767 768 while((ch = getopt(argc, argv, opts)) != -1) 769 switch (ch) { 770 case 'f': 771 f_opt = optarg; 772 break; 773 case 'i': 774 i_opt = !i_opt; 775 case 'l': 776 l_opt = optarg; 777 break; 778 case 'L': 779 L_opt = optarg; 780 break; 781 case 'p': 782 p_opt = optarg; 783 break; 784 case 'P': 785 P_opt = optarg; 786 break; 787 case 'n': 788 n_opt = strtoul(optarg, &q, 0); 789 if (!*optarg || *q) 790 usage("-n argument not numeric\n"); 791 if (n_opt < -1 || n_opt > G_BDE_MAXKEYS) 792 usage("-n argument out of range\n"); break; 793 default: 794 usage("Invalid option\n"); 795 } 796 797 if (doopen) { 798 dfd = open(dest, O_RDWR | O_CREAT, 0644); 799 if (dfd < 0) { 800 if (snprintf(buf, sizeof(buf), "%s%s", 801 _PATH_DEV, dest) >= (ssize_t)sizeof(buf)) 802 errno = ENAMETOOLONG; 803 else 804 dfd = open(buf, O_RDWR | O_CREAT, 0644); 805 } 806 if (dfd < 0) 807 err(1, "%s", dest); 808 } else { 809 if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV))) 810 strcpy(dest, dest + strlen(_PATH_DEV)); 811 if (strchr(dest, '/')) 812 usage("\"dest\" argument must be geom-name\n"); 813 } 814 815 memset(&sc, 0, sizeof sc); 816 sc.consumer = (void *)&dfd; 817 gl = &sc.key; 818 switch(action) { 819 case ACT_ATTACH: 820 setup_passphrase(&sc, 0, p_opt); 821 cmd_attach(&sc, dest, l_opt); 822 break; 823 case ACT_DETACH: 824 cmd_detach(dest); 825 break; 826 case ACT_INIT: 827 cmd_init(gl, dfd, f_opt, i_opt, L_opt); 828 setup_passphrase(&sc, 1, P_opt); 829 cmd_write(gl, &sc, dfd, 0, L_opt); 830 break; 831 case ACT_SETKEY: 832 setup_passphrase(&sc, 0, p_opt); 833 cmd_open(&sc, dfd, l_opt, &nkey); 834 if (n_opt == 0) 835 n_opt = nkey + 1; 836 setup_passphrase(&sc, 1, P_opt); 837 cmd_write(gl, &sc, dfd, n_opt - 1, L_opt); 838 break; 839 case ACT_DESTROY: 840 setup_passphrase(&sc, 0, p_opt); 841 cmd_open(&sc, dfd, l_opt, &nkey); 842 cmd_destroy(gl, nkey); 843 reset_passphrase(&sc); 844 cmd_write(gl, &sc, dfd, nkey, l_opt); 845 break; 846 case ACT_NUKE: 847 setup_passphrase(&sc, 0, p_opt); 848 cmd_open(&sc, dfd, l_opt, &nkey); 849 if (n_opt == 0) 850 n_opt = nkey + 1; 851 if (n_opt == -1) { 852 for(i = 0; i < G_BDE_MAXKEYS; i++) 853 cmd_nuke(gl, dfd, i); 854 } else { 855 cmd_nuke(gl, dfd, n_opt - 1); 856 } 857 break; 858 default: 859 usage("Internal error\n"); 860 } 861 862 return(0); 863} 864