geom_eli.c revision 226716
1148456Spjd/*-
2213073Spjd * Copyright (c) 2004-2010 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 226716 2011-10-25 07:31:13Z pjd $");
29148456Spjd
30226715Spjd#include <sys/param.h>
31226715Spjd#include <sys/mman.h>
32213060Spjd#include <sys/sysctl.h>
33226715Spjd#include <sys/resource.h>
34226715Spjd#include <opencrypto/cryptodev.h>
35213060Spjd
36226715Spjd#include <assert.h>
37226715Spjd#include <err.h>
38226715Spjd#include <errno.h>
39226715Spjd#include <fcntl.h>
40226715Spjd#include <libgeom.h>
41226715Spjd#include <paths.h>
42226715Spjd#include <readpassphrase.h>
43213172Spjd#include <stdbool.h>
44226715Spjd#include <stdint.h>
45148456Spjd#include <stdio.h>
46148456Spjd#include <stdlib.h>
47148456Spjd#include <string.h>
48148456Spjd#include <strings.h>
49226715Spjd#include <unistd.h>
50148456Spjd
51148456Spjd#include <geom/eli/g_eli.h>
52148456Spjd#include <geom/eli/pkcs5v2.h>
53148456Spjd
54148456Spjd#include "core/geom.h"
55148456Spjd#include "misc/subr.h"
56148456Spjd
57148456Spjd
58148456Spjduint32_t lib_version = G_LIB_VERSION;
59148456Spjduint32_t version = G_ELI_VERSION;
60148456Spjd
61182452Spjd#define	GELI_BACKUP_DIR	"/var/backups/"
62212547Spjd#define	GELI_ENC_ALGO	"aes"
63182452Spjd
64148456Spjdstatic void eli_main(struct gctl_req *req, unsigned flags);
65148456Spjdstatic void eli_init(struct gctl_req *req);
66148456Spjdstatic void eli_attach(struct gctl_req *req);
67162353Spjdstatic void eli_configure(struct gctl_req *req);
68148456Spjdstatic void eli_setkey(struct gctl_req *req);
69148456Spjdstatic void eli_delkey(struct gctl_req *req);
70214118Spjdstatic void eli_resume(struct gctl_req *req);
71148456Spjdstatic void eli_kill(struct gctl_req *req);
72148456Spjdstatic void eli_backup(struct gctl_req *req);
73148456Spjdstatic void eli_restore(struct gctl_req *req);
74212934Sbrianstatic void eli_resize(struct gctl_req *req);
75148456Spjdstatic void eli_clear(struct gctl_req *req);
76148456Spjdstatic void eli_dump(struct gctl_req *req);
77148456Spjd
78182452Spjdstatic int eli_backup_create(struct gctl_req *req, const char *prov,
79182452Spjd    const char *file);
80182452Spjd
81148456Spjd/*
82148456Spjd * Available commands:
83148456Spjd *
84213172Spjd * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
85148456Spjd * label - alias for 'init'
86213172Spjd * attach [-dprv] [-j passfile] [-k keyfile] prov
87148456Spjd * detach [-fl] prov ...
88148456Spjd * stop - alias for 'detach'
89181639Spjd * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov
90162353Spjd * configure [-bB] prov ...
91213172Spjd * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
92148456Spjd * delkey [-afv] [-n keyno] prov
93214118Spjd * suspend [-v] -a | prov ...
94214118Spjd * resume [-pv] [-j passfile] [-k keyfile] prov
95148456Spjd * kill [-av] [prov ...]
96148456Spjd * backup [-v] prov file
97212934Sbrian * restore [-fv] file prov
98212934Sbrian * resize [-v] -s oldsize prov
99148456Spjd * clear [-v] prov ...
100148456Spjd * dump [-v] prov ...
101148456Spjd */
102148456Spjdstruct g_command class_commands[] = {
103148456Spjd	{ "init", G_FLAG_VERBOSE, eli_main,
104148456Spjd	    {
105212547Spjd		{ 'a', "aalgo", "", G_TYPE_STRING },
106162868Spjd		{ 'b', "boot", NULL, G_TYPE_BOOL },
107212547Spjd		{ 'B', "backupfile", "", G_TYPE_STRING },
108212547Spjd		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
109212554Spjd		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
110213172Spjd		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
111213172Spjd		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
112212554Spjd		{ 'l', "keylen", "0", G_TYPE_NUMBER },
113162868Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
114212554Spjd		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
115148456Spjd		G_OPT_SENTINEL
116148456Spjd	    },
117213172Spjd	    "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
118148456Spjd	},
119148456Spjd	{ "label", G_FLAG_VERBOSE, eli_main,
120148456Spjd	    {
121212547Spjd		{ 'a', "aalgo", "", G_TYPE_STRING },
122162868Spjd		{ 'b', "boot", NULL, G_TYPE_BOOL },
123212547Spjd		{ 'B', "backupfile", "", G_TYPE_STRING },
124212547Spjd		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
125212554Spjd		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
126213172Spjd		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
127213172Spjd		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
128212554Spjd		{ 'l', "keylen", "0", G_TYPE_NUMBER },
129162868Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
130212554Spjd		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
131148456Spjd		G_OPT_SENTINEL
132148456Spjd	    },
133212554Spjd	    "- an alias for 'init'"
134148456Spjd	},
135148456Spjd	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
136148456Spjd	    {
137162868Spjd		{ 'd', "detach", NULL, G_TYPE_BOOL },
138213172Spjd		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
139213172Spjd		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
140162868Spjd		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
141162868Spjd		{ 'r', "readonly", NULL, G_TYPE_BOOL },
142148456Spjd		G_OPT_SENTINEL
143148456Spjd	    },
144213172Spjd	    "[-dprv] [-j passfile] [-k keyfile] prov"
145148456Spjd	},
146148456Spjd	{ "detach", 0, NULL,
147148456Spjd	    {
148162868Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
149162868Spjd		{ 'l', "last", NULL, G_TYPE_BOOL },
150148456Spjd		G_OPT_SENTINEL
151148456Spjd	    },
152212554Spjd	    "[-fl] prov ..."
153148456Spjd	},
154148456Spjd	{ "stop", 0, NULL,
155148456Spjd	    {
156162868Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
157162868Spjd		{ 'l', "last", NULL, G_TYPE_BOOL },
158148456Spjd		G_OPT_SENTINEL
159148456Spjd	    },
160212554Spjd	    "- an alias for 'detach'"
161148456Spjd	},
162148456Spjd	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
163148456Spjd	    {
164212547Spjd		{ 'a', "aalgo", "", G_TYPE_STRING },
165162868Spjd		{ 'd', "detach", NULL, G_TYPE_BOOL },
166212547Spjd		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
167212554Spjd		{ 'l', "keylen", "0", G_TYPE_NUMBER },
168212554Spjd		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
169148456Spjd		G_OPT_SENTINEL
170148456Spjd	    },
171212554Spjd	    "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov"
172148456Spjd	},
173162353Spjd	{ "configure", G_FLAG_VERBOSE, eli_main,
174162353Spjd	    {
175162868Spjd		{ 'b', "boot", NULL, G_TYPE_BOOL },
176162868Spjd		{ 'B', "noboot", NULL, G_TYPE_BOOL },
177162353Spjd		G_OPT_SENTINEL
178162353Spjd	    },
179212554Spjd	    "[-bB] prov ..."
180162353Spjd	},
181148456Spjd	{ "setkey", G_FLAG_VERBOSE, eli_main,
182148456Spjd	    {
183212554Spjd		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
184213172Spjd		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
185213172Spjd		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
186213172Spjd		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
187213172Spjd		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
188212554Spjd		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
189162868Spjd		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
190162868Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
191148456Spjd		G_OPT_SENTINEL
192148456Spjd	    },
193213172Spjd	    "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
194148456Spjd	},
195148456Spjd	{ "delkey", G_FLAG_VERBOSE, eli_main,
196148456Spjd	    {
197162868Spjd		{ 'a', "all", NULL, G_TYPE_BOOL },
198162868Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
199212554Spjd		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
200148456Spjd		G_OPT_SENTINEL
201148456Spjd	    },
202212554Spjd	    "[-afv] [-n keyno] prov"
203148456Spjd	},
204214118Spjd	{ "suspend", G_FLAG_VERBOSE, NULL,
205214118Spjd	    {
206214118Spjd		{ 'a', "all", NULL, G_TYPE_BOOL },
207214118Spjd		G_OPT_SENTINEL
208214118Spjd	    },
209214118Spjd	    "[-v] -a | prov ..."
210214118Spjd	},
211214118Spjd	{ "resume", G_FLAG_VERBOSE, eli_main,
212214118Spjd	    {
213214118Spjd		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
214214118Spjd		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
215214118Spjd		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
216214118Spjd		G_OPT_SENTINEL
217214118Spjd	    },
218214118Spjd	    "[-pv] [-j passfile] [-k keyfile] prov"
219214118Spjd	},
220148456Spjd	{ "kill", G_FLAG_VERBOSE, eli_main,
221148456Spjd	    {
222162868Spjd		{ 'a', "all", NULL, G_TYPE_BOOL },
223148456Spjd		G_OPT_SENTINEL
224148456Spjd	    },
225212554Spjd	    "[-av] [prov ...]"
226148456Spjd	},
227212554Spjd	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
228148456Spjd	    "[-v] prov file"
229148456Spjd	},
230212934Sbrian	{ "restore", G_FLAG_VERBOSE, eli_main,
231212934Sbrian	    {
232212934Sbrian		{ 'f', "force", NULL, G_TYPE_BOOL },
233212934Sbrian		G_OPT_SENTINEL
234212934Sbrian	    },
235212934Sbrian	    "[-fv] file prov"
236148456Spjd	},
237212934Sbrian	{ "resize", G_FLAG_VERBOSE, eli_main,
238212934Sbrian	    {
239212934Sbrian		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
240212934Sbrian		G_OPT_SENTINEL
241212934Sbrian	    },
242212934Sbrian	    "[-v] -s oldsize prov"
243212934Sbrian	},
244212554Spjd	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
245148456Spjd	    "[-v] prov ..."
246148456Spjd	},
247212554Spjd	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
248148456Spjd	    "[-v] prov ..."
249148456Spjd	},
250148456Spjd	G_CMD_SENTINEL
251148456Spjd};
252148456Spjd
253148456Spjdstatic int verbose = 0;
254148456Spjd
255148456Spjdstatic int
256148456Spjdeli_protect(struct gctl_req *req)
257148456Spjd{
258148456Spjd	struct rlimit rl;
259148456Spjd
260148456Spjd	/* Disable core dumps. */
261148456Spjd	rl.rlim_cur = 0;
262148456Spjd	rl.rlim_max = 0;
263148456Spjd	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
264148456Spjd		gctl_error(req, "Cannot disable core dumps: %s.",
265148456Spjd		    strerror(errno));
266148456Spjd		return (-1);
267148456Spjd	}
268148456Spjd	/* Disable swapping. */
269148456Spjd	if (mlockall(MCL_FUTURE) == -1) {
270148456Spjd		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
271148456Spjd		return (-1);
272148456Spjd	}
273148456Spjd	return (0);
274148456Spjd}
275148456Spjd
276148456Spjdstatic void
277213172Spjdeli_main(struct gctl_req *req, unsigned int flags)
278148456Spjd{
279148456Spjd	const char *name;
280148456Spjd
281148456Spjd	if (eli_protect(req) == -1)
282148456Spjd		return;
283148456Spjd
284148456Spjd	if ((flags & G_FLAG_VERBOSE) != 0)
285148456Spjd		verbose = 1;
286148456Spjd
287153190Spjd	name = gctl_get_ascii(req, "verb");
288148456Spjd	if (name == NULL) {
289148456Spjd		gctl_error(req, "No '%s' argument.", "verb");
290148456Spjd		return;
291148456Spjd	}
292148456Spjd	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
293148456Spjd		eli_init(req);
294148456Spjd	else if (strcmp(name, "attach") == 0)
295148456Spjd		eli_attach(req);
296162353Spjd	else if (strcmp(name, "configure") == 0)
297162353Spjd		eli_configure(req);
298148456Spjd	else if (strcmp(name, "setkey") == 0)
299148456Spjd		eli_setkey(req);
300148456Spjd	else if (strcmp(name, "delkey") == 0)
301148456Spjd		eli_delkey(req);
302214118Spjd	else if (strcmp(name, "resume") == 0)
303214118Spjd		eli_resume(req);
304148456Spjd	else if (strcmp(name, "kill") == 0)
305148456Spjd		eli_kill(req);
306148456Spjd	else if (strcmp(name, "backup") == 0)
307148456Spjd		eli_backup(req);
308148456Spjd	else if (strcmp(name, "restore") == 0)
309148456Spjd		eli_restore(req);
310212934Sbrian	else if (strcmp(name, "resize") == 0)
311212934Sbrian		eli_resize(req);
312148456Spjd	else if (strcmp(name, "dump") == 0)
313148456Spjd		eli_dump(req);
314148456Spjd	else if (strcmp(name, "clear") == 0)
315148456Spjd		eli_clear(req);
316148456Spjd	else
317148456Spjd		gctl_error(req, "Unknown command: %s.", name);
318148456Spjd}
319148456Spjd
320148456Spjdstatic void
321148456Spjdarc4rand(unsigned char *buf, size_t size)
322148456Spjd{
323148456Spjd	uint32_t *buf4;
324148456Spjd	size_t size4;
325213172Spjd	unsigned int i;
326148456Spjd
327148456Spjd	buf4 = (uint32_t *)buf;
328148456Spjd	size4 = size / 4;
329148456Spjd
330148456Spjd	for (i = 0; i < size4; i++)
331148456Spjd		buf4[i] = arc4random();
332148456Spjd	for (i *= 4; i < size; i++)
333148456Spjd		buf[i] = arc4random() % 0xff;
334148456Spjd}
335148456Spjd
336148456Spjdstatic int
337148456Spjdeli_is_attached(const char *prov)
338148456Spjd{
339148456Spjd	char name[MAXPATHLEN];
340148456Spjd	unsigned secsize;
341148456Spjd
342148456Spjd	/*
343148456Spjd	 * Not the best way to do it, but the easiest.
344148456Spjd	 * We try to open provider and check if it is a GEOM provider
345148456Spjd	 * by asking about its sectorsize.
346148456Spjd	 */
347148456Spjd	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
348148456Spjd	secsize = g_get_sectorsize(name);
349148456Spjd	if (secsize > 0)
350148456Spjd		return (1);
351148456Spjd	return (0);
352148456Spjd}
353148456Spjd
354213172Spjdstatic int
355213172Spjdeli_genkey_files(struct gctl_req *req, bool new, const char *type,
356213172Spjd    struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize)
357148456Spjd{
358213172Spjd	char *p, buf[MAXPHYS], argname[16];
359213172Spjd	const char *file;
360213172Spjd	int error, fd, i;
361213172Spjd	ssize_t done;
362148456Spjd
363213172Spjd	assert((strcmp(type, "keyfile") == 0 && ctxp != NULL &&
364213172Spjd	    passbuf == NULL && passbufsize == 0) ||
365213172Spjd	    (strcmp(type, "passfile") == 0 && ctxp == NULL &&
366213172Spjd	    passbuf != NULL && passbufsize > 0));
367213172Spjd	assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0');
368148456Spjd
369213172Spjd	for (i = 0; ; i++) {
370213172Spjd		snprintf(argname, sizeof(argname), "%s%s%d",
371213172Spjd		    new ? "new" : "", type, i);
372148456Spjd
373213172Spjd		/* No more {key,pass}files? */
374213172Spjd		if (!gctl_has_param(req, argname))
375213172Spjd			return (i);
376148456Spjd
377215704Sbrucec		file = gctl_get_ascii(req, "%s", argname);
378213172Spjd		assert(file != NULL);
379213172Spjd
380213172Spjd		if (strcmp(file, "-") == 0)
381148456Spjd			fd = STDIN_FILENO;
382148456Spjd		else {
383213172Spjd			fd = open(file, O_RDONLY);
384148456Spjd			if (fd == -1) {
385213172Spjd				gctl_error(req, "Cannot open %s %s: %s.",
386213172Spjd				    type, file, strerror(errno));
387213172Spjd				return (-1);
388148456Spjd			}
389148456Spjd		}
390213172Spjd		if (strcmp(type, "keyfile") == 0) {
391213172Spjd			while ((done = read(fd, buf, sizeof(buf))) > 0)
392213172Spjd				g_eli_crypto_hmac_update(ctxp, buf, done);
393213172Spjd		} else /* if (strcmp(type, "passfile") == 0) */ {
394213172Spjd			while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) {
395213172Spjd				buf[done] = '\0';
396213172Spjd				p = strchr(buf, '\n');
397213172Spjd				if (p != NULL) {
398213172Spjd					*p = '\0';
399213172Spjd					done = p - buf;
400213172Spjd				}
401213172Spjd				if (strlcat(passbuf, buf, passbufsize) >=
402213172Spjd				    passbufsize) {
403213172Spjd					gctl_error(req,
404213172Spjd					    "Passphrase in %s too long.", file);
405213172Spjd					bzero(buf, sizeof(buf));
406213172Spjd					return (-1);
407213172Spjd				}
408213172Spjd				if (p != NULL)
409213172Spjd					break;
410213172Spjd			}
411213172Spjd		}
412148456Spjd		error = errno;
413213172Spjd		if (strcmp(file, "-") != 0)
414148456Spjd			close(fd);
415148456Spjd		bzero(buf, sizeof(buf));
416148456Spjd		if (done == -1) {
417213172Spjd			gctl_error(req, "Cannot read %s %s: %s.",
418213172Spjd			    type, file, strerror(error));
419213172Spjd			return (-1);
420148456Spjd		}
421148456Spjd	}
422213172Spjd	/* NOTREACHED */
423213172Spjd}
424148456Spjd
425213172Spjdstatic int
426213172Spjdeli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf,
427213172Spjd    size_t passbufsize)
428213172Spjd{
429213172Spjd	char *p;
430148456Spjd
431213172Spjd	for (;;) {
432213172Spjd		p = readpassphrase(
433213172Spjd		    new ? "Enter new passphrase:" : "Enter passphrase:",
434213172Spjd		    passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY);
435213172Spjd		if (p == NULL) {
436213172Spjd			bzero(passbuf, passbufsize);
437213172Spjd			gctl_error(req, "Cannot read passphrase: %s.",
438213172Spjd			    strerror(errno));
439213172Spjd			return (-1);
440149047Spjd		}
441213172Spjd
442213172Spjd		if (new) {
443213172Spjd			char tmpbuf[BUFSIZ];
444213172Spjd
445213172Spjd			p = readpassphrase("Reenter new passphrase: ",
446213172Spjd			    tmpbuf, sizeof(tmpbuf),
447213172Spjd			    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
448148456Spjd			if (p == NULL) {
449213172Spjd				bzero(passbuf, passbufsize);
450213172Spjd				gctl_error(req,
451213172Spjd				    "Cannot read passphrase: %s.",
452148456Spjd				    strerror(errno));
453213172Spjd				return (-1);
454148456Spjd			}
455213172Spjd
456213172Spjd			if (strcmp(passbuf, tmpbuf) != 0) {
457213172Spjd				bzero(passbuf, passbufsize);
458213172Spjd				fprintf(stderr, "They didn't match.\n");
459213172Spjd				continue;
460148456Spjd			}
461213172Spjd			bzero(tmpbuf, sizeof(tmpbuf));
462148456Spjd		}
463213172Spjd		return (0);
464213172Spjd	}
465213172Spjd	/* NOTREACHED */
466213172Spjd}
467213172Spjd
468213172Spjdstatic int
469213172Spjdeli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new,
470213172Spjd    struct hmac_ctx *ctxp)
471213172Spjd{
472213172Spjd	char passbuf[MAXPHYS];
473213172Spjd	bool nopassphrase;
474213172Spjd	int nfiles;
475213172Spjd
476213172Spjd	nopassphrase =
477213172Spjd	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
478213172Spjd	if (nopassphrase) {
479213172Spjd		if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) {
480213172Spjd			gctl_error(req,
481213172Spjd			    "Options -%c and -%c are mutually exclusive.",
482213172Spjd			    new ? 'J' : 'j', new ? 'P' : 'p');
483213172Spjd			return (-1);
484148456Spjd		}
485213172Spjd		return (0);
486213172Spjd	}
487148456Spjd
488213172Spjd	if (!new && md->md_iterations == -1) {
489213172Spjd		gctl_error(req, "Missing -p flag.");
490213172Spjd		return (-1);
491213172Spjd	}
492213172Spjd	passbuf[0] = '\0';
493213172Spjd	nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf,
494213172Spjd	    sizeof(passbuf));
495213172Spjd	if (nfiles == -1)
496213172Spjd		return (-1);
497213172Spjd	else if (nfiles == 0) {
498213172Spjd		if (eli_genkey_passphrase_prompt(req, new, passbuf,
499213172Spjd		    sizeof(passbuf)) == -1) {
500213172Spjd			return (-1);
501148456Spjd		}
502148456Spjd	}
503213172Spjd	/*
504213172Spjd	 * Field md_iterations equal to -1 means "choose some sane
505213172Spjd	 * value for me".
506213172Spjd	 */
507213172Spjd	if (md->md_iterations == -1) {
508213172Spjd		assert(new);
509213172Spjd		if (verbose)
510213172Spjd			printf("Calculating number of iterations...\n");
511213172Spjd		md->md_iterations = pkcs5v2_calculate(2000000);
512213172Spjd		assert(md->md_iterations > 0);
513213172Spjd		if (verbose) {
514213172Spjd			printf("Done, using %d iterations.\n",
515213172Spjd			    md->md_iterations);
516213172Spjd		}
517213172Spjd	}
518213172Spjd	/*
519213172Spjd	 * If md_iterations is equal to 0, user doesn't want PKCS#5v2.
520213172Spjd	 */
521213172Spjd	if (md->md_iterations == 0) {
522213172Spjd		g_eli_crypto_hmac_update(ctxp, md->md_salt,
523213172Spjd		    sizeof(md->md_salt));
524213172Spjd		g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf));
525213172Spjd	} else /* if (md->md_iterations > 0) */ {
526213172Spjd		unsigned char dkey[G_ELI_USERKEYLEN];
527213172Spjd
528213172Spjd		pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
529213172Spjd		    sizeof(md->md_salt), passbuf, md->md_iterations);
530213172Spjd		g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey));
531213172Spjd		bzero(dkey, sizeof(dkey));
532213172Spjd	}
533213172Spjd	bzero(passbuf, sizeof(passbuf));
534213172Spjd
535213172Spjd	return (0);
536213172Spjd}
537213172Spjd
538213172Spjdstatic unsigned char *
539213172Spjdeli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
540213172Spjd    bool new)
541213172Spjd{
542213172Spjd	struct hmac_ctx ctx;
543213172Spjd	bool nopassphrase;
544213172Spjd	int nfiles;
545213172Spjd
546213172Spjd	nopassphrase =
547213172Spjd	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
548213172Spjd
549213172Spjd	g_eli_crypto_hmac_init(&ctx, NULL, 0);
550213172Spjd
551213172Spjd	nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0);
552213172Spjd	if (nfiles == -1)
553213172Spjd		return (NULL);
554213172Spjd	else if (nfiles == 0 && nopassphrase) {
555213172Spjd		gctl_error(req, "No key components given.");
556213172Spjd		return (NULL);
557213172Spjd	}
558213172Spjd
559213172Spjd	if (eli_genkey_passphrase(req, md, new, &ctx) == -1)
560213172Spjd		return (NULL);
561213172Spjd
562148456Spjd	g_eli_crypto_hmac_final(&ctx, key, 0);
563213172Spjd
564148456Spjd	return (key);
565148456Spjd}
566148456Spjd
567148456Spjdstatic int
568148456Spjdeli_metadata_read(struct gctl_req *req, const char *prov,
569148456Spjd    struct g_eli_metadata *md)
570148456Spjd{
571148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
572148456Spjd	int error;
573148456Spjd
574148456Spjd	if (g_get_sectorsize(prov) == 0) {
575148456Spjd		int fd;
576148456Spjd
577148456Spjd		/* This is a file probably. */
578148456Spjd		fd = open(prov, O_RDONLY);
579148456Spjd		if (fd == -1) {
580148456Spjd			gctl_error(req, "Cannot open %s: %s.", prov,
581148456Spjd			    strerror(errno));
582148456Spjd			return (-1);
583148456Spjd		}
584148456Spjd		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
585148456Spjd			gctl_error(req, "Cannot read metadata from %s: %s.",
586148456Spjd			    prov, strerror(errno));
587148456Spjd			close(fd);
588148456Spjd			return (-1);
589148456Spjd		}
590148456Spjd		close(fd);
591148456Spjd	} else {
592148456Spjd		/* This is a GEOM provider. */
593148456Spjd		error = g_metadata_read(prov, sector, sizeof(sector),
594148456Spjd		    G_ELI_MAGIC);
595148456Spjd		if (error != 0) {
596148456Spjd			gctl_error(req, "Cannot read metadata from %s: %s.",
597148456Spjd			    prov, strerror(error));
598148456Spjd			return (-1);
599148456Spjd		}
600148456Spjd	}
601148456Spjd	if (eli_metadata_decode(sector, md) != 0) {
602148456Spjd		gctl_error(req, "MD5 hash mismatch for %s.", prov);
603148456Spjd		return (-1);
604148456Spjd	}
605148456Spjd	return (0);
606148456Spjd}
607148456Spjd
608148456Spjdstatic int
609148456Spjdeli_metadata_store(struct gctl_req *req, const char *prov,
610148456Spjd    struct g_eli_metadata *md)
611148456Spjd{
612148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
613148456Spjd	int error;
614148456Spjd
615148456Spjd	eli_metadata_encode(md, sector);
616148456Spjd	if (g_get_sectorsize(prov) == 0) {
617148456Spjd		int fd;
618148456Spjd
619148456Spjd		/* This is a file probably. */
620148456Spjd		fd = open(prov, O_WRONLY | O_TRUNC);
621148456Spjd		if (fd == -1) {
622148456Spjd			gctl_error(req, "Cannot open %s: %s.", prov,
623148456Spjd			    strerror(errno));
624148456Spjd			bzero(sector, sizeof(sector));
625148456Spjd			return (-1);
626148456Spjd		}
627148456Spjd		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
628148456Spjd			gctl_error(req, "Cannot write metadata to %s: %s.",
629148456Spjd			    prov, strerror(errno));
630148456Spjd			bzero(sector, sizeof(sector));
631148456Spjd			close(fd);
632148456Spjd			return (-1);
633148456Spjd		}
634148456Spjd		close(fd);
635148456Spjd	} else {
636148456Spjd		/* This is a GEOM provider. */
637148456Spjd		error = g_metadata_store(prov, sector, sizeof(sector));
638148456Spjd		if (error != 0) {
639148456Spjd			gctl_error(req, "Cannot write metadata to %s: %s.",
640148456Spjd			    prov, strerror(errno));
641148456Spjd			bzero(sector, sizeof(sector));
642148456Spjd			return (-1);
643148456Spjd		}
644148456Spjd	}
645148456Spjd	bzero(sector, sizeof(sector));
646148456Spjd	return (0);
647148456Spjd}
648148456Spjd
649148456Spjdstatic void
650148456Spjdeli_init(struct gctl_req *req)
651148456Spjd{
652148456Spjd	struct g_eli_metadata md;
653148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
654148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
655182452Spjd	char backfile[MAXPATHLEN];
656148456Spjd	const char *str, *prov;
657148456Spjd	unsigned secsize;
658148456Spjd	off_t mediasize;
659153190Spjd	intmax_t val;
660155536Spjd	int error, nargs;
661148456Spjd
662153190Spjd	nargs = gctl_get_int(req, "nargs");
663153190Spjd	if (nargs != 1) {
664158214Spjd		gctl_error(req, "Invalid number of arguments.");
665148456Spjd		return;
666148456Spjd	}
667153190Spjd	prov = gctl_get_ascii(req, "arg0");
668148456Spjd	mediasize = g_get_mediasize(prov);
669148456Spjd	secsize = g_get_sectorsize(prov);
670148456Spjd	if (mediasize == 0 || secsize == 0) {
671148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
672148456Spjd		    strerror(errno));
673148456Spjd		return;
674148456Spjd	}
675148456Spjd
676148456Spjd	bzero(&md, sizeof(md));
677148456Spjd	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
678148456Spjd	md.md_version = G_ELI_VERSION;
679148456Spjd	md.md_flags = 0;
680155536Spjd	if (gctl_get_int(req, "boot"))
681148456Spjd		md.md_flags |= G_ELI_FLAG_BOOT;
682159361Spjd	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
683159308Spjd	str = gctl_get_ascii(req, "aalgo");
684212547Spjd	if (*str != '\0') {
685159308Spjd		md.md_aalgo = g_eli_str2aalgo(str);
686159361Spjd		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
687159361Spjd		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
688159361Spjd			md.md_flags |= G_ELI_FLAG_AUTH;
689159361Spjd		} else {
690159361Spjd			/*
691159361Spjd			 * For backward compatibility, check if the -a option
692159361Spjd			 * was used to provide encryption algorithm.
693159361Spjd			 */
694159361Spjd			md.md_ealgo = g_eli_str2ealgo(str);
695159361Spjd			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
696159361Spjd			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
697159361Spjd				gctl_error(req,
698159361Spjd				    "Invalid authentication algorithm.");
699159361Spjd				return;
700159361Spjd			} else {
701159361Spjd				fprintf(stderr, "warning: The -e option, not "
702159361Spjd				    "the -a option is now used to specify "
703159361Spjd				    "encryption algorithm to use.\n");
704159361Spjd			}
705159308Spjd		}
706159308Spjd	}
707159308Spjd	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
708159308Spjd	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
709159361Spjd		str = gctl_get_ascii(req, "ealgo");
710159361Spjd		md.md_ealgo = g_eli_str2ealgo(str);
711159361Spjd		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
712159361Spjd		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
713159361Spjd			gctl_error(req, "Invalid encryption algorithm.");
714159361Spjd			return;
715159361Spjd		}
716148456Spjd	}
717153190Spjd	val = gctl_get_intmax(req, "keylen");
718153190Spjd	md.md_keylen = val;
719159308Spjd	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
720148456Spjd	if (md.md_keylen == 0) {
721148456Spjd		gctl_error(req, "Invalid key length.");
722148456Spjd		return;
723148456Spjd	}
724148456Spjd	md.md_provsize = mediasize;
725148456Spjd
726153190Spjd	val = gctl_get_intmax(req, "iterations");
727155536Spjd	if (val != -1) {
728155536Spjd		int nonewpassphrase;
729155536Spjd
730155536Spjd		/*
731155536Spjd		 * Don't allow to set iterations when there will be no
732155536Spjd		 * passphrase.
733155536Spjd		 */
734155536Spjd		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
735155536Spjd		if (nonewpassphrase) {
736155536Spjd			gctl_error(req,
737155536Spjd			    "Options -i and -P are mutually exclusive.");
738155536Spjd			return;
739155536Spjd		}
740155536Spjd	}
741153190Spjd	md.md_iterations = val;
742148456Spjd
743153190Spjd	val = gctl_get_intmax(req, "sectorsize");
744153190Spjd	if (val == 0)
745148456Spjd		md.md_sectorsize = secsize;
746148456Spjd	else {
747153190Spjd		if (val < 0 || (val % secsize) != 0) {
748148456Spjd			gctl_error(req, "Invalid sector size.");
749148456Spjd			return;
750148456Spjd		}
751167229Spjd		if (val > sysconf(_SC_PAGE_SIZE)) {
752214404Spjd			fprintf(stderr,
753214404Spjd			    "warning: Using sectorsize bigger than the page size!\n");
754167229Spjd		}
755153190Spjd		md.md_sectorsize = val;
756148456Spjd	}
757148456Spjd
758148456Spjd	md.md_keys = 0x01;
759148456Spjd	arc4rand(md.md_salt, sizeof(md.md_salt));
760148456Spjd	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
761148456Spjd
762148456Spjd	/* Generate user key. */
763213172Spjd	if (eli_genkey(req, &md, key, true) == NULL) {
764148456Spjd		bzero(key, sizeof(key));
765148456Spjd		bzero(&md, sizeof(md));
766148456Spjd		return;
767148456Spjd	}
768148456Spjd
769148456Spjd	/* Encrypt the first and the only Master Key. */
770159308Spjd	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
771148456Spjd	bzero(key, sizeof(key));
772148456Spjd	if (error != 0) {
773148456Spjd		bzero(&md, sizeof(md));
774148456Spjd		gctl_error(req, "Cannot encrypt Master Key: %s.",
775148456Spjd		    strerror(error));
776148456Spjd		return;
777148456Spjd	}
778148456Spjd
779148456Spjd	eli_metadata_encode(&md, sector);
780148456Spjd	bzero(&md, sizeof(md));
781148456Spjd	error = g_metadata_store(prov, sector, sizeof(sector));
782148456Spjd	bzero(sector, sizeof(sector));
783148456Spjd	if (error != 0) {
784148456Spjd		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
785148456Spjd		    strerror(error));
786148456Spjd		return;
787148456Spjd	}
788148456Spjd	if (verbose)
789148456Spjd		printf("Metadata value stored on %s.\n", prov);
790182452Spjd	/* Backup metadata to a file. */
791182452Spjd	str = gctl_get_ascii(req, "backupfile");
792182452Spjd	if (str[0] != '\0') {
793182452Spjd		/* Backupfile given be the user, just copy it. */
794182452Spjd		strlcpy(backfile, str, sizeof(backfile));
795182452Spjd	} else {
796182452Spjd		/* Generate file name automatically. */
797182452Spjd		const char *p = prov;
798182452Spjd		unsigned int i;
799182452Spjd
800213662Sae		if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
801213662Sae			p += sizeof(_PATH_DEV) - 1;
802182452Spjd		snprintf(backfile, sizeof(backfile), "%s%s.eli",
803182452Spjd		    GELI_BACKUP_DIR, p);
804182452Spjd		/* Replace all / with _. */
805182452Spjd		for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
806182452Spjd			if (backfile[i] == '/')
807182452Spjd				backfile[i] = '_';
808182452Spjd		}
809182452Spjd	}
810182452Spjd	if (strcmp(backfile, "none") != 0 &&
811182452Spjd	    eli_backup_create(req, prov, backfile) == 0) {
812182452Spjd		printf("\nMetadata backup can be found in %s and\n", backfile);
813182452Spjd		printf("can be restored with the following command:\n");
814182452Spjd		printf("\n\t# geli restore %s %s\n\n", backfile, prov);
815182452Spjd	}
816148456Spjd}
817148456Spjd
818148456Spjdstatic void
819148456Spjdeli_attach(struct gctl_req *req)
820148456Spjd{
821148456Spjd	struct g_eli_metadata md;
822148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
823148456Spjd	const char *prov;
824212934Sbrian	off_t mediasize;
825153190Spjd	int nargs;
826148456Spjd
827153190Spjd	nargs = gctl_get_int(req, "nargs");
828153190Spjd	if (nargs != 1) {
829158214Spjd		gctl_error(req, "Invalid number of arguments.");
830148456Spjd		return;
831148456Spjd	}
832153190Spjd	prov = gctl_get_ascii(req, "arg0");
833148456Spjd
834148456Spjd	if (eli_metadata_read(req, prov, &md) == -1)
835148456Spjd		return;
836148456Spjd
837212934Sbrian	mediasize = g_get_mediasize(prov);
838212934Sbrian	if (md.md_provsize != (uint64_t)mediasize) {
839212934Sbrian		gctl_error(req, "Provider size mismatch.");
840212934Sbrian		return;
841212934Sbrian	}
842212934Sbrian
843213172Spjd	if (eli_genkey(req, &md, key, false) == NULL) {
844148456Spjd		bzero(key, sizeof(key));
845148456Spjd		return;
846148456Spjd	}
847148456Spjd
848148456Spjd	gctl_ro_param(req, "key", sizeof(key), key);
849148456Spjd	if (gctl_issue(req) == NULL) {
850148456Spjd		if (verbose)
851166892Spjd			printf("Attached to %s.\n", prov);
852148456Spjd	}
853148456Spjd	bzero(key, sizeof(key));
854148456Spjd}
855148456Spjd
856148456Spjdstatic void
857213172Spjdeli_configure_detached(struct gctl_req *req, const char *prov, bool boot)
858162353Spjd{
859162353Spjd	struct g_eli_metadata md;
860162353Spjd
861162353Spjd	if (eli_metadata_read(req, prov, &md) == -1)
862162353Spjd		return;
863162353Spjd
864162353Spjd	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
865162353Spjd		if (verbose)
866162353Spjd			printf("BOOT flag already configured for %s.\n", prov);
867162353Spjd	} else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) {
868162353Spjd		if (verbose)
869162353Spjd			printf("BOOT flag not configured for %s.\n", prov);
870162353Spjd	} else {
871162353Spjd		if (boot)
872162353Spjd			md.md_flags |= G_ELI_FLAG_BOOT;
873162353Spjd		else
874162353Spjd			md.md_flags &= ~G_ELI_FLAG_BOOT;
875162353Spjd		eli_metadata_store(req, prov, &md);
876162353Spjd	}
877162353Spjd	bzero(&md, sizeof(md));
878162353Spjd}
879162353Spjd
880162353Spjdstatic void
881162353Spjdeli_configure(struct gctl_req *req)
882162353Spjd{
883162353Spjd	const char *prov;
884213172Spjd	bool boot, noboot;
885213172Spjd	int i, nargs;
886162353Spjd
887162353Spjd	nargs = gctl_get_int(req, "nargs");
888162353Spjd	if (nargs == 0) {
889162353Spjd		gctl_error(req, "Too few arguments.");
890162353Spjd		return;
891162353Spjd	}
892162353Spjd
893162353Spjd	boot = gctl_get_int(req, "boot");
894162353Spjd	noboot = gctl_get_int(req, "noboot");
895162353Spjd
896162353Spjd	if (boot && noboot) {
897162353Spjd		gctl_error(req, "Options -b and -B are mutually exclusive.");
898162353Spjd		return;
899162353Spjd	}
900162353Spjd	if (!boot && !noboot) {
901162353Spjd		gctl_error(req, "No option given.");
902162353Spjd		return;
903162353Spjd	}
904162353Spjd
905162353Spjd	/* First attached providers. */
906162353Spjd	gctl_issue(req);
907162353Spjd	/* Now the rest. */
908162353Spjd	for (i = 0; i < nargs; i++) {
909162353Spjd		prov = gctl_get_ascii(req, "arg%d", i);
910162353Spjd		if (!eli_is_attached(prov))
911162353Spjd			eli_configure_detached(req, prov, boot);
912162353Spjd	}
913162353Spjd}
914162353Spjd
915162353Spjdstatic void
916155101Spjdeli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
917148456Spjd{
918148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
919166216Spjd	intmax_t val, old = 0;
920166216Spjd	int error;
921148456Spjd
922153190Spjd	val = gctl_get_intmax(req, "iterations");
923149304Spjd	/* Check if iterations number should be changed. */
924153190Spjd	if (val != -1)
925153190Spjd		md->md_iterations = val;
926166216Spjd	else
927166216Spjd		old = md->md_iterations;
928148456Spjd
929148456Spjd	/* Generate key for Master Key encryption. */
930213172Spjd	if (eli_genkey(req, md, key, true) == NULL) {
931148456Spjd		bzero(key, sizeof(key));
932148456Spjd		return;
933148456Spjd	}
934166216Spjd	/*
935166216Spjd	 * If number of iterations has changed, but wasn't given as a
936166216Spjd	 * command-line argument, update the request.
937166216Spjd	 */
938166216Spjd	if (val == -1 && md->md_iterations != old) {
939166216Spjd		error = gctl_change_param(req, "iterations", sizeof(intmax_t),
940166216Spjd		    &md->md_iterations);
941166216Spjd		assert(error == 0);
942166216Spjd	}
943148456Spjd
944148456Spjd	gctl_ro_param(req, "key", sizeof(key), key);
945148456Spjd	gctl_issue(req);
946148456Spjd	bzero(key, sizeof(key));
947148456Spjd}
948148456Spjd
949148456Spjdstatic void
950149304Spjdeli_setkey_detached(struct gctl_req *req, const char *prov,
951149304Spjd struct g_eli_metadata *md)
952148456Spjd{
953148456Spjd	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
954148456Spjd	unsigned char *mkeydst;
955213172Spjd	unsigned int nkey;
956153190Spjd	intmax_t val;
957148456Spjd	int error;
958148456Spjd
959149928Spjd	if (md->md_keys == 0) {
960149928Spjd		gctl_error(req, "No valid keys on %s.", prov);
961149928Spjd		return;
962149928Spjd	}
963149928Spjd
964148456Spjd	/* Generate key for Master Key decryption. */
965213172Spjd	if (eli_genkey(req, md, key, false) == NULL) {
966148456Spjd		bzero(key, sizeof(key));
967148456Spjd		return;
968148456Spjd	}
969148456Spjd
970148456Spjd	/* Decrypt Master Key. */
971149304Spjd	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
972148456Spjd	bzero(key, sizeof(key));
973148456Spjd	if (error != 0) {
974149304Spjd		bzero(md, sizeof(*md));
975148456Spjd		if (error == -1)
976148456Spjd			gctl_error(req, "Wrong key for %s.", prov);
977148456Spjd		else /* if (error > 0) */ {
978148456Spjd			gctl_error(req, "Cannot decrypt Master Key: %s.",
979148456Spjd			    strerror(error));
980148456Spjd		}
981148456Spjd		return;
982148456Spjd	}
983148456Spjd	if (verbose)
984148456Spjd		printf("Decrypted Master Key %u.\n", nkey);
985148456Spjd
986153190Spjd	val = gctl_get_intmax(req, "keyno");
987153190Spjd	if (val != -1)
988153190Spjd		nkey = val;
989148456Spjd#if 0
990148456Spjd	else
991148456Spjd		; /* Use the key number which was found during decryption. */
992148456Spjd#endif
993148456Spjd	if (nkey >= G_ELI_MAXMKEYS) {
994148456Spjd		gctl_error(req, "Invalid '%s' argument.", "keyno");
995148456Spjd		return;
996148456Spjd	}
997148456Spjd
998153190Spjd	val = gctl_get_intmax(req, "iterations");
999149304Spjd	/* Check if iterations number should and can be changed. */
1000153190Spjd	if (val != -1) {
1001149304Spjd		if (bitcount32(md->md_keys) != 1) {
1002149304Spjd			gctl_error(req, "To be able to use '-i' option, only "
1003149304Spjd			    "one key can be defined.");
1004149304Spjd			return;
1005149304Spjd		}
1006149304Spjd		if (md->md_keys != (1 << nkey)) {
1007149304Spjd			gctl_error(req, "Only already defined key can be "
1008149304Spjd			    "changed when '-i' option is used.");
1009149304Spjd			return;
1010149304Spjd		}
1011153190Spjd		md->md_iterations = val;
1012149304Spjd	}
1013148456Spjd
1014149304Spjd	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
1015149304Spjd	md->md_keys |= (1 << nkey);
1016149304Spjd
1017148456Spjd	bcopy(mkey, mkeydst, sizeof(mkey));
1018148456Spjd	bzero(mkey, sizeof(mkey));
1019148456Spjd
1020148456Spjd	/* Generate key for Master Key encryption. */
1021213172Spjd	if (eli_genkey(req, md, key, true) == NULL) {
1022148456Spjd		bzero(key, sizeof(key));
1023149304Spjd		bzero(md, sizeof(*md));
1024148456Spjd		return;
1025148456Spjd	}
1026148456Spjd
1027148456Spjd	/* Encrypt the Master-Key with the new key. */
1028159308Spjd	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
1029148456Spjd	bzero(key, sizeof(key));
1030148456Spjd	if (error != 0) {
1031149304Spjd		bzero(md, sizeof(*md));
1032148456Spjd		gctl_error(req, "Cannot encrypt Master Key: %s.",
1033148456Spjd		    strerror(error));
1034148456Spjd		return;
1035148456Spjd	}
1036148456Spjd
1037148456Spjd	/* Store metadata with fresh key. */
1038149304Spjd	eli_metadata_store(req, prov, md);
1039149304Spjd	bzero(md, sizeof(*md));
1040148456Spjd}
1041148456Spjd
1042148456Spjdstatic void
1043148456Spjdeli_setkey(struct gctl_req *req)
1044148456Spjd{
1045149304Spjd	struct g_eli_metadata md;
1046148456Spjd	const char *prov;
1047153190Spjd	int nargs;
1048148456Spjd
1049153190Spjd	nargs = gctl_get_int(req, "nargs");
1050153190Spjd	if (nargs != 1) {
1051158214Spjd		gctl_error(req, "Invalid number of arguments.");
1052148456Spjd		return;
1053148456Spjd	}
1054153190Spjd	prov = gctl_get_ascii(req, "arg0");
1055148456Spjd
1056149304Spjd	if (eli_metadata_read(req, prov, &md) == -1)
1057149304Spjd		return;
1058149304Spjd
1059148456Spjd	if (eli_is_attached(prov))
1060155101Spjd		eli_setkey_attached(req, &md);
1061148456Spjd	else
1062149304Spjd		eli_setkey_detached(req, prov, &md);
1063182452Spjd
1064182452Spjd	if (req->error == NULL || req->error[0] == '\0') {
1065182452Spjd		printf("Note, that the master key encrypted with old keys "
1066182452Spjd		    "and/or passphrase may still exists in a metadata backup "
1067182452Spjd		    "file.\n");
1068182452Spjd	}
1069148456Spjd}
1070148456Spjd
1071148456Spjdstatic void
1072148456Spjdeli_delkey_attached(struct gctl_req *req, const char *prov __unused)
1073148456Spjd{
1074148456Spjd
1075148456Spjd	gctl_issue(req);
1076148456Spjd}
1077148456Spjd
1078148456Spjdstatic void
1079148456Spjdeli_delkey_detached(struct gctl_req *req, const char *prov)
1080148456Spjd{
1081148456Spjd	struct g_eli_metadata md;
1082148456Spjd	unsigned char *mkeydst;
1083213172Spjd	unsigned int nkey;
1084153190Spjd	intmax_t val;
1085213172Spjd	bool all, force;
1086148456Spjd
1087148456Spjd	if (eli_metadata_read(req, prov, &md) == -1)
1088148456Spjd		return;
1089148456Spjd
1090153190Spjd	all = gctl_get_int(req, "all");
1091153190Spjd	if (all)
1092148456Spjd		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
1093148456Spjd	else {
1094153190Spjd		force = gctl_get_int(req, "force");
1095153190Spjd		val = gctl_get_intmax(req, "keyno");
1096153190Spjd		if (val == -1) {
1097148456Spjd			gctl_error(req, "Key number has to be specified.");
1098148456Spjd			return;
1099148456Spjd		}
1100153190Spjd		nkey = val;
1101148456Spjd		if (nkey >= G_ELI_MAXMKEYS) {
1102148456Spjd			gctl_error(req, "Invalid '%s' argument.", "keyno");
1103148456Spjd			return;
1104148456Spjd		}
1105153190Spjd		if (!(md.md_keys & (1 << nkey)) && !force) {
1106148456Spjd			gctl_error(req, "Master Key %u is not set.", nkey);
1107148456Spjd			return;
1108148456Spjd		}
1109148456Spjd		md.md_keys &= ~(1 << nkey);
1110153190Spjd		if (md.md_keys == 0 && !force) {
1111148456Spjd			gctl_error(req, "This is the last Master Key. Use '-f' "
1112148456Spjd			    "option if you really want to remove it.");
1113148456Spjd			return;
1114148456Spjd		}
1115148456Spjd		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
1116148456Spjd		arc4rand(mkeydst, G_ELI_MKEYLEN);
1117148456Spjd	}
1118148456Spjd
1119148456Spjd	eli_metadata_store(req, prov, &md);
1120148456Spjd	bzero(&md, sizeof(md));
1121148456Spjd}
1122148456Spjd
1123148456Spjdstatic void
1124148456Spjdeli_delkey(struct gctl_req *req)
1125148456Spjd{
1126148456Spjd	const char *prov;
1127153190Spjd	int nargs;
1128148456Spjd
1129153190Spjd	nargs = gctl_get_int(req, "nargs");
1130153190Spjd	if (nargs != 1) {
1131158214Spjd		gctl_error(req, "Invalid number of arguments.");
1132148456Spjd		return;
1133148456Spjd	}
1134153190Spjd	prov = gctl_get_ascii(req, "arg0");
1135148456Spjd
1136148456Spjd	if (eli_is_attached(prov))
1137148456Spjd		eli_delkey_attached(req, prov);
1138148456Spjd	else
1139148456Spjd		eli_delkey_detached(req, prov);
1140148456Spjd}
1141148456Spjd
1142214118Spjdstatic void
1143214118Spjdeli_resume(struct gctl_req *req)
1144214118Spjd{
1145214118Spjd	struct g_eli_metadata md;
1146214118Spjd	unsigned char key[G_ELI_USERKEYLEN];
1147214118Spjd	const char *prov;
1148214118Spjd	off_t mediasize;
1149214118Spjd	int nargs;
1150214118Spjd
1151214118Spjd	nargs = gctl_get_int(req, "nargs");
1152214118Spjd	if (nargs != 1) {
1153214118Spjd		gctl_error(req, "Invalid number of arguments.");
1154214118Spjd		return;
1155214118Spjd	}
1156214118Spjd	prov = gctl_get_ascii(req, "arg0");
1157214118Spjd
1158214118Spjd	if (eli_metadata_read(req, prov, &md) == -1)
1159214118Spjd		return;
1160214118Spjd
1161214118Spjd	mediasize = g_get_mediasize(prov);
1162214118Spjd	if (md.md_provsize != (uint64_t)mediasize) {
1163214118Spjd		gctl_error(req, "Provider size mismatch.");
1164214118Spjd		return;
1165214118Spjd	}
1166214118Spjd
1167214118Spjd	if (eli_genkey(req, &md, key, false) == NULL) {
1168214118Spjd		bzero(key, sizeof(key));
1169214118Spjd		return;
1170214118Spjd	}
1171214118Spjd
1172214118Spjd	gctl_ro_param(req, "key", sizeof(key), key);
1173214118Spjd	if (gctl_issue(req) == NULL) {
1174214118Spjd		if (verbose)
1175214118Spjd			printf("Resumed %s.\n", prov);
1176214118Spjd	}
1177214118Spjd	bzero(key, sizeof(key));
1178214118Spjd}
1179214118Spjd
1180213060Spjdstatic int
1181213060Spjdeli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset)
1182213060Spjd{
1183213060Spjd	unsigned int overwrites;
1184213060Spjd	unsigned char *sector;
1185213060Spjd	ssize_t size;
1186213060Spjd	int error;
1187213060Spjd
1188213060Spjd	size = sizeof(overwrites);
1189213060Spjd	if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size,
1190213060Spjd	    NULL, 0) == -1 || overwrites == 0) {
1191213060Spjd		overwrites = G_ELI_OVERWRITES;
1192213060Spjd	}
1193213060Spjd
1194213060Spjd	size = g_sectorsize(fd);
1195213060Spjd	if (size <= 0) {
1196213060Spjd		gctl_error(req, "Cannot obtain provider sector size %s: %s.",
1197213060Spjd		    prov, strerror(errno));
1198213060Spjd		return (-1);
1199213060Spjd	}
1200213060Spjd	sector = malloc(size);
1201213060Spjd	if (sector == NULL) {
1202213060Spjd		gctl_error(req, "Cannot allocate %zd bytes of memory.", size);
1203213060Spjd		return (-1);
1204213060Spjd	}
1205213060Spjd
1206213060Spjd	error = 0;
1207213060Spjd	do {
1208213060Spjd		arc4rand(sector, size);
1209213060Spjd		if (pwrite(fd, sector, size, offset) != size) {
1210213060Spjd			if (error == 0)
1211213060Spjd				error = errno;
1212213060Spjd		}
1213213060Spjd		(void)g_flush(fd);
1214213060Spjd	} while (--overwrites > 0);
1215213060Spjd	if (error != 0) {
1216213060Spjd		gctl_error(req, "Cannot trash metadata on provider %s: %s.",
1217213060Spjd		    prov, strerror(error));
1218213060Spjd		return (-1);
1219213060Spjd	}
1220213060Spjd	return (0);
1221213060Spjd}
1222213060Spjd
1223148456Spjdstatic void
1224148456Spjdeli_kill_detached(struct gctl_req *req, const char *prov)
1225148456Spjd{
1226213060Spjd	off_t offset;
1227213060Spjd	int fd;
1228148456Spjd
1229148456Spjd	/*
1230148456Spjd	 * NOTE: Maybe we should verify if this is geli provider first,
1231148456Spjd	 *       but 'kill' command is quite critical so better don't waste
1232148456Spjd	 *       the time.
1233148456Spjd	 */
1234148456Spjd#if 0
1235148456Spjd	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
1236148456Spjd	    G_ELI_MAGIC);
1237148456Spjd	if (error != 0) {
1238148456Spjd		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
1239148456Spjd		    strerror(error));
1240148456Spjd		return;
1241148456Spjd	}
1242148456Spjd#endif
1243148456Spjd
1244213060Spjd	fd = g_open(prov, 1);
1245213060Spjd	if (fd == -1) {
1246213060Spjd		gctl_error(req, "Cannot open provider %s: %s.", prov,
1247213060Spjd		    strerror(errno));
1248213060Spjd		return;
1249148456Spjd	}
1250213060Spjd	offset = g_mediasize(fd) - g_sectorsize(fd);
1251213060Spjd	if (offset <= 0) {
1252213060Spjd		gctl_error(req,
1253213060Spjd		    "Cannot obtain media size or sector size for provider %s: %s.",
1254213060Spjd		    prov, strerror(errno));
1255213060Spjd		(void)g_close(fd);
1256213060Spjd		return;
1257213060Spjd	}
1258213060Spjd	(void)eli_trash_metadata(req, prov, fd, offset);
1259213060Spjd	(void)g_close(fd);
1260148456Spjd}
1261148456Spjd
1262148456Spjdstatic void
1263148456Spjdeli_kill(struct gctl_req *req)
1264148456Spjd{
1265148456Spjd	const char *prov;
1266153190Spjd	int i, nargs, all;
1267148456Spjd
1268153190Spjd	nargs = gctl_get_int(req, "nargs");
1269153190Spjd	all = gctl_get_int(req, "all");
1270153190Spjd	if (!all && nargs == 0) {
1271148456Spjd		gctl_error(req, "Too few arguments.");
1272148456Spjd		return;
1273148456Spjd	}
1274148456Spjd	/*
1275148456Spjd	 * How '-a' option combine with a list of providers:
1276148456Spjd	 * Delete Master Keys from all attached providers:
1277148456Spjd	 * geli kill -a
1278169312Spjd	 * Delete Master Keys from all attached providers and from
1279148456Spjd	 * detached da0 and da1:
1280148456Spjd	 * geli kill -a da0 da1
1281148456Spjd	 * Delete Master Keys from (attached or detached) da0 and da1:
1282148456Spjd	 * geli kill da0 da1
1283148456Spjd	 */
1284148456Spjd
1285169312Spjd	/* First detached providers. */
1286153190Spjd	for (i = 0; i < nargs; i++) {
1287153190Spjd		prov = gctl_get_ascii(req, "arg%d", i);
1288148456Spjd		if (!eli_is_attached(prov))
1289148456Spjd			eli_kill_detached(req, prov);
1290148456Spjd	}
1291162347Spjd	/* Now attached providers. */
1292162347Spjd	gctl_issue(req);
1293148456Spjd}
1294148456Spjd
1295182452Spjdstatic int
1296182452Spjdeli_backup_create(struct gctl_req *req, const char *prov, const char *file)
1297148456Spjd{
1298148456Spjd	unsigned char *sector;
1299213059Spjd	ssize_t secsize;
1300226716Spjd	int error, filefd, ret;
1301148456Spjd
1302182452Spjd	ret = -1;
1303226716Spjd	filefd = -1;
1304148456Spjd	sector = NULL;
1305148456Spjd	secsize = 0;
1306148456Spjd
1307226716Spjd	secsize = g_get_sectorsize(prov);
1308226716Spjd	if (secsize == 0) {
1309148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1310148456Spjd		    strerror(errno));
1311169193Spjd		goto out;
1312148456Spjd	}
1313148456Spjd	sector = malloc(secsize);
1314148456Spjd	if (sector == NULL) {
1315148456Spjd		gctl_error(req, "Cannot allocate memory.");
1316169193Spjd		goto out;
1317148456Spjd	}
1318148456Spjd	/* Read metadata from the provider. */
1319226716Spjd	error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC);
1320226716Spjd	if (error != 0) {
1321226716Spjd		gctl_error(req, "Unable to read metadata from %s: %s.", prov,
1322226716Spjd		    strerror(error));
1323148456Spjd		goto out;
1324148456Spjd	}
1325226716Spjd
1326226716Spjd	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1327226716Spjd	if (filefd == -1) {
1328226716Spjd		gctl_error(req, "Unable to open %s: %s.", file,
1329226716Spjd		    strerror(errno));
1330148456Spjd		goto out;
1331148456Spjd	}
1332148456Spjd	/* Write metadata to the destination file. */
1333213059Spjd	if (write(filefd, sector, secsize) != secsize) {
1334226716Spjd		gctl_error(req, "Unable to write to %s: %s.", file,
1335148456Spjd		    strerror(errno));
1336226716Spjd		(void)close(filefd);
1337226716Spjd		(void)unlink(file);
1338148456Spjd		goto out;
1339148456Spjd	}
1340213059Spjd	(void)fsync(filefd);
1341226716Spjd	(void)close(filefd);
1342182452Spjd	/* Success. */
1343182452Spjd	ret = 0;
1344148456Spjdout:
1345148456Spjd	if (sector != NULL) {
1346148456Spjd		bzero(sector, secsize);
1347148456Spjd		free(sector);
1348148456Spjd	}
1349182452Spjd	return (ret);
1350148456Spjd}
1351148456Spjd
1352148456Spjdstatic void
1353182452Spjdeli_backup(struct gctl_req *req)
1354182452Spjd{
1355182452Spjd	const char *file, *prov;
1356182452Spjd	int nargs;
1357182452Spjd
1358182452Spjd	nargs = gctl_get_int(req, "nargs");
1359182452Spjd	if (nargs != 2) {
1360182452Spjd		gctl_error(req, "Invalid number of arguments.");
1361182452Spjd		return;
1362182452Spjd	}
1363182452Spjd	prov = gctl_get_ascii(req, "arg0");
1364182452Spjd	file = gctl_get_ascii(req, "arg1");
1365182452Spjd
1366182452Spjd	eli_backup_create(req, prov, file);
1367182452Spjd}
1368182452Spjd
1369182452Spjdstatic void
1370148456Spjdeli_restore(struct gctl_req *req)
1371148456Spjd{
1372148456Spjd	struct g_eli_metadata md;
1373148456Spjd	const char *file, *prov;
1374148456Spjd	off_t mediasize;
1375226716Spjd	int nargs;
1376148456Spjd
1377153190Spjd	nargs = gctl_get_int(req, "nargs");
1378153190Spjd	if (nargs != 2) {
1379148456Spjd		gctl_error(req, "Invalid number of arguments.");
1380148456Spjd		return;
1381148456Spjd	}
1382153190Spjd	file = gctl_get_ascii(req, "arg0");
1383153190Spjd	prov = gctl_get_ascii(req, "arg1");
1384148456Spjd
1385226716Spjd	/* Read metadata from the backup file. */
1386226716Spjd	if (eli_metadata_read(req, file, &md) == -1)
1387226716Spjd		return;
1388226716Spjd	/* Obtain provider's mediasize. */
1389226716Spjd	mediasize = g_get_mediasize(prov);
1390226716Spjd	if (mediasize == 0) {
1391148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1392148456Spjd		    strerror(errno));
1393226716Spjd		return;
1394148456Spjd	}
1395212934Sbrian	/* Check if the provider size has changed since we did the backup. */
1396212934Sbrian	if (md.md_provsize != (uint64_t)mediasize) {
1397212934Sbrian		if (gctl_get_int(req, "force")) {
1398212934Sbrian			md.md_provsize = mediasize;
1399212934Sbrian		} else {
1400212934Sbrian			gctl_error(req, "Provider size mismatch: "
1401212934Sbrian			    "wrong backup file?");
1402226716Spjd			return;
1403212934Sbrian		}
1404212934Sbrian	}
1405226716Spjd	/* Write metadata to the provider. */
1406226716Spjd	(void)eli_metadata_store(req, prov, &md);
1407148456Spjd}
1408148456Spjd
1409148456Spjdstatic void
1410212934Sbrianeli_resize(struct gctl_req *req)
1411212934Sbrian{
1412212934Sbrian	struct g_eli_metadata md;
1413212934Sbrian	const char *prov;
1414212934Sbrian	unsigned char *sector;
1415213056Spjd	ssize_t secsize;
1416212934Sbrian	off_t mediasize, oldsize;
1417212934Sbrian	int nargs, provfd;
1418212934Sbrian
1419212934Sbrian	nargs = gctl_get_int(req, "nargs");
1420212934Sbrian	if (nargs != 1) {
1421212934Sbrian		gctl_error(req, "Invalid number of arguments.");
1422212934Sbrian		return;
1423212934Sbrian	}
1424212934Sbrian	prov = gctl_get_ascii(req, "arg0");
1425212934Sbrian
1426212934Sbrian	provfd = -1;
1427212934Sbrian	sector = NULL;
1428212934Sbrian	secsize = 0;
1429212934Sbrian
1430213056Spjd	provfd = g_open(prov, 1);
1431212934Sbrian	if (provfd == -1) {
1432212934Sbrian		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1433212934Sbrian		goto out;
1434212934Sbrian	}
1435212934Sbrian
1436213056Spjd	mediasize = g_mediasize(provfd);
1437213056Spjd	secsize = g_sectorsize(provfd);
1438213056Spjd	if (mediasize == -1 || secsize == -1) {
1439212934Sbrian		gctl_error(req, "Cannot get information about %s: %s.", prov,
1440212934Sbrian		    strerror(errno));
1441212934Sbrian		goto out;
1442212934Sbrian	}
1443212934Sbrian
1444212934Sbrian	sector = malloc(secsize);
1445212934Sbrian	if (sector == NULL) {
1446212934Sbrian		gctl_error(req, "Cannot allocate memory.");
1447212934Sbrian		goto out;
1448212934Sbrian	}
1449212934Sbrian
1450212934Sbrian	oldsize = gctl_get_intmax(req, "oldsize");
1451212934Sbrian	if (oldsize < 0 || oldsize > mediasize) {
1452212934Sbrian		gctl_error(req, "Invalid oldsize: Out of range.");
1453212934Sbrian		goto out;
1454212934Sbrian	}
1455213058Spjd	if (oldsize == mediasize) {
1456213058Spjd		gctl_error(req, "Size hasn't changed.");
1457213058Spjd		goto out;
1458213058Spjd	}
1459212934Sbrian
1460212934Sbrian	/* Read metadata from the 'oldsize' offset. */
1461213056Spjd	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
1462212934Sbrian		gctl_error(req, "Cannot read old metadata: %s.",
1463212934Sbrian		    strerror(errno));
1464212934Sbrian		goto out;
1465212934Sbrian	}
1466212934Sbrian
1467212934Sbrian	/* Check if this sector contains geli metadata. */
1468212934Sbrian	if (eli_metadata_decode(sector, &md) != 0) {
1469212934Sbrian		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
1470212934Sbrian		goto out;
1471212934Sbrian	}
1472212934Sbrian
1473212934Sbrian	/*
1474212934Sbrian	 * If the old metadata doesn't have a correct provider size, refuse
1475212934Sbrian	 * to resize.
1476212934Sbrian	 */
1477212934Sbrian	if (md.md_provsize != (uint64_t)oldsize) {
1478212934Sbrian		gctl_error(req, "Provider size mismatch at oldsize.");
1479212934Sbrian		goto out;
1480212934Sbrian	}
1481212934Sbrian
1482212934Sbrian	/*
1483212934Sbrian	 * Update the old metadata with the current provider size and write
1484212934Sbrian	 * it back to the correct place on the provider.
1485212934Sbrian	 */
1486212934Sbrian	md.md_provsize = mediasize;
1487212934Sbrian	eli_metadata_encode(&md, sector);
1488213056Spjd	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
1489212934Sbrian		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1490212934Sbrian		goto out;
1491212934Sbrian	}
1492213057Spjd	(void)g_flush(provfd);
1493212934Sbrian
1494212934Sbrian	/* Now trash the old metadata. */
1495213060Spjd	if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
1496212934Sbrian		goto out;
1497212934Sbrianout:
1498213056Spjd	if (provfd >= 0)
1499213056Spjd		(void)g_close(provfd);
1500212934Sbrian	if (sector != NULL) {
1501212934Sbrian		bzero(sector, secsize);
1502212934Sbrian		free(sector);
1503212934Sbrian	}
1504212934Sbrian}
1505212934Sbrian
1506212934Sbrianstatic void
1507148456Spjdeli_clear(struct gctl_req *req)
1508148456Spjd{
1509148456Spjd	const char *name;
1510153190Spjd	int error, i, nargs;
1511148456Spjd
1512153190Spjd	nargs = gctl_get_int(req, "nargs");
1513153190Spjd	if (nargs < 1) {
1514148456Spjd		gctl_error(req, "Too few arguments.");
1515148456Spjd		return;
1516148456Spjd	}
1517148456Spjd
1518153190Spjd	for (i = 0; i < nargs; i++) {
1519153190Spjd		name = gctl_get_ascii(req, "arg%d", i);
1520148456Spjd		error = g_metadata_clear(name, G_ELI_MAGIC);
1521148456Spjd		if (error != 0) {
1522148456Spjd			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1523148456Spjd			    name, strerror(error));
1524148456Spjd			gctl_error(req, "Not fully done.");
1525148456Spjd			continue;
1526148456Spjd		}
1527148456Spjd		if (verbose)
1528155175Spjd			printf("Metadata cleared on %s.\n", name);
1529148456Spjd	}
1530148456Spjd}
1531148456Spjd
1532148456Spjdstatic void
1533148456Spjdeli_dump(struct gctl_req *req)
1534148456Spjd{
1535148456Spjd	struct g_eli_metadata md, tmpmd;
1536148456Spjd	const char *name;
1537153190Spjd	int error, i, nargs;
1538148456Spjd
1539153190Spjd	nargs = gctl_get_int(req, "nargs");
1540153190Spjd	if (nargs < 1) {
1541148456Spjd		gctl_error(req, "Too few arguments.");
1542148456Spjd		return;
1543148456Spjd	}
1544148456Spjd
1545153190Spjd	for (i = 0; i < nargs; i++) {
1546153190Spjd		name = gctl_get_ascii(req, "arg%d", i);
1547148456Spjd		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1548148456Spjd		    sizeof(tmpmd), G_ELI_MAGIC);
1549148456Spjd		if (error != 0) {
1550148456Spjd			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1551148456Spjd			    name, strerror(error));
1552148456Spjd			gctl_error(req, "Not fully done.");
1553148456Spjd			continue;
1554148456Spjd		}
1555148456Spjd		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1556148456Spjd			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1557148456Spjd			    name);
1558148456Spjd			gctl_error(req, "Not fully done.");
1559148456Spjd			continue;
1560148456Spjd		}
1561148456Spjd		printf("Metadata on %s:\n", name);
1562148456Spjd		eli_metadata_dump(&md);
1563148456Spjd		printf("\n");
1564148456Spjd	}
1565148456Spjd}
1566