gbde.c revision 141198
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 141198 2005-02-03 13:12:17Z pjd $
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");
140141198Spjd	fprintf(stderr, "\t%s attach dest [-l lockfile] [-p pass-phrase]\n", p);
141105541Sphk	fprintf(stderr, "\t%s detach dest\n", p);
142141198Spjd	fprintf(stderr, "\t%s init /dev/dest [-i] [-f filename] [-L lockfile] [-P pass-phrase]\n", p);
143141198Spjd	fprintf(stderr, "\t%s setkey dest [-n key] [-l lockfile] [-p pass-phrase] [-L new-lockfile] [-P new-pass-phrase]\n", p);
144141198Spjd	fprintf(stderr, "\t%s destroy dest [-n key] [-l lockfile] [-p pass-phrase] [-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, &sectorsize);
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);
365125473Spjd	free(sbuf);
366105513Sphk	if (i != (int)gl->sectorsize)
367105513Sphk		err(1, "write");
368105513Sphk	printf("Nuked key %d\n", key);
369105513Sphk}
370105513Sphk
371105513Sphkstatic void
372105513Sphkcmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt)
373105513Sphk{
374105513Sphk	int i, ffd;
375105513Sphk	uint64_t off[2];
376105513Sphk	u_char keyloc[16];
377105513Sphk	u_char *sbuf, *q;
378105513Sphk	off_t offset, offset2;
379105513Sphk
380105513Sphk	sbuf = malloc(gl->sectorsize);
381105513Sphk	/*
382105513Sphk	 * Find the byte-offset in the lock sector where we will put the lock
383105513Sphk	 * data structure.  We can put it any random place as long as the
384105513Sphk	 * structure fits.
385105513Sphk	 */
386105513Sphk	for(;;) {
387105513Sphk		random_bits(off, sizeof off);
388105513Sphk		off[0] &= (gl->sectorsize - 1);
389105513Sphk		if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize)
390105513Sphk			continue;
391105513Sphk		break;
392105513Sphk	}
393105513Sphk
394105513Sphk	/* Add the sector offset in bytes */
395105513Sphk	off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1));
396105513Sphk	gl->lsector[key] = off[0];
397105513Sphk
398120876Sphk	i = g_bde_keyloc_encrypt(sc->sha2, off[0], off[1], keyloc);
399105513Sphk	if (i)
400105513Sphk		errx(1, "g_bde_keyloc_encrypt()");
401105513Sphk	if (l_opt != NULL) {
402105513Sphk		ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600);
403105513Sphk		if (ffd < 0)
404111296Stjr			err(1, "%s", l_opt);
405105513Sphk		write(ffd, keyloc, sizeof keyloc);
406105513Sphk		close(ffd);
407120876Sphk	} else if (gl->flags & GBDE_F_SECT0) {
408105513Sphk		offset2 = lseek(dfd, 0, SEEK_SET);
409105513Sphk		if (offset2 != 0)
410105513Sphk			err(1, "lseek");
411105513Sphk		i = read(dfd, sbuf, gl->sectorsize);
412105513Sphk		if (i != (int)gl->sectorsize)
413105513Sphk			err(1, "read");
414105513Sphk		memcpy(sbuf + key * 16, keyloc, sizeof keyloc);
415105513Sphk		offset2 = lseek(dfd, 0, SEEK_SET);
416105513Sphk		if (offset2 != 0)
417105513Sphk			err(1, "lseek");
418105513Sphk		i = write(dfd, sbuf, gl->sectorsize);
419105513Sphk		if (i != (int)gl->sectorsize)
420105513Sphk			err(1, "write");
421105513Sphk	} else {
422105513Sphk		errx(1, "No -L option and no space in sector 0 for lockfile");
423105513Sphk	}
424105513Sphk
425105513Sphk	/* Allocate a sectorbuffer and fill it with random junk */
426105513Sphk	if (sbuf == NULL)
427105513Sphk		err(1, "malloc");
428105513Sphk	random_bits(sbuf, gl->sectorsize);
429105513Sphk
430105513Sphk	/* Fill random bits in the spare field */
431105513Sphk	random_bits(gl->spare, sizeof(gl->spare));
432105513Sphk
433105513Sphk	/* Encode the structure where we want it */
434105513Sphk	q = sbuf + (off[0] % gl->sectorsize);
435120876Sphk	i = g_bde_encode_lock(sc->sha2, gl, q);
436106407Sphk	if (i < 0)
437106407Sphk		errx(1, "programming error encoding lock");
438105513Sphk
439106407Sphk	encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16);
440105513Sphk	offset = gl->lsector[key] & ~(gl->sectorsize - 1);
441105513Sphk	offset2 = lseek(dfd, offset, SEEK_SET);
442105513Sphk	if (offset2 != offset)
443105513Sphk		err(1, "lseek");
444105513Sphk	i = write(dfd, sbuf, gl->sectorsize);
445105513Sphk	if (i != (int)gl->sectorsize)
446105513Sphk		err(1, "write");
447125473Spjd	free(sbuf);
448108052Sphk#if 0
449135035Sphk	printf("Wrote key %d at %jd\n", key, (intmax_t)offset);
450108052Sphk	printf("s0 = %jd\n", (intmax_t)gl->sector0);
451108052Sphk	printf("sN = %jd\n", (intmax_t)gl->sectorN);
452108052Sphk	printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]);
453108052Sphk	printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]);
454108052Sphk	printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]);
455108052Sphk	printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]);
456108052Sphk	printf("k = %jd\n", (intmax_t)gl->keyoffset);
457108052Sphk	printf("ss = %jd\n", (intmax_t)gl->sectorsize);
458108052Sphk#endif
459105513Sphk}
460105513Sphk
461105513Sphkstatic void
462105513Sphkcmd_destroy(struct g_bde_key *gl, int nkey)
463105513Sphk{
464105513Sphk	int i;
465105513Sphk
466105513Sphk	bzero(&gl->sector0, sizeof gl->sector0);
467105513Sphk	bzero(&gl->sectorN, sizeof gl->sectorN);
468105513Sphk	bzero(&gl->keyoffset, sizeof gl->keyoffset);
469105513Sphk	bzero(&gl->flags, sizeof gl->flags);
470106227Sphk	bzero(gl->mkey, sizeof gl->mkey);
471105513Sphk	for (i = 0; i < G_BDE_MAXKEYS; i++)
472105513Sphk		if (i != nkey)
473105513Sphk			gl->lsector[i] = ~0;
474105513Sphk}
475105513Sphk
476108052Sphkstatic int
477108052Sphksorthelp(const void *a, const void *b)
478108052Sphk{
479135035Sphk	const uint64_t *oa, *ob;
480108052Sphk
481108052Sphk	oa = a;
482108052Sphk	ob = b;
483131101Ssobomax	if (*oa > *ob)
484131101Ssobomax		return 1;
485131101Ssobomax	if (*oa < *ob)
486131101Ssobomax		return -1;
487131101Ssobomax	return 0;
488108052Sphk}
489108052Sphk
490105513Sphkstatic void
491105513Sphkcmd_init(struct g_bde_key *gl, int dfd, const char *f_opt, int i_opt, const char *l_opt)
492105513Sphk{
493105513Sphk	int i;
494105513Sphk	u_char *buf;
495105513Sphk	unsigned sector_size;
496105513Sphk	uint64_t	first_sector;
497105513Sphk	uint64_t	last_sector;
498105513Sphk	uint64_t	total_sectors;
499105513Sphk	off_t	off, off2;
500105513Sphk	unsigned nkeys;
501105513Sphk	const char *p;
502105513Sphk	char *q, cbuf[BUFSIZ];
503105513Sphk	unsigned u, u2;
504105513Sphk	uint64_t o;
505105513Sphk	properties	params;
506105513Sphk
507105513Sphk	bzero(gl, sizeof *gl);
508105513Sphk	if (f_opt != NULL) {
509105513Sphk		i = open(f_opt, O_RDONLY);
510105513Sphk		if (i < 0)
511111296Stjr			err(1, "%s", f_opt);
512105513Sphk		params = properties_read(i);
513105513Sphk		close (i);
514125477Sdes	} else if (i_opt) {
515105513Sphk		/* XXX: Polish */
516125477Sdes		asprintf(&q, "%stemp.XXXXXXXXXX", _PATH_TMP);
517125477Sdes		if (q == NULL)
518125477Sdes			err(1, "asprintf");
519105513Sphk		i = mkstemp(q);
520105513Sphk		if (i < 0)
521111296Stjr			err(1, "%s", q);
522105513Sphk		write(i, template, strlen(template));
523105513Sphk		close (i);
524125477Sdes		p = getenv("EDITOR");
525125477Sdes		if (p == NULL)
526125477Sdes			p = "vi";
527125477Sdes		if (snprintf(cbuf, sizeof(cbuf), "%s %s\n", p, q) >=
528125477Sdes		    (ssize_t)sizeof(cbuf)) {
529125477Sdes			unlink(q);
530125477Sdes			errx(1, "EDITOR is too long");
531105513Sphk		}
532125477Sdes		system(cbuf);
533105513Sphk		i = open(q, O_RDONLY);
534105513Sphk		if (i < 0)
535111296Stjr			err(1, "%s", f_opt);
536105513Sphk		params = properties_read(i);
537105513Sphk		close (i);
538105513Sphk		unlink(q);
539125473Spjd		free(q);
540125477Sdes	} else {
541125477Sdes		/* XXX: Hack */
542125477Sdes		i = open(_PATH_DEVNULL, O_RDONLY);
543125477Sdes		if (i < 0)
544125477Sdes			err(1, "%s", _PATH_DEVNULL);
545125477Sdes		params = properties_read(i);
546125477Sdes		close (i);
547105513Sphk	}
548105513Sphk
549105513Sphk	/* <sector_size> */
550105513Sphk	p = property_find(params, "sector_size");
551105513Sphk	i = ioctl(dfd, DIOCGSECTORSIZE, &u);
552105513Sphk	if (p != NULL) {
553105513Sphk		sector_size = strtoul(p, &q, 0);
554105513Sphk		if (!*p || *q)
555105513Sphk			errx(1, "sector_size not a proper number");
556108020Sphk	} else if (i == 0) {
557108020Sphk		sector_size = u;
558108020Sphk	} else {
559108020Sphk		errx(1, "Missing sector_size property");
560105513Sphk	}
561105513Sphk	if (sector_size & (sector_size - 1))
562105513Sphk		errx(1, "sector_size not a power of 2");
563105513Sphk	if (sector_size < 512)
564105513Sphk		errx(1, "sector_size is smaller than 512");
565105513Sphk	buf = malloc(sector_size);
566105513Sphk	if (buf == NULL)
567105513Sphk		err(1, "Failed to malloc sector buffer");
568105513Sphk	gl->sectorsize = sector_size;
569105513Sphk
570105513Sphk	i = ioctl(dfd, DIOCGMEDIASIZE, &off);
571105513Sphk	if (i == 0) {
572105513Sphk		first_sector = 0;
573105513Sphk		total_sectors = off / sector_size;
574105513Sphk		last_sector = total_sectors - 1;
575105513Sphk	} else {
576105513Sphk		first_sector = 0;
577105513Sphk		last_sector = 0;
578105513Sphk		total_sectors = 0;
579105513Sphk	}
580105513Sphk
581105513Sphk	/* <first_sector> */
582105513Sphk	p = property_find(params, "first_sector");
583105513Sphk	if (p != NULL) {
584105513Sphk		first_sector = strtoul(p, &q, 0);
585105513Sphk		if (!*p || *q)
586105513Sphk			errx(1, "first_sector not a proper number");
587105513Sphk	}
588105513Sphk
589105513Sphk	/* <last_sector> */
590105513Sphk	p = property_find(params, "last_sector");
591105513Sphk	if (p != NULL) {
592105513Sphk		last_sector = strtoul(p, &q, 0);
593105513Sphk		if (!*p || *q)
594105513Sphk			errx(1, "last_sector not a proper number");
595105513Sphk		if (last_sector <= first_sector)
596105513Sphk			errx(1, "last_sector not larger than first_sector");
597105513Sphk		total_sectors = last_sector + 1;
598105513Sphk	}
599105513Sphk
600105513Sphk	/* <total_sectors> */
601105513Sphk	p = property_find(params, "total_sectors");
602105513Sphk	if (p != NULL) {
603105513Sphk		total_sectors = strtoul(p, &q, 0);
604105513Sphk		if (!*p || *q)
605105513Sphk			errx(1, "total_sectors not a proper number");
606125387Sdes		if (last_sector == 0)
607105513Sphk			last_sector = first_sector + total_sectors - 1;
608105513Sphk	}
609105513Sphk
610105513Sphk	if (l_opt == NULL && first_sector != 0)
611105513Sphk		errx(1, "No -L new-lockfile argument and first_sector != 0");
612105513Sphk	else if (l_opt == NULL) {
613105513Sphk		first_sector++;
614105513Sphk		total_sectors--;
615120876Sphk		gl->flags |= GBDE_F_SECT0;
616105513Sphk	}
617108060Sphk	gl->sector0 = first_sector * gl->sectorsize;
618105513Sphk
619105513Sphk	if (total_sectors != (last_sector - first_sector) + 1)
620105513Sphk		errx(1, "total_sectors disagree with first_sector and last_sector");
621105513Sphk	if (total_sectors == 0)
622105513Sphk		errx(1, "missing last_sector or total_sectors");
623105513Sphk
624105513Sphk	gl->sectorN = (last_sector + 1) * gl->sectorsize;
625105513Sphk
626105513Sphk	/* Find a random keyoffset */
627105513Sphk	random_bits(&o, sizeof o);
628105513Sphk	o %= (gl->sectorN - gl->sector0);
629105513Sphk	o &= ~(gl->sectorsize - 1);
630105513Sphk	gl->keyoffset = o;
631105513Sphk
632105513Sphk	/* <number_of_keys> */
633105513Sphk	p = property_find(params, "number_of_keys");
634125477Sdes	if (p != NULL) {
635125477Sdes		nkeys = strtoul(p, &q, 0);
636125477Sdes		if (!*p || *q)
637125477Sdes			errx(1, "number_of_keys not a proper number");
638125477Sdes		if (nkeys < 1 || nkeys > G_BDE_MAXKEYS)
639125477Sdes			errx(1, "number_of_keys out of range");
640125477Sdes	} else {
641125477Sdes		nkeys = 4;
642125477Sdes	}
643105513Sphk	for (u = 0; u < nkeys; u++) {
644105513Sphk		for(;;) {
645105513Sphk			do {
646105513Sphk				random_bits(&o, sizeof o);
647105513Sphk				o %= gl->sectorN;
648105513Sphk				o &= ~(gl->sectorsize - 1);
649105513Sphk			} while(o < gl->sector0);
650105513Sphk			for (u2 = 0; u2 < u; u2++)
651105513Sphk				if (o == gl->lsector[u2])
652105513Sphk					break;
653105513Sphk			if (u2 < u)
654105513Sphk				continue;
655105513Sphk			break;
656105513Sphk		}
657105513Sphk		gl->lsector[u] = o;
658125387Sdes	}
659105513Sphk	for (; u < G_BDE_MAXKEYS; u++) {
660125387Sdes		do
661105513Sphk			random_bits(&o, sizeof o);
662105513Sphk		while (o < gl->sectorN);
663105513Sphk		gl->lsector[u] = o;
664105513Sphk	}
665108052Sphk	qsort(gl->lsector, G_BDE_MAXKEYS, sizeof gl->lsector[0], sorthelp);
666105513Sphk
667105513Sphk	/* Flush sector zero if we use it for lockfile data */
668120876Sphk	if (gl->flags & GBDE_F_SECT0) {
669105513Sphk		off2 = lseek(dfd, 0, SEEK_SET);
670105513Sphk		if (off2 != 0)
671105513Sphk			err(1, "lseek(2) to sector 0");
672105513Sphk		random_bits(buf, sector_size);
673105513Sphk		i = write(dfd, buf, sector_size);
674105513Sphk		if (i != (int)sector_size)
675105513Sphk			err(1, "write sector 0");
676105513Sphk	}
677105513Sphk
678105513Sphk	/* <random_flush> */
679105513Sphk	p = property_find(params, "random_flush");
680105513Sphk	if (p != NULL) {
681105513Sphk		off = first_sector * sector_size;
682105513Sphk		off2 = lseek(dfd, off, SEEK_SET);
683105513Sphk		if (off2 != off)
684105513Sphk			err(1, "lseek(2) to first_sector");
685105513Sphk		off2 = last_sector * sector_size;
686105513Sphk		while (off <= off2) {
687105513Sphk			random_bits(buf, sector_size);
688105513Sphk			i = write(dfd, buf, sector_size);
689105513Sphk			if (i != (int)sector_size)
690105513Sphk				err(1, "write to $device_name");
691105513Sphk			off += sector_size;
692105513Sphk		}
693105513Sphk	}
694105513Sphk
695106227Sphk	random_bits(gl->mkey, sizeof gl->mkey);
696106227Sphk	random_bits(gl->salt, sizeof gl->salt);
697125387Sdes
698105513Sphk	return;
699105513Sphk}
700105513Sphk
701105513Sphkstatic enum action {
702105513Sphk	ACT_HUH,
703105541Sphk	ACT_ATTACH, ACT_DETACH,
704105513Sphk	ACT_INIT, ACT_SETKEY, ACT_DESTROY, ACT_NUKE
705105513Sphk} action;
706105513Sphk
707105513Sphkint
708105513Sphkmain(int argc, char **argv)
709105513Sphk{
710105513Sphk	const char *opts;
711105513Sphk	const char *l_opt, *L_opt;
712105513Sphk	const char *p_opt, *P_opt;
713105513Sphk	const char *f_opt;
714107455Sphk	char *dest;
715107455Sphk	int i_opt, n_opt, ch, dfd, doopen;
716107455Sphk	u_int nkey;
717105513Sphk	int i;
718107455Sphk	char *q, buf[BUFSIZ];
719105513Sphk	struct g_bde_key *gl;
720105513Sphk	struct g_bde_softc sc;
721105513Sphk
722105513Sphk	if (argc < 3)
723105513Sphk		usage("Too few arguments\n");
724105513Sphk
725120969Sphk       if ((i = modfind("g_bde")) < 0) {
726125387Sdes	       /* need to load the gbde module */
727125387Sdes	       if (kldload(GBDEMOD) < 0 || modfind("g_bde") < 0) {
728131101Ssobomax		       usage(GBDEMOD ": Kernel module not available\n");
729125387Sdes	       }
730120877Sphk       }
731105513Sphk	doopen = 0;
732105513Sphk	if (!strcmp(argv[1], "attach")) {
733105513Sphk		action = ACT_ATTACH;
734105513Sphk		opts = "l:p:";
735105541Sphk	} else if (!strcmp(argv[1], "detach")) {
736105541Sphk		action = ACT_DETACH;
737105513Sphk		opts = "";
738105513Sphk	} else if (!strcmp(argv[1], "init")) {
739105513Sphk		action = ACT_INIT;
740105513Sphk		doopen = 1;
741105513Sphk		opts = "f:iL:P:";
742105513Sphk	} else if (!strcmp(argv[1], "setkey")) {
743105513Sphk		action = ACT_SETKEY;
744105513Sphk		doopen = 1;
745105513Sphk		opts = "n:l:L:p:P:";
746105513Sphk	} else if (!strcmp(argv[1], "destroy")) {
747105513Sphk		action = ACT_DESTROY;
748105513Sphk		doopen = 1;
749105513Sphk		opts = "l:p:";
750105513Sphk	} else if (!strcmp(argv[1], "nuke")) {
751105513Sphk		action = ACT_NUKE;
752105513Sphk		doopen = 1;
753105513Sphk		opts = "l:p:n:";
754105513Sphk	} else {
755105513Sphk		usage("Unknown sub command\n");
756105513Sphk	}
757105513Sphk	argc--;
758105513Sphk	argv++;
759105513Sphk
760107455Sphk	dest = strdup(argv[1]);
761105513Sphk	argc--;
762105513Sphk	argv++;
763105513Sphk
764105513Sphk	p_opt = NULL;
765105513Sphk	P_opt = NULL;
766105513Sphk	l_opt = NULL;
767105513Sphk	L_opt = NULL;
768105513Sphk	f_opt = NULL;
769105513Sphk	n_opt = 0;
770105513Sphk	i_opt = 0;
771105513Sphk
772105513Sphk	while((ch = getopt(argc, argv, opts)) != -1)
773105513Sphk		switch (ch) {
774105513Sphk		case 'f':
775105513Sphk			f_opt = optarg;
776105513Sphk			break;
777105513Sphk		case 'i':
778105513Sphk			i_opt = !i_opt;
779105513Sphk		case 'l':
780105513Sphk			l_opt = optarg;
781105513Sphk			break;
782105513Sphk		case 'L':
783105513Sphk			L_opt = optarg;
784105513Sphk			break;
785105513Sphk		case 'p':
786105513Sphk			p_opt = optarg;
787105513Sphk			break;
788105513Sphk		case 'P':
789105513Sphk			P_opt = optarg;
790105513Sphk			break;
791105513Sphk		case 'n':
792105513Sphk			n_opt = strtoul(optarg, &q, 0);
793105513Sphk			if (!*optarg || *q)
794105513Sphk				usage("-n argument not numeric\n");
795105513Sphk			if (n_opt < -1 || n_opt > G_BDE_MAXKEYS)
796107982Sphk				usage("-n argument out of range\n"); break;
797105513Sphk		default:
798105513Sphk			usage("Invalid option\n");
799105513Sphk		}
800105513Sphk
801105513Sphk	if (doopen) {
802141198Spjd		dfd = open(dest, O_RDWR);
803141198Spjd		if (dfd < 0 && dest[0] != '/') {
804111298Stjr			if (snprintf(buf, sizeof(buf), "%s%s",
805111298Stjr			    _PATH_DEV, dest) >= (ssize_t)sizeof(buf))
806111298Stjr				errno = ENAMETOOLONG;
807111298Stjr			else
808141198Spjd				dfd = open(buf, O_RDWR);
809107455Sphk		}
810105513Sphk		if (dfd < 0)
811111296Stjr			err(1, "%s", dest);
812107455Sphk	} else {
813107455Sphk		if (!memcmp(dest, _PATH_DEV, strlen(_PATH_DEV)))
814107455Sphk			strcpy(dest, dest + strlen(_PATH_DEV));
815105513Sphk	}
816105513Sphk
817105513Sphk	memset(&sc, 0, sizeof sc);
818107982Sphk	sc.consumer = (void *)&dfd;
819105513Sphk	gl = &sc.key;
820105513Sphk	switch(action) {
821105513Sphk	case ACT_ATTACH:
822105513Sphk		setup_passphrase(&sc, 0, p_opt);
823105513Sphk		cmd_attach(&sc, dest, l_opt);
824105513Sphk		break;
825105541Sphk	case ACT_DETACH:
826105541Sphk		cmd_detach(dest);
827105513Sphk		break;
828105513Sphk	case ACT_INIT:
829105513Sphk		cmd_init(gl, dfd, f_opt, i_opt, L_opt);
830105513Sphk		setup_passphrase(&sc, 1, P_opt);
831105513Sphk		cmd_write(gl, &sc, dfd, 0, L_opt);
832105513Sphk		break;
833105513Sphk	case ACT_SETKEY:
834105513Sphk		setup_passphrase(&sc, 0, p_opt);
835105513Sphk		cmd_open(&sc, dfd, l_opt, &nkey);
836105513Sphk		if (n_opt == 0)
837105513Sphk			n_opt = nkey + 1;
838105513Sphk		setup_passphrase(&sc, 1, P_opt);
839105513Sphk		cmd_write(gl, &sc, dfd, n_opt - 1, L_opt);
840105513Sphk		break;
841105513Sphk	case ACT_DESTROY:
842105513Sphk		setup_passphrase(&sc, 0, p_opt);
843105513Sphk		cmd_open(&sc, dfd, l_opt, &nkey);
844105513Sphk		cmd_destroy(gl, nkey);
845105513Sphk		reset_passphrase(&sc);
846105513Sphk		cmd_write(gl, &sc, dfd, nkey, l_opt);
847105513Sphk		break;
848105513Sphk	case ACT_NUKE:
849105513Sphk		setup_passphrase(&sc, 0, p_opt);
850105513Sphk		cmd_open(&sc, dfd, l_opt, &nkey);
851105513Sphk		if (n_opt == 0)
852105513Sphk			n_opt = nkey + 1;
853105513Sphk		if (n_opt == -1) {
854105513Sphk			for(i = 0; i < G_BDE_MAXKEYS; i++)
855105513Sphk				cmd_nuke(gl, dfd, i);
856105513Sphk		} else {
857105513Sphk				cmd_nuke(gl, dfd, n_opt - 1);
858105513Sphk		}
859105513Sphk		break;
860105513Sphk	default:
861105513Sphk		usage("Internal error\n");
862105513Sphk	}
863105513Sphk
864105513Sphk	return(0);
865105513Sphk}
866