geom_eli.c revision 213056
1148456Spjd/*-
2182452Spjd * Copyright (c) 2004-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3148456Spjd * All rights reserved.
4148456Spjd *
5148456Spjd * Redistribution and use in source and binary forms, with or without
6148456Spjd * modification, are permitted provided that the following conditions
7148456Spjd * are met:
8148456Spjd * 1. Redistributions of source code must retain the above copyright
9148456Spjd *    notice, this list of conditions and the following disclaimer.
10148456Spjd * 2. Redistributions in binary form must reproduce the above copyright
11148456Spjd *    notice, this list of conditions and the following disclaimer in the
12148456Spjd *    documentation and/or other materials provided with the distribution.
13155175Spjd *
14148456Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15148456Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16148456Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17148456Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18148456Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19148456Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148456Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148456Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22148456Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23148456Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24148456Spjd * SUCH DAMAGE.
25148456Spjd */
26148456Spjd
27148456Spjd#include <sys/cdefs.h>
28148456Spjd__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 213056 2010-09-23 10:50:17Z pjd $");
29148456Spjd
30148456Spjd#include <stdio.h>
31148456Spjd#include <stdint.h>
32148456Spjd#include <stdlib.h>
33148456Spjd#include <unistd.h>
34148456Spjd#include <fcntl.h>
35148456Spjd#include <readpassphrase.h>
36148456Spjd#include <string.h>
37148456Spjd#include <strings.h>
38148456Spjd#include <libgeom.h>
39148456Spjd#include <paths.h>
40148456Spjd#include <errno.h>
41148456Spjd#include <assert.h>
42148456Spjd
43148456Spjd#include <sys/param.h>
44148456Spjd#include <sys/mman.h>
45148456Spjd#include <sys/resource.h>
46148456Spjd#include <opencrypto/cryptodev.h>
47148456Spjd#include <geom/eli/g_eli.h>
48148456Spjd#include <geom/eli/pkcs5v2.h>
49148456Spjd
50148456Spjd#include "core/geom.h"
51148456Spjd#include "misc/subr.h"
52148456Spjd
53148456Spjd
54148456Spjduint32_t lib_version = G_LIB_VERSION;
55148456Spjduint32_t version = G_ELI_VERSION;
56148456Spjd
57182452Spjd#define	GELI_BACKUP_DIR	"/var/backups/"
58212547Spjd#define	GELI_ENC_ALGO	"aes"
59182452Spjd
60148456Spjdstatic void eli_main(struct gctl_req *req, unsigned flags);
61148456Spjdstatic void eli_init(struct gctl_req *req);
62148456Spjdstatic void eli_attach(struct gctl_req *req);
63162353Spjdstatic void eli_configure(struct gctl_req *req);
64148456Spjdstatic void eli_setkey(struct gctl_req *req);
65148456Spjdstatic void eli_delkey(struct gctl_req *req);
66148456Spjdstatic void eli_kill(struct gctl_req *req);
67148456Spjdstatic void eli_backup(struct gctl_req *req);
68148456Spjdstatic void eli_restore(struct gctl_req *req);
69212934Sbrianstatic void eli_resize(struct gctl_req *req);
70148456Spjdstatic void eli_clear(struct gctl_req *req);
71148456Spjdstatic void eli_dump(struct gctl_req *req);
72148456Spjd
73182452Spjdstatic int eli_backup_create(struct gctl_req *req, const char *prov,
74182452Spjd    const char *file);
75182452Spjd
76148456Spjd/*
77148456Spjd * Available commands:
78148456Spjd *
79182452Spjd * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
80148456Spjd * label - alias for 'init'
81161127Spjd * attach [-dprv] [-k keyfile] prov
82148456Spjd * detach [-fl] prov ...
83148456Spjd * stop - alias for 'detach'
84181639Spjd * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov
85162353Spjd * configure [-bB] prov ...
86148456Spjd * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
87148456Spjd * delkey [-afv] [-n keyno] prov
88148456Spjd * kill [-av] [prov ...]
89148456Spjd * backup [-v] prov file
90212934Sbrian * restore [-fv] file prov
91212934Sbrian * resize [-v] -s oldsize prov
92148456Spjd * clear [-v] prov ...
93148456Spjd * dump [-v] prov ...
94148456Spjd */
95148456Spjdstruct g_command class_commands[] = {
96148456Spjd	{ "init", G_FLAG_VERBOSE, eli_main,
97148456Spjd	    {
98212547Spjd		{ 'a', "aalgo", "", G_TYPE_STRING },
99162868Spjd		{ 'b', "boot", NULL, G_TYPE_BOOL },
100212547Spjd		{ 'B', "backupfile", "", G_TYPE_STRING },
101212547Spjd		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
102212554Spjd		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
103212547Spjd		{ 'K', "newkeyfile", "", G_TYPE_STRING },
104212554Spjd		{ 'l', "keylen", "0", G_TYPE_NUMBER },
105162868Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
106212554Spjd		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
107148456Spjd		G_OPT_SENTINEL
108148456Spjd	    },
109212554Spjd	    "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
110148456Spjd	},
111148456Spjd	{ "label", G_FLAG_VERBOSE, eli_main,
112148456Spjd	    {
113212547Spjd		{ 'a', "aalgo", "", G_TYPE_STRING },
114162868Spjd		{ 'b', "boot", NULL, G_TYPE_BOOL },
115212547Spjd		{ 'B', "backupfile", "", G_TYPE_STRING },
116212547Spjd		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
117212554Spjd		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
118212547Spjd		{ 'K', "newkeyfile", "", G_TYPE_STRING },
119212554Spjd		{ 'l', "keylen", "0", G_TYPE_NUMBER },
120162868Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
121212554Spjd		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
122148456Spjd		G_OPT_SENTINEL
123148456Spjd	    },
124212554Spjd	    "- an alias for 'init'"
125148456Spjd	},
126148456Spjd	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
127148456Spjd	    {
128162868Spjd		{ 'd', "detach", NULL, G_TYPE_BOOL },
129212547Spjd		{ 'k', "keyfile", "", G_TYPE_STRING },
130162868Spjd		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
131162868Spjd		{ 'r', "readonly", NULL, G_TYPE_BOOL },
132148456Spjd		G_OPT_SENTINEL
133148456Spjd	    },
134212554Spjd	    "[-dprv] [-k keyfile] prov"
135148456Spjd	},
136148456Spjd	{ "detach", 0, NULL,
137148456Spjd	    {
138162868Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
139162868Spjd		{ 'l', "last", NULL, G_TYPE_BOOL },
140148456Spjd		G_OPT_SENTINEL
141148456Spjd	    },
142212554Spjd	    "[-fl] prov ..."
143148456Spjd	},
144148456Spjd	{ "stop", 0, NULL,
145148456Spjd	    {
146162868Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
147162868Spjd		{ 'l', "last", NULL, G_TYPE_BOOL },
148148456Spjd		G_OPT_SENTINEL
149148456Spjd	    },
150212554Spjd	    "- an alias for 'detach'"
151148456Spjd	},
152148456Spjd	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
153148456Spjd	    {
154212547Spjd		{ 'a', "aalgo", "", G_TYPE_STRING },
155162868Spjd		{ 'd', "detach", NULL, G_TYPE_BOOL },
156212547Spjd		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
157212554Spjd		{ 'l', "keylen", "0", G_TYPE_NUMBER },
158212554Spjd		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
159148456Spjd		G_OPT_SENTINEL
160148456Spjd	    },
161212554Spjd	    "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov"
162148456Spjd	},
163162353Spjd	{ "configure", G_FLAG_VERBOSE, eli_main,
164162353Spjd	    {
165162868Spjd		{ 'b', "boot", NULL, G_TYPE_BOOL },
166162868Spjd		{ 'B', "noboot", NULL, G_TYPE_BOOL },
167162353Spjd		G_OPT_SENTINEL
168162353Spjd	    },
169212554Spjd	    "[-bB] prov ..."
170162353Spjd	},
171148456Spjd	{ "setkey", G_FLAG_VERBOSE, eli_main,
172148456Spjd	    {
173212554Spjd		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
174212547Spjd		{ 'k', "keyfile", "", G_TYPE_STRING },
175212547Spjd		{ 'K', "newkeyfile", "", G_TYPE_STRING },
176212554Spjd		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
177162868Spjd		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
178162868Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
179148456Spjd		G_OPT_SENTINEL
180148456Spjd	    },
181212554Spjd	    "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
182148456Spjd	},
183148456Spjd	{ "delkey", G_FLAG_VERBOSE, eli_main,
184148456Spjd	    {
185162868Spjd		{ 'a', "all", NULL, G_TYPE_BOOL },
186162868Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
187212554Spjd		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
188148456Spjd		G_OPT_SENTINEL
189148456Spjd	    },
190212554Spjd	    "[-afv] [-n keyno] prov"
191148456Spjd	},
192148456Spjd	{ "kill", G_FLAG_VERBOSE, eli_main,
193148456Spjd	    {
194162868Spjd		{ 'a', "all", NULL, G_TYPE_BOOL },
195148456Spjd		G_OPT_SENTINEL
196148456Spjd	    },
197212554Spjd	    "[-av] [prov ...]"
198148456Spjd	},
199212554Spjd	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
200148456Spjd	    "[-v] prov file"
201148456Spjd	},
202212934Sbrian	{ "restore", G_FLAG_VERBOSE, eli_main,
203212934Sbrian	    {
204212934Sbrian		{ 'f', "force", NULL, G_TYPE_BOOL },
205212934Sbrian		G_OPT_SENTINEL
206212934Sbrian	    },
207212934Sbrian	    "[-fv] file prov"
208148456Spjd	},
209212934Sbrian	{ "resize", G_FLAG_VERBOSE, eli_main,
210212934Sbrian	    {
211212934Sbrian		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
212212934Sbrian		G_OPT_SENTINEL
213212934Sbrian	    },
214212934Sbrian	    "[-v] -s oldsize prov"
215212934Sbrian	},
216212554Spjd	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
217148456Spjd	    "[-v] prov ..."
218148456Spjd	},
219212554Spjd	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
220148456Spjd	    "[-v] prov ..."
221148456Spjd	},
222148456Spjd	G_CMD_SENTINEL
223148456Spjd};
224148456Spjd
225148456Spjdstatic int verbose = 0;
226148456Spjd
227148456Spjdstatic int
228148456Spjdeli_protect(struct gctl_req *req)
229148456Spjd{
230148456Spjd	struct rlimit rl;
231148456Spjd
232148456Spjd	/* Disable core dumps. */
233148456Spjd	rl.rlim_cur = 0;
234148456Spjd	rl.rlim_max = 0;
235148456Spjd	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
236148456Spjd		gctl_error(req, "Cannot disable core dumps: %s.",
237148456Spjd		    strerror(errno));
238148456Spjd		return (-1);
239148456Spjd	}
240148456Spjd	/* Disable swapping. */
241148456Spjd	if (mlockall(MCL_FUTURE) == -1) {
242148456Spjd		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
243148456Spjd		return (-1);
244148456Spjd	}
245148456Spjd	return (0);
246148456Spjd}
247148456Spjd
248148456Spjdstatic void
249148456Spjdeli_main(struct gctl_req *req, unsigned flags)
250148456Spjd{
251148456Spjd	const char *name;
252148456Spjd
253148456Spjd	if (eli_protect(req) == -1)
254148456Spjd		return;
255148456Spjd
256148456Spjd	if ((flags & G_FLAG_VERBOSE) != 0)
257148456Spjd		verbose = 1;
258148456Spjd
259153190Spjd	name = gctl_get_ascii(req, "verb");
260148456Spjd	if (name == NULL) {
261148456Spjd		gctl_error(req, "No '%s' argument.", "verb");
262148456Spjd		return;
263148456Spjd	}
264148456Spjd	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
265148456Spjd		eli_init(req);
266148456Spjd	else if (strcmp(name, "attach") == 0)
267148456Spjd		eli_attach(req);
268162353Spjd	else if (strcmp(name, "configure") == 0)
269162353Spjd		eli_configure(req);
270148456Spjd	else if (strcmp(name, "setkey") == 0)
271148456Spjd		eli_setkey(req);
272148456Spjd	else if (strcmp(name, "delkey") == 0)
273148456Spjd		eli_delkey(req);
274148456Spjd	else if (strcmp(name, "kill") == 0)
275148456Spjd		eli_kill(req);
276148456Spjd	else if (strcmp(name, "backup") == 0)
277148456Spjd		eli_backup(req);
278148456Spjd	else if (strcmp(name, "restore") == 0)
279148456Spjd		eli_restore(req);
280212934Sbrian	else if (strcmp(name, "resize") == 0)
281212934Sbrian		eli_resize(req);
282148456Spjd	else if (strcmp(name, "dump") == 0)
283148456Spjd		eli_dump(req);
284148456Spjd	else if (strcmp(name, "clear") == 0)
285148456Spjd		eli_clear(req);
286148456Spjd	else
287148456Spjd		gctl_error(req, "Unknown command: %s.", name);
288148456Spjd}
289148456Spjd
290148456Spjdstatic void
291148456Spjdarc4rand(unsigned char *buf, size_t size)
292148456Spjd{
293148456Spjd	uint32_t *buf4;
294148456Spjd	size_t size4;
295148456Spjd	unsigned i;
296148456Spjd
297148456Spjd	buf4 = (uint32_t *)buf;
298148456Spjd	size4 = size / 4;
299148456Spjd
300148456Spjd	for (i = 0; i < size4; i++)
301148456Spjd		buf4[i] = arc4random();
302148456Spjd	for (i *= 4; i < size; i++)
303148456Spjd		buf[i] = arc4random() % 0xff;
304148456Spjd}
305148456Spjd
306148456Spjdstatic int
307148456Spjdeli_is_attached(const char *prov)
308148456Spjd{
309148456Spjd	char name[MAXPATHLEN];
310148456Spjd	unsigned secsize;
311148456Spjd
312148456Spjd	/*
313148456Spjd	 * Not the best way to do it, but the easiest.
314148456Spjd	 * We try to open provider and check if it is a GEOM provider
315148456Spjd	 * by asking about its sectorsize.
316148456Spjd	 */
317148456Spjd	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
318148456Spjd	secsize = g_get_sectorsize(name);
319148456Spjd	if (secsize > 0)
320148456Spjd		return (1);
321148456Spjd	return (0);
322148456Spjd}
323148456Spjd
324148456Spjdstatic unsigned char *
325148456Spjdeli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
326148456Spjd    int new)
327148456Spjd{
328148456Spjd	struct hmac_ctx ctx;
329148456Spjd	const char *str;
330153190Spjd	int error, nopassphrase;
331148456Spjd
332153190Spjd	nopassphrase =
333153190Spjd	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
334148456Spjd
335148456Spjd	g_eli_crypto_hmac_init(&ctx, NULL, 0);
336148456Spjd
337153190Spjd	str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
338155183Spjd	if (str[0] == '\0' && nopassphrase) {
339155183Spjd		gctl_error(req, "No key components given.");
340155183Spjd		return (NULL);
341155183Spjd	} else if (str[0] != '\0') {
342148456Spjd		char buf[MAXPHYS];
343148456Spjd		ssize_t done;
344148456Spjd		int fd;
345148456Spjd
346148456Spjd		if (strcmp(str, "-") == 0)
347148456Spjd			fd = STDIN_FILENO;
348148456Spjd		else {
349148456Spjd			fd = open(str, O_RDONLY);
350148456Spjd			if (fd == -1) {
351148456Spjd				gctl_error(req, "Cannot open keyfile %s: %s.",
352148456Spjd				    str, strerror(errno));
353148456Spjd				return (NULL);
354148456Spjd			}
355148456Spjd		}
356148456Spjd		while ((done = read(fd, buf, sizeof(buf))) > 0)
357148456Spjd			g_eli_crypto_hmac_update(&ctx, buf, done);
358148456Spjd		error = errno;
359148456Spjd		if (strcmp(str, "-") != 0)
360148456Spjd			close(fd);
361148456Spjd		bzero(buf, sizeof(buf));
362148456Spjd		if (done == -1) {
363148456Spjd			gctl_error(req, "Cannot read keyfile %s: %s.", str,
364148456Spjd			    strerror(error));
365148456Spjd			return (NULL);
366148456Spjd		}
367148456Spjd	}
368148456Spjd
369153190Spjd	if (!nopassphrase) {
370148456Spjd		char buf1[BUFSIZ], buf2[BUFSIZ], *p;
371148456Spjd
372149047Spjd		if (!new && md->md_iterations == -1) {
373149047Spjd			gctl_error(req, "Missing -p flag.");
374149047Spjd			return (NULL);
375149047Spjd		}
376148456Spjd		for (;;) {
377148456Spjd			p = readpassphrase(
378148456Spjd			    new ? "Enter new passphrase:" : "Enter passphrase:",
379148456Spjd			    buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
380148456Spjd			if (p == NULL) {
381148456Spjd				bzero(buf1, sizeof(buf1));
382148456Spjd				gctl_error(req, "Cannot read passphrase: %s.",
383148456Spjd				    strerror(errno));
384148456Spjd				return (NULL);
385148456Spjd			}
386148456Spjd
387148456Spjd			if (new) {
388148456Spjd				p = readpassphrase("Reenter new passphrase: ",
389148456Spjd				    buf2, sizeof(buf2),
390148456Spjd				    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
391148456Spjd				if (p == NULL) {
392148456Spjd					bzero(buf1, sizeof(buf1));
393148456Spjd					gctl_error(req,
394148456Spjd					    "Cannot read passphrase: %s.",
395148456Spjd					    strerror(errno));
396148456Spjd					return (NULL);
397148456Spjd				}
398148456Spjd
399148456Spjd				if (strcmp(buf1, buf2) != 0) {
400148456Spjd					bzero(buf2, sizeof(buf2));
401148456Spjd					fprintf(stderr, "They didn't match.\n");
402148456Spjd					continue;
403148456Spjd				}
404148456Spjd				bzero(buf2, sizeof(buf2));
405148456Spjd			}
406148456Spjd			break;
407148456Spjd		}
408148456Spjd		/*
409148456Spjd		 * Field md_iterations equal to -1 means "choose some sane
410148456Spjd		 * value for me".
411148456Spjd		 */
412148456Spjd		if (md->md_iterations == -1) {
413148456Spjd			assert(new);
414148456Spjd			if (verbose)
415148456Spjd				printf("Calculating number of iterations...\n");
416148456Spjd			md->md_iterations = pkcs5v2_calculate(2000000);
417148456Spjd			assert(md->md_iterations > 0);
418148456Spjd			if (verbose) {
419148456Spjd				printf("Done, using %d iterations.\n",
420148456Spjd				    md->md_iterations);
421148456Spjd			}
422148456Spjd		}
423148456Spjd		/*
424161052Spjd		 * If md_iterations is equal to 0, user don't want PKCS#5v2.
425148456Spjd		 */
426148456Spjd		if (md->md_iterations == 0) {
427148456Spjd			g_eli_crypto_hmac_update(&ctx, md->md_salt,
428148456Spjd			    sizeof(md->md_salt));
429148456Spjd			g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
430148456Spjd		} else /* if (md->md_iterations > 0) */ {
431148456Spjd			unsigned char dkey[G_ELI_USERKEYLEN];
432148456Spjd
433148456Spjd			pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
434148456Spjd			    sizeof(md->md_salt), buf1, md->md_iterations);
435148456Spjd			g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
436148456Spjd			bzero(dkey, sizeof(dkey));
437148456Spjd		}
438148456Spjd		bzero(buf1, sizeof(buf1));
439148456Spjd	}
440148456Spjd	g_eli_crypto_hmac_final(&ctx, key, 0);
441148456Spjd	return (key);
442148456Spjd}
443148456Spjd
444148456Spjdstatic int
445148456Spjdeli_metadata_read(struct gctl_req *req, const char *prov,
446148456Spjd    struct g_eli_metadata *md)
447148456Spjd{
448148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
449148456Spjd	int error;
450148456Spjd
451148456Spjd	if (g_get_sectorsize(prov) == 0) {
452148456Spjd		int fd;
453148456Spjd
454148456Spjd		/* This is a file probably. */
455148456Spjd		fd = open(prov, O_RDONLY);
456148456Spjd		if (fd == -1) {
457148456Spjd			gctl_error(req, "Cannot open %s: %s.", prov,
458148456Spjd			    strerror(errno));
459148456Spjd			return (-1);
460148456Spjd		}
461148456Spjd		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
462148456Spjd			gctl_error(req, "Cannot read metadata from %s: %s.",
463148456Spjd			    prov, strerror(errno));
464148456Spjd			close(fd);
465148456Spjd			return (-1);
466148456Spjd		}
467148456Spjd		close(fd);
468148456Spjd	} else {
469148456Spjd		/* This is a GEOM provider. */
470148456Spjd		error = g_metadata_read(prov, sector, sizeof(sector),
471148456Spjd		    G_ELI_MAGIC);
472148456Spjd		if (error != 0) {
473148456Spjd			gctl_error(req, "Cannot read metadata from %s: %s.",
474148456Spjd			    prov, strerror(error));
475148456Spjd			return (-1);
476148456Spjd		}
477148456Spjd	}
478148456Spjd	if (eli_metadata_decode(sector, md) != 0) {
479148456Spjd		gctl_error(req, "MD5 hash mismatch for %s.", prov);
480148456Spjd		return (-1);
481148456Spjd	}
482148456Spjd	return (0);
483148456Spjd}
484148456Spjd
485148456Spjdstatic int
486148456Spjdeli_metadata_store(struct gctl_req *req, const char *prov,
487148456Spjd    struct g_eli_metadata *md)
488148456Spjd{
489148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
490148456Spjd	int error;
491148456Spjd
492148456Spjd	eli_metadata_encode(md, sector);
493148456Spjd	if (g_get_sectorsize(prov) == 0) {
494148456Spjd		int fd;
495148456Spjd
496148456Spjd		/* This is a file probably. */
497148456Spjd		fd = open(prov, O_WRONLY | O_TRUNC);
498148456Spjd		if (fd == -1) {
499148456Spjd			gctl_error(req, "Cannot open %s: %s.", prov,
500148456Spjd			    strerror(errno));
501148456Spjd			bzero(sector, sizeof(sector));
502148456Spjd			return (-1);
503148456Spjd		}
504148456Spjd		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
505148456Spjd			gctl_error(req, "Cannot write metadata to %s: %s.",
506148456Spjd			    prov, strerror(errno));
507148456Spjd			bzero(sector, sizeof(sector));
508148456Spjd			close(fd);
509148456Spjd			return (-1);
510148456Spjd		}
511148456Spjd		close(fd);
512148456Spjd	} else {
513148456Spjd		/* This is a GEOM provider. */
514148456Spjd		error = g_metadata_store(prov, sector, sizeof(sector));
515148456Spjd		if (error != 0) {
516148456Spjd			gctl_error(req, "Cannot write metadata to %s: %s.",
517148456Spjd			    prov, strerror(errno));
518148456Spjd			bzero(sector, sizeof(sector));
519148456Spjd			return (-1);
520148456Spjd		}
521148456Spjd	}
522148456Spjd	bzero(sector, sizeof(sector));
523148456Spjd	return (0);
524148456Spjd}
525148456Spjd
526148456Spjdstatic void
527148456Spjdeli_init(struct gctl_req *req)
528148456Spjd{
529148456Spjd	struct g_eli_metadata md;
530148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
531148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
532182452Spjd	char backfile[MAXPATHLEN];
533148456Spjd	const char *str, *prov;
534148456Spjd	unsigned secsize;
535148456Spjd	off_t mediasize;
536153190Spjd	intmax_t val;
537155536Spjd	int error, nargs;
538148456Spjd
539153190Spjd	nargs = gctl_get_int(req, "nargs");
540153190Spjd	if (nargs != 1) {
541158214Spjd		gctl_error(req, "Invalid number of arguments.");
542148456Spjd		return;
543148456Spjd	}
544153190Spjd	prov = gctl_get_ascii(req, "arg0");
545148456Spjd	mediasize = g_get_mediasize(prov);
546148456Spjd	secsize = g_get_sectorsize(prov);
547148456Spjd	if (mediasize == 0 || secsize == 0) {
548148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
549148456Spjd		    strerror(errno));
550148456Spjd		return;
551148456Spjd	}
552148456Spjd
553148456Spjd	bzero(&md, sizeof(md));
554148456Spjd	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
555148456Spjd	md.md_version = G_ELI_VERSION;
556148456Spjd	md.md_flags = 0;
557155536Spjd	if (gctl_get_int(req, "boot"))
558148456Spjd		md.md_flags |= G_ELI_FLAG_BOOT;
559159361Spjd	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
560159308Spjd	str = gctl_get_ascii(req, "aalgo");
561212547Spjd	if (*str != '\0') {
562159308Spjd		md.md_aalgo = g_eli_str2aalgo(str);
563159361Spjd		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
564159361Spjd		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
565159361Spjd			md.md_flags |= G_ELI_FLAG_AUTH;
566159361Spjd		} else {
567159361Spjd			/*
568159361Spjd			 * For backward compatibility, check if the -a option
569159361Spjd			 * was used to provide encryption algorithm.
570159361Spjd			 */
571159361Spjd			md.md_ealgo = g_eli_str2ealgo(str);
572159361Spjd			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
573159361Spjd			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
574159361Spjd				gctl_error(req,
575159361Spjd				    "Invalid authentication algorithm.");
576159361Spjd				return;
577159361Spjd			} else {
578159361Spjd				fprintf(stderr, "warning: The -e option, not "
579159361Spjd				    "the -a option is now used to specify "
580159361Spjd				    "encryption algorithm to use.\n");
581159361Spjd			}
582159308Spjd		}
583159308Spjd	}
584159308Spjd	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
585159308Spjd	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
586159361Spjd		str = gctl_get_ascii(req, "ealgo");
587159361Spjd		md.md_ealgo = g_eli_str2ealgo(str);
588159361Spjd		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
589159361Spjd		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
590159361Spjd			gctl_error(req, "Invalid encryption algorithm.");
591159361Spjd			return;
592159361Spjd		}
593148456Spjd	}
594153190Spjd	val = gctl_get_intmax(req, "keylen");
595153190Spjd	md.md_keylen = val;
596159308Spjd	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
597148456Spjd	if (md.md_keylen == 0) {
598148456Spjd		gctl_error(req, "Invalid key length.");
599148456Spjd		return;
600148456Spjd	}
601148456Spjd	md.md_provsize = mediasize;
602148456Spjd
603153190Spjd	val = gctl_get_intmax(req, "iterations");
604155536Spjd	if (val != -1) {
605155536Spjd		int nonewpassphrase;
606155536Spjd
607155536Spjd		/*
608155536Spjd		 * Don't allow to set iterations when there will be no
609155536Spjd		 * passphrase.
610155536Spjd		 */
611155536Spjd		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
612155536Spjd		if (nonewpassphrase) {
613155536Spjd			gctl_error(req,
614155536Spjd			    "Options -i and -P are mutually exclusive.");
615155536Spjd			return;
616155536Spjd		}
617155536Spjd	}
618153190Spjd	md.md_iterations = val;
619148456Spjd
620153190Spjd	val = gctl_get_intmax(req, "sectorsize");
621153190Spjd	if (val == 0)
622148456Spjd		md.md_sectorsize = secsize;
623148456Spjd	else {
624153190Spjd		if (val < 0 || (val % secsize) != 0) {
625148456Spjd			gctl_error(req, "Invalid sector size.");
626148456Spjd			return;
627148456Spjd		}
628167229Spjd		if (val > sysconf(_SC_PAGE_SIZE)) {
629167229Spjd			gctl_error(req, "warning: Using sectorsize bigger than "
630167229Spjd			    "the page size!");
631167229Spjd		}
632153190Spjd		md.md_sectorsize = val;
633148456Spjd	}
634148456Spjd
635148456Spjd	md.md_keys = 0x01;
636148456Spjd	arc4rand(md.md_salt, sizeof(md.md_salt));
637148456Spjd	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
638148456Spjd
639148456Spjd	/* Generate user key. */
640148456Spjd	if (eli_genkey(req, &md, key, 1) == NULL) {
641148456Spjd		bzero(key, sizeof(key));
642148456Spjd		bzero(&md, sizeof(md));
643148456Spjd		return;
644148456Spjd	}
645148456Spjd
646148456Spjd	/* Encrypt the first and the only Master Key. */
647159308Spjd	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
648148456Spjd	bzero(key, sizeof(key));
649148456Spjd	if (error != 0) {
650148456Spjd		bzero(&md, sizeof(md));
651148456Spjd		gctl_error(req, "Cannot encrypt Master Key: %s.",
652148456Spjd		    strerror(error));
653148456Spjd		return;
654148456Spjd	}
655148456Spjd
656148456Spjd	eli_metadata_encode(&md, sector);
657148456Spjd	bzero(&md, sizeof(md));
658148456Spjd	error = g_metadata_store(prov, sector, sizeof(sector));
659148456Spjd	bzero(sector, sizeof(sector));
660148456Spjd	if (error != 0) {
661148456Spjd		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
662148456Spjd		    strerror(error));
663148456Spjd		return;
664148456Spjd	}
665148456Spjd	if (verbose)
666148456Spjd		printf("Metadata value stored on %s.\n", prov);
667182452Spjd	/* Backup metadata to a file. */
668182452Spjd	str = gctl_get_ascii(req, "backupfile");
669182452Spjd	if (str[0] != '\0') {
670182452Spjd		/* Backupfile given be the user, just copy it. */
671182452Spjd		strlcpy(backfile, str, sizeof(backfile));
672182452Spjd	} else {
673182452Spjd		/* Generate file name automatically. */
674182452Spjd		const char *p = prov;
675182452Spjd		unsigned int i;
676182452Spjd
677182452Spjd		if (strncmp(p, _PATH_DEV, strlen(_PATH_DEV)) == 0)
678182452Spjd			p += strlen(_PATH_DEV);
679182452Spjd		snprintf(backfile, sizeof(backfile), "%s%s.eli",
680182452Spjd		    GELI_BACKUP_DIR, p);
681182452Spjd		/* Replace all / with _. */
682182452Spjd		for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
683182452Spjd			if (backfile[i] == '/')
684182452Spjd				backfile[i] = '_';
685182452Spjd		}
686182452Spjd	}
687182452Spjd	if (strcmp(backfile, "none") != 0 &&
688182452Spjd	    eli_backup_create(req, prov, backfile) == 0) {
689182452Spjd		printf("\nMetadata backup can be found in %s and\n", backfile);
690182452Spjd		printf("can be restored with the following command:\n");
691182452Spjd		printf("\n\t# geli restore %s %s\n\n", backfile, prov);
692182452Spjd	}
693148456Spjd}
694148456Spjd
695148456Spjdstatic void
696148456Spjdeli_attach(struct gctl_req *req)
697148456Spjd{
698148456Spjd	struct g_eli_metadata md;
699148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
700148456Spjd	const char *prov;
701212934Sbrian	off_t mediasize;
702153190Spjd	int nargs;
703148456Spjd
704153190Spjd	nargs = gctl_get_int(req, "nargs");
705153190Spjd	if (nargs != 1) {
706158214Spjd		gctl_error(req, "Invalid number of arguments.");
707148456Spjd		return;
708148456Spjd	}
709153190Spjd	prov = gctl_get_ascii(req, "arg0");
710148456Spjd
711148456Spjd	if (eli_metadata_read(req, prov, &md) == -1)
712148456Spjd		return;
713148456Spjd
714212934Sbrian	mediasize = g_get_mediasize(prov);
715212934Sbrian	if (md.md_provsize != (uint64_t)mediasize) {
716212934Sbrian		gctl_error(req, "Provider size mismatch.");
717212934Sbrian		return;
718212934Sbrian	}
719212934Sbrian
720148456Spjd	if (eli_genkey(req, &md, key, 0) == NULL) {
721148456Spjd		bzero(key, sizeof(key));
722148456Spjd		return;
723148456Spjd	}
724148456Spjd
725148456Spjd	gctl_ro_param(req, "key", sizeof(key), key);
726148456Spjd	if (gctl_issue(req) == NULL) {
727148456Spjd		if (verbose)
728166892Spjd			printf("Attached to %s.\n", prov);
729148456Spjd	}
730148456Spjd	bzero(key, sizeof(key));
731148456Spjd}
732148456Spjd
733148456Spjdstatic void
734162353Spjdeli_configure_detached(struct gctl_req *req, const char *prov, int boot)
735162353Spjd{
736162353Spjd	struct g_eli_metadata md;
737162353Spjd
738162353Spjd	if (eli_metadata_read(req, prov, &md) == -1)
739162353Spjd		return;
740162353Spjd
741162353Spjd	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
742162353Spjd		if (verbose)
743162353Spjd			printf("BOOT flag already configured for %s.\n", prov);
744162353Spjd	} else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) {
745162353Spjd		if (verbose)
746162353Spjd			printf("BOOT flag not configured for %s.\n", prov);
747162353Spjd	} else {
748162353Spjd		if (boot)
749162353Spjd			md.md_flags |= G_ELI_FLAG_BOOT;
750162353Spjd		else
751162353Spjd			md.md_flags &= ~G_ELI_FLAG_BOOT;
752162353Spjd		eli_metadata_store(req, prov, &md);
753162353Spjd	}
754162353Spjd	bzero(&md, sizeof(md));
755162353Spjd}
756162353Spjd
757162353Spjdstatic void
758162353Spjdeli_configure(struct gctl_req *req)
759162353Spjd{
760162353Spjd	const char *prov;
761162353Spjd	int i, nargs, boot, noboot;
762162353Spjd
763162353Spjd	nargs = gctl_get_int(req, "nargs");
764162353Spjd	if (nargs == 0) {
765162353Spjd		gctl_error(req, "Too few arguments.");
766162353Spjd		return;
767162353Spjd	}
768162353Spjd
769162353Spjd	boot = gctl_get_int(req, "boot");
770162353Spjd	noboot = gctl_get_int(req, "noboot");
771162353Spjd
772162353Spjd	if (boot && noboot) {
773162353Spjd		gctl_error(req, "Options -b and -B are mutually exclusive.");
774162353Spjd		return;
775162353Spjd	}
776162353Spjd	if (!boot && !noboot) {
777162353Spjd		gctl_error(req, "No option given.");
778162353Spjd		return;
779162353Spjd	}
780162353Spjd
781162353Spjd	/* First attached providers. */
782162353Spjd	gctl_issue(req);
783162353Spjd	/* Now the rest. */
784162353Spjd	for (i = 0; i < nargs; i++) {
785162353Spjd		prov = gctl_get_ascii(req, "arg%d", i);
786162353Spjd		if (!eli_is_attached(prov))
787162353Spjd			eli_configure_detached(req, prov, boot);
788162353Spjd	}
789162353Spjd}
790162353Spjd
791162353Spjdstatic void
792155101Spjdeli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
793148456Spjd{
794148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
795166216Spjd	intmax_t val, old = 0;
796166216Spjd	int error;
797148456Spjd
798153190Spjd	val = gctl_get_intmax(req, "iterations");
799149304Spjd	/* Check if iterations number should be changed. */
800153190Spjd	if (val != -1)
801153190Spjd		md->md_iterations = val;
802166216Spjd	else
803166216Spjd		old = md->md_iterations;
804148456Spjd
805148456Spjd	/* Generate key for Master Key encryption. */
806149304Spjd	if (eli_genkey(req, md, key, 1) == NULL) {
807148456Spjd		bzero(key, sizeof(key));
808148456Spjd		return;
809148456Spjd	}
810166216Spjd	/*
811166216Spjd	 * If number of iterations has changed, but wasn't given as a
812166216Spjd	 * command-line argument, update the request.
813166216Spjd	 */
814166216Spjd	if (val == -1 && md->md_iterations != old) {
815166216Spjd		error = gctl_change_param(req, "iterations", sizeof(intmax_t),
816166216Spjd		    &md->md_iterations);
817166216Spjd		assert(error == 0);
818166216Spjd	}
819148456Spjd
820148456Spjd	gctl_ro_param(req, "key", sizeof(key), key);
821148456Spjd	gctl_issue(req);
822148456Spjd	bzero(key, sizeof(key));
823148456Spjd}
824148456Spjd
825148456Spjdstatic void
826149304Spjdeli_setkey_detached(struct gctl_req *req, const char *prov,
827149304Spjd struct g_eli_metadata *md)
828148456Spjd{
829148456Spjd	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
830148456Spjd	unsigned char *mkeydst;
831153190Spjd	intmax_t val;
832148456Spjd	unsigned nkey;
833148456Spjd	int error;
834148456Spjd
835149928Spjd	if (md->md_keys == 0) {
836149928Spjd		gctl_error(req, "No valid keys on %s.", prov);
837149928Spjd		return;
838149928Spjd	}
839149928Spjd
840148456Spjd	/* Generate key for Master Key decryption. */
841149304Spjd	if (eli_genkey(req, md, key, 0) == NULL) {
842148456Spjd		bzero(key, sizeof(key));
843148456Spjd		return;
844148456Spjd	}
845148456Spjd
846148456Spjd	/* Decrypt Master Key. */
847149304Spjd	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
848148456Spjd	bzero(key, sizeof(key));
849148456Spjd	if (error != 0) {
850149304Spjd		bzero(md, sizeof(*md));
851148456Spjd		if (error == -1)
852148456Spjd			gctl_error(req, "Wrong key for %s.", prov);
853148456Spjd		else /* if (error > 0) */ {
854148456Spjd			gctl_error(req, "Cannot decrypt Master Key: %s.",
855148456Spjd			    strerror(error));
856148456Spjd		}
857148456Spjd		return;
858148456Spjd	}
859148456Spjd	if (verbose)
860148456Spjd		printf("Decrypted Master Key %u.\n", nkey);
861148456Spjd
862153190Spjd	val = gctl_get_intmax(req, "keyno");
863153190Spjd	if (val != -1)
864153190Spjd		nkey = val;
865148456Spjd#if 0
866148456Spjd	else
867148456Spjd		; /* Use the key number which was found during decryption. */
868148456Spjd#endif
869148456Spjd	if (nkey >= G_ELI_MAXMKEYS) {
870148456Spjd		gctl_error(req, "Invalid '%s' argument.", "keyno");
871148456Spjd		return;
872148456Spjd	}
873148456Spjd
874153190Spjd	val = gctl_get_intmax(req, "iterations");
875149304Spjd	/* Check if iterations number should and can be changed. */
876153190Spjd	if (val != -1) {
877149304Spjd		if (bitcount32(md->md_keys) != 1) {
878149304Spjd			gctl_error(req, "To be able to use '-i' option, only "
879149304Spjd			    "one key can be defined.");
880149304Spjd			return;
881149304Spjd		}
882149304Spjd		if (md->md_keys != (1 << nkey)) {
883149304Spjd			gctl_error(req, "Only already defined key can be "
884149304Spjd			    "changed when '-i' option is used.");
885149304Spjd			return;
886149304Spjd		}
887153190Spjd		md->md_iterations = val;
888149304Spjd	}
889148456Spjd
890149304Spjd	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
891149304Spjd	md->md_keys |= (1 << nkey);
892149304Spjd
893148456Spjd	bcopy(mkey, mkeydst, sizeof(mkey));
894148456Spjd	bzero(mkey, sizeof(mkey));
895148456Spjd
896148456Spjd	/* Generate key for Master Key encryption. */
897149304Spjd	if (eli_genkey(req, md, key, 1) == NULL) {
898148456Spjd		bzero(key, sizeof(key));
899149304Spjd		bzero(md, sizeof(*md));
900148456Spjd		return;
901148456Spjd	}
902148456Spjd
903148456Spjd	/* Encrypt the Master-Key with the new key. */
904159308Spjd	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
905148456Spjd	bzero(key, sizeof(key));
906148456Spjd	if (error != 0) {
907149304Spjd		bzero(md, sizeof(*md));
908148456Spjd		gctl_error(req, "Cannot encrypt Master Key: %s.",
909148456Spjd		    strerror(error));
910148456Spjd		return;
911148456Spjd	}
912148456Spjd
913148456Spjd	/* Store metadata with fresh key. */
914149304Spjd	eli_metadata_store(req, prov, md);
915149304Spjd	bzero(md, sizeof(*md));
916148456Spjd}
917148456Spjd
918148456Spjdstatic void
919148456Spjdeli_setkey(struct gctl_req *req)
920148456Spjd{
921149304Spjd	struct g_eli_metadata md;
922148456Spjd	const char *prov;
923153190Spjd	int nargs;
924148456Spjd
925153190Spjd	nargs = gctl_get_int(req, "nargs");
926153190Spjd	if (nargs != 1) {
927158214Spjd		gctl_error(req, "Invalid number of arguments.");
928148456Spjd		return;
929148456Spjd	}
930153190Spjd	prov = gctl_get_ascii(req, "arg0");
931148456Spjd
932149304Spjd	if (eli_metadata_read(req, prov, &md) == -1)
933149304Spjd		return;
934149304Spjd
935148456Spjd	if (eli_is_attached(prov))
936155101Spjd		eli_setkey_attached(req, &md);
937148456Spjd	else
938149304Spjd		eli_setkey_detached(req, prov, &md);
939182452Spjd
940182452Spjd	if (req->error == NULL || req->error[0] == '\0') {
941182452Spjd		printf("Note, that the master key encrypted with old keys "
942182452Spjd		    "and/or passphrase may still exists in a metadata backup "
943182452Spjd		    "file.\n");
944182452Spjd	}
945148456Spjd}
946148456Spjd
947148456Spjdstatic void
948148456Spjdeli_delkey_attached(struct gctl_req *req, const char *prov __unused)
949148456Spjd{
950148456Spjd
951148456Spjd	gctl_issue(req);
952148456Spjd}
953148456Spjd
954148456Spjdstatic void
955148456Spjdeli_delkey_detached(struct gctl_req *req, const char *prov)
956148456Spjd{
957148456Spjd	struct g_eli_metadata md;
958148456Spjd	unsigned char *mkeydst;
959153190Spjd	intmax_t val;
960148456Spjd	unsigned nkey;
961153190Spjd	int all, force;
962148456Spjd
963148456Spjd	if (eli_metadata_read(req, prov, &md) == -1)
964148456Spjd		return;
965148456Spjd
966153190Spjd	all = gctl_get_int(req, "all");
967153190Spjd	if (all)
968148456Spjd		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
969148456Spjd	else {
970153190Spjd		force = gctl_get_int(req, "force");
971153190Spjd		val = gctl_get_intmax(req, "keyno");
972153190Spjd		if (val == -1) {
973148456Spjd			gctl_error(req, "Key number has to be specified.");
974148456Spjd			return;
975148456Spjd		}
976153190Spjd		nkey = val;
977148456Spjd		if (nkey >= G_ELI_MAXMKEYS) {
978148456Spjd			gctl_error(req, "Invalid '%s' argument.", "keyno");
979148456Spjd			return;
980148456Spjd		}
981153190Spjd		if (!(md.md_keys & (1 << nkey)) && !force) {
982148456Spjd			gctl_error(req, "Master Key %u is not set.", nkey);
983148456Spjd			return;
984148456Spjd		}
985148456Spjd		md.md_keys &= ~(1 << nkey);
986153190Spjd		if (md.md_keys == 0 && !force) {
987148456Spjd			gctl_error(req, "This is the last Master Key. Use '-f' "
988148456Spjd			    "option if you really want to remove it.");
989148456Spjd			return;
990148456Spjd		}
991148456Spjd		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
992148456Spjd		arc4rand(mkeydst, G_ELI_MKEYLEN);
993148456Spjd	}
994148456Spjd
995148456Spjd	eli_metadata_store(req, prov, &md);
996148456Spjd	bzero(&md, sizeof(md));
997148456Spjd}
998148456Spjd
999148456Spjdstatic void
1000148456Spjdeli_delkey(struct gctl_req *req)
1001148456Spjd{
1002148456Spjd	const char *prov;
1003153190Spjd	int nargs;
1004148456Spjd
1005153190Spjd	nargs = gctl_get_int(req, "nargs");
1006153190Spjd	if (nargs != 1) {
1007158214Spjd		gctl_error(req, "Invalid number of arguments.");
1008148456Spjd		return;
1009148456Spjd	}
1010153190Spjd	prov = gctl_get_ascii(req, "arg0");
1011148456Spjd
1012148456Spjd	if (eli_is_attached(prov))
1013148456Spjd		eli_delkey_attached(req, prov);
1014148456Spjd	else
1015148456Spjd		eli_delkey_detached(req, prov);
1016148456Spjd}
1017148456Spjd
1018148456Spjdstatic void
1019148456Spjdeli_kill_detached(struct gctl_req *req, const char *prov)
1020148456Spjd{
1021148456Spjd	struct g_eli_metadata md;
1022148456Spjd	int error;
1023148456Spjd
1024148456Spjd	/*
1025148456Spjd	 * NOTE: Maybe we should verify if this is geli provider first,
1026148456Spjd	 *       but 'kill' command is quite critical so better don't waste
1027148456Spjd	 *       the time.
1028148456Spjd	 */
1029148456Spjd#if 0
1030148456Spjd	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
1031148456Spjd	    G_ELI_MAGIC);
1032148456Spjd	if (error != 0) {
1033148456Spjd		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
1034148456Spjd		    strerror(error));
1035148456Spjd		return;
1036148456Spjd	}
1037148456Spjd#endif
1038148456Spjd
1039148456Spjd	arc4rand((unsigned char *)&md, sizeof(md));
1040148456Spjd	error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
1041148456Spjd	if (error != 0) {
1042148456Spjd		gctl_error(req, "Cannot write metadata to %s: %s.", prov,
1043148456Spjd		    strerror(error));
1044148456Spjd	}
1045148456Spjd}
1046148456Spjd
1047148456Spjdstatic void
1048148456Spjdeli_kill(struct gctl_req *req)
1049148456Spjd{
1050148456Spjd	const char *prov;
1051153190Spjd	int i, nargs, all;
1052148456Spjd
1053153190Spjd	nargs = gctl_get_int(req, "nargs");
1054153190Spjd	all = gctl_get_int(req, "all");
1055153190Spjd	if (!all && nargs == 0) {
1056148456Spjd		gctl_error(req, "Too few arguments.");
1057148456Spjd		return;
1058148456Spjd	}
1059148456Spjd	/*
1060148456Spjd	 * How '-a' option combine with a list of providers:
1061148456Spjd	 * Delete Master Keys from all attached providers:
1062148456Spjd	 * geli kill -a
1063169312Spjd	 * Delete Master Keys from all attached providers and from
1064148456Spjd	 * detached da0 and da1:
1065148456Spjd	 * geli kill -a da0 da1
1066148456Spjd	 * Delete Master Keys from (attached or detached) da0 and da1:
1067148456Spjd	 * geli kill da0 da1
1068148456Spjd	 */
1069148456Spjd
1070169312Spjd	/* First detached providers. */
1071153190Spjd	for (i = 0; i < nargs; i++) {
1072153190Spjd		prov = gctl_get_ascii(req, "arg%d", i);
1073148456Spjd		if (!eli_is_attached(prov))
1074148456Spjd			eli_kill_detached(req, prov);
1075148456Spjd	}
1076162347Spjd	/* Now attached providers. */
1077162347Spjd	gctl_issue(req);
1078148456Spjd}
1079148456Spjd
1080182452Spjdstatic int
1081182452Spjdeli_backup_create(struct gctl_req *req, const char *prov, const char *file)
1082148456Spjd{
1083148456Spjd	struct g_eli_metadata md;
1084148456Spjd	unsigned secsize;
1085148456Spjd	unsigned char *sector;
1086148456Spjd	off_t mediasize;
1087182452Spjd	int filefd, provfd, ret;
1088148456Spjd
1089182452Spjd	ret = -1;
1090148456Spjd	provfd = filefd = -1;
1091148456Spjd	sector = NULL;
1092148456Spjd	secsize = 0;
1093148456Spjd
1094148456Spjd	provfd = open(prov, O_RDONLY);
1095148456Spjd	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1096148456Spjd		char devprov[MAXPATHLEN];
1097148456Spjd
1098148456Spjd		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1099148456Spjd		provfd = open(devprov, O_RDONLY);
1100148456Spjd	}
1101148456Spjd	if (provfd == -1) {
1102148456Spjd		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1103169193Spjd		goto out;
1104148456Spjd	}
1105148456Spjd	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1106148456Spjd	if (filefd == -1) {
1107148456Spjd		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1108148456Spjd		goto out;
1109148456Spjd	}
1110148456Spjd
1111148456Spjd	mediasize = g_get_mediasize(prov);
1112148456Spjd	secsize = g_get_sectorsize(prov);
1113148456Spjd	if (mediasize == 0 || secsize == 0) {
1114148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1115148456Spjd		    strerror(errno));
1116169193Spjd		goto out;
1117148456Spjd	}
1118148456Spjd
1119148456Spjd	sector = malloc(secsize);
1120148456Spjd	if (sector == NULL) {
1121148456Spjd		gctl_error(req, "Cannot allocate memory.");
1122169193Spjd		goto out;
1123148456Spjd	}
1124148456Spjd
1125148456Spjd	/* Read metadata from the provider. */
1126148456Spjd	if (pread(provfd, sector, secsize, mediasize - secsize) !=
1127148456Spjd	    (ssize_t)secsize) {
1128148456Spjd		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
1129148456Spjd		goto out;
1130148456Spjd	}
1131148456Spjd	/* Check if this is geli provider. */
1132148456Spjd	if (eli_metadata_decode(sector, &md) != 0) {
1133148456Spjd		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1134148456Spjd		goto out;
1135148456Spjd	}
1136148456Spjd	/* Write metadata to the destination file. */
1137148456Spjd	if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1138148456Spjd		gctl_error(req, "Cannot write to %s: %s.", file,
1139148456Spjd		    strerror(errno));
1140148456Spjd		goto out;
1141148456Spjd	}
1142182452Spjd	/* Success. */
1143182452Spjd	ret = 0;
1144148456Spjdout:
1145148456Spjd	if (provfd > 0)
1146148456Spjd		close(provfd);
1147148456Spjd	if (filefd > 0)
1148148456Spjd		close(filefd);
1149148456Spjd	if (sector != NULL) {
1150148456Spjd		bzero(sector, secsize);
1151148456Spjd		free(sector);
1152148456Spjd	}
1153182452Spjd	return (ret);
1154148456Spjd}
1155148456Spjd
1156148456Spjdstatic void
1157182452Spjdeli_backup(struct gctl_req *req)
1158182452Spjd{
1159182452Spjd	const char *file, *prov;
1160182452Spjd	int nargs;
1161182452Spjd
1162182452Spjd	nargs = gctl_get_int(req, "nargs");
1163182452Spjd	if (nargs != 2) {
1164182452Spjd		gctl_error(req, "Invalid number of arguments.");
1165182452Spjd		return;
1166182452Spjd	}
1167182452Spjd	prov = gctl_get_ascii(req, "arg0");
1168182452Spjd	file = gctl_get_ascii(req, "arg1");
1169182452Spjd
1170182452Spjd	eli_backup_create(req, prov, file);
1171182452Spjd}
1172182452Spjd
1173182452Spjdstatic void
1174148456Spjdeli_restore(struct gctl_req *req)
1175148456Spjd{
1176148456Spjd	struct g_eli_metadata md;
1177148456Spjd	const char *file, *prov;
1178148456Spjd	unsigned char *sector;
1179148456Spjd	unsigned secsize;
1180148456Spjd	off_t mediasize;
1181153190Spjd	int nargs, filefd, provfd;
1182148456Spjd
1183153190Spjd	nargs = gctl_get_int(req, "nargs");
1184153190Spjd	if (nargs != 2) {
1185148456Spjd		gctl_error(req, "Invalid number of arguments.");
1186148456Spjd		return;
1187148456Spjd	}
1188153190Spjd	file = gctl_get_ascii(req, "arg0");
1189153190Spjd	prov = gctl_get_ascii(req, "arg1");
1190148456Spjd
1191148456Spjd	provfd = filefd = -1;
1192148456Spjd	sector = NULL;
1193148456Spjd	secsize = 0;
1194148456Spjd
1195148456Spjd	filefd = open(file, O_RDONLY);
1196148456Spjd	if (filefd == -1) {
1197148456Spjd		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1198148456Spjd		goto out;
1199148456Spjd	}
1200148456Spjd	provfd = open(prov, O_WRONLY);
1201148456Spjd	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1202148456Spjd		char devprov[MAXPATHLEN];
1203148456Spjd
1204148456Spjd		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1205148456Spjd		provfd = open(devprov, O_WRONLY);
1206148456Spjd	}
1207148456Spjd	if (provfd == -1) {
1208148456Spjd		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1209169193Spjd		goto out;
1210148456Spjd	}
1211148456Spjd
1212148456Spjd	mediasize = g_get_mediasize(prov);
1213148456Spjd	secsize = g_get_sectorsize(prov);
1214148456Spjd	if (mediasize == 0 || secsize == 0) {
1215148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1216148456Spjd		    strerror(errno));
1217169193Spjd		goto out;
1218148456Spjd	}
1219148456Spjd
1220148456Spjd	sector = malloc(secsize);
1221148456Spjd	if (sector == NULL) {
1222148456Spjd		gctl_error(req, "Cannot allocate memory.");
1223169193Spjd		goto out;
1224148456Spjd	}
1225148456Spjd
1226148456Spjd	/* Read metadata from the backup file. */
1227148456Spjd	if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1228148456Spjd		gctl_error(req, "Cannot read from %s: %s.", file,
1229148456Spjd		    strerror(errno));
1230148456Spjd		goto out;
1231148456Spjd	}
1232148456Spjd	/* Check if this file contains geli metadata. */
1233148456Spjd	if (eli_metadata_decode(sector, &md) != 0) {
1234148456Spjd		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1235148456Spjd		goto out;
1236148456Spjd	}
1237212934Sbrian	/* Check if the provider size has changed since we did the backup. */
1238212934Sbrian	if (md.md_provsize != (uint64_t)mediasize) {
1239212934Sbrian		if (gctl_get_int(req, "force")) {
1240212934Sbrian			md.md_provsize = mediasize;
1241212934Sbrian			eli_metadata_encode(&md, sector);
1242212934Sbrian		} else {
1243212934Sbrian			gctl_error(req, "Provider size mismatch: "
1244212934Sbrian			    "wrong backup file?");
1245212934Sbrian			goto out;
1246212934Sbrian		}
1247212934Sbrian	}
1248162356Spjd	/* Write metadata from the provider. */
1249148456Spjd	if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1250148456Spjd	    (ssize_t)secsize) {
1251148456Spjd		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1252148456Spjd		goto out;
1253148456Spjd	}
1254148456Spjdout:
1255148456Spjd	if (provfd > 0)
1256148456Spjd		close(provfd);
1257148456Spjd	if (filefd > 0)
1258148456Spjd		close(filefd);
1259148456Spjd	if (sector != NULL) {
1260148456Spjd		bzero(sector, secsize);
1261148456Spjd		free(sector);
1262148456Spjd	}
1263148456Spjd}
1264148456Spjd
1265148456Spjdstatic void
1266212934Sbrianeli_resize(struct gctl_req *req)
1267212934Sbrian{
1268212934Sbrian	struct g_eli_metadata md;
1269212934Sbrian	const char *prov;
1270212934Sbrian	unsigned char *sector;
1271213056Spjd	ssize_t secsize;
1272212934Sbrian	off_t mediasize, oldsize;
1273212934Sbrian	int nargs, provfd;
1274212934Sbrian
1275212934Sbrian	nargs = gctl_get_int(req, "nargs");
1276212934Sbrian	if (nargs != 1) {
1277212934Sbrian		gctl_error(req, "Invalid number of arguments.");
1278212934Sbrian		return;
1279212934Sbrian	}
1280212934Sbrian	prov = gctl_get_ascii(req, "arg0");
1281212934Sbrian
1282212934Sbrian	provfd = -1;
1283212934Sbrian	sector = NULL;
1284212934Sbrian	secsize = 0;
1285212934Sbrian
1286213056Spjd	provfd = g_open(prov, 1);
1287212934Sbrian	if (provfd == -1) {
1288212934Sbrian		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1289212934Sbrian		goto out;
1290212934Sbrian	}
1291212934Sbrian
1292213056Spjd	mediasize = g_mediasize(provfd);
1293213056Spjd	secsize = g_sectorsize(provfd);
1294213056Spjd	if (mediasize == -1 || secsize == -1) {
1295212934Sbrian		gctl_error(req, "Cannot get information about %s: %s.", prov,
1296212934Sbrian		    strerror(errno));
1297212934Sbrian		goto out;
1298212934Sbrian	}
1299212934Sbrian
1300212934Sbrian	sector = malloc(secsize);
1301212934Sbrian	if (sector == NULL) {
1302212934Sbrian		gctl_error(req, "Cannot allocate memory.");
1303212934Sbrian		goto out;
1304212934Sbrian	}
1305212934Sbrian
1306212934Sbrian	oldsize = gctl_get_intmax(req, "oldsize");
1307212934Sbrian	if (oldsize < 0 || oldsize > mediasize) {
1308212934Sbrian		gctl_error(req, "Invalid oldsize: Out of range.");
1309212934Sbrian		goto out;
1310212934Sbrian	}
1311212934Sbrian
1312212934Sbrian	/* Read metadata from the 'oldsize' offset. */
1313213056Spjd	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
1314212934Sbrian		gctl_error(req, "Cannot read old metadata: %s.",
1315212934Sbrian		    strerror(errno));
1316212934Sbrian		goto out;
1317212934Sbrian	}
1318212934Sbrian
1319212934Sbrian	/* Check if this sector contains geli metadata. */
1320212934Sbrian	if (eli_metadata_decode(sector, &md) != 0) {
1321212934Sbrian		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
1322212934Sbrian		goto out;
1323212934Sbrian	}
1324212934Sbrian
1325212934Sbrian	/*
1326212934Sbrian	 * If the old metadata doesn't have a correct provider size, refuse
1327212934Sbrian	 * to resize.
1328212934Sbrian	 */
1329212934Sbrian	if (md.md_provsize != (uint64_t)oldsize) {
1330212934Sbrian		gctl_error(req, "Provider size mismatch at oldsize.");
1331212934Sbrian		goto out;
1332212934Sbrian	}
1333212934Sbrian
1334212934Sbrian	/*
1335212934Sbrian	 * Update the old metadata with the current provider size and write
1336212934Sbrian	 * it back to the correct place on the provider.
1337212934Sbrian	 */
1338212934Sbrian	md.md_provsize = mediasize;
1339212934Sbrian	eli_metadata_encode(&md, sector);
1340213056Spjd	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
1341212934Sbrian		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1342212934Sbrian		goto out;
1343212934Sbrian	}
1344212934Sbrian
1345212934Sbrian	/* Now trash the old metadata. */
1346212934Sbrian	arc4rand(sector, secsize);
1347213056Spjd	if (pwrite(provfd, sector, secsize, oldsize - secsize) != secsize) {
1348212934Sbrian		gctl_error(req, "Failed to clobber old metadata: %s.",
1349212934Sbrian		    strerror(errno));
1350212934Sbrian		goto out;
1351212934Sbrian	}
1352212934Sbrianout:
1353213056Spjd	if (provfd >= 0)
1354213056Spjd		(void)g_close(provfd);
1355212934Sbrian	if (sector != NULL) {
1356212934Sbrian		bzero(sector, secsize);
1357212934Sbrian		free(sector);
1358212934Sbrian	}
1359212934Sbrian}
1360212934Sbrian
1361212934Sbrianstatic void
1362148456Spjdeli_clear(struct gctl_req *req)
1363148456Spjd{
1364148456Spjd	const char *name;
1365153190Spjd	int error, i, nargs;
1366148456Spjd
1367153190Spjd	nargs = gctl_get_int(req, "nargs");
1368153190Spjd	if (nargs < 1) {
1369148456Spjd		gctl_error(req, "Too few arguments.");
1370148456Spjd		return;
1371148456Spjd	}
1372148456Spjd
1373153190Spjd	for (i = 0; i < nargs; i++) {
1374153190Spjd		name = gctl_get_ascii(req, "arg%d", i);
1375148456Spjd		error = g_metadata_clear(name, G_ELI_MAGIC);
1376148456Spjd		if (error != 0) {
1377148456Spjd			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1378148456Spjd			    name, strerror(error));
1379148456Spjd			gctl_error(req, "Not fully done.");
1380148456Spjd			continue;
1381148456Spjd		}
1382148456Spjd		if (verbose)
1383155175Spjd			printf("Metadata cleared on %s.\n", name);
1384148456Spjd	}
1385148456Spjd}
1386148456Spjd
1387148456Spjdstatic void
1388148456Spjdeli_dump(struct gctl_req *req)
1389148456Spjd{
1390148456Spjd	struct g_eli_metadata md, tmpmd;
1391148456Spjd	const char *name;
1392153190Spjd	int error, i, nargs;
1393148456Spjd
1394153190Spjd	nargs = gctl_get_int(req, "nargs");
1395153190Spjd	if (nargs < 1) {
1396148456Spjd		gctl_error(req, "Too few arguments.");
1397148456Spjd		return;
1398148456Spjd	}
1399148456Spjd
1400153190Spjd	for (i = 0; i < nargs; i++) {
1401153190Spjd		name = gctl_get_ascii(req, "arg%d", i);
1402148456Spjd		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1403148456Spjd		    sizeof(tmpmd), G_ELI_MAGIC);
1404148456Spjd		if (error != 0) {
1405148456Spjd			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1406148456Spjd			    name, strerror(error));
1407148456Spjd			gctl_error(req, "Not fully done.");
1408148456Spjd			continue;
1409148456Spjd		}
1410148456Spjd		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1411148456Spjd			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1412148456Spjd			    name);
1413148456Spjd			gctl_error(req, "Not fully done.");
1414148456Spjd			continue;
1415148456Spjd		}
1416148456Spjd		printf("Metadata on %s:\n", name);
1417148456Spjd		eli_metadata_dump(&md);
1418148456Spjd		printf("\n");
1419148456Spjd	}
1420148456Spjd}
1421