geom_eli.c revision 226717
1/*-
2 * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 226717 2011-10-25 07:32:43Z pjd $");
29
30#include <sys/param.h>
31#include <sys/mman.h>
32#include <sys/sysctl.h>
33#include <sys/resource.h>
34#include <opencrypto/cryptodev.h>
35
36#include <assert.h>
37#include <err.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <libgeom.h>
41#include <paths.h>
42#include <readpassphrase.h>
43#include <stdbool.h>
44#include <stdint.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <strings.h>
49#include <unistd.h>
50
51#include <geom/eli/g_eli.h>
52#include <geom/eli/pkcs5v2.h>
53
54#include "core/geom.h"
55#include "misc/subr.h"
56
57
58uint32_t lib_version = G_LIB_VERSION;
59uint32_t version = G_ELI_VERSION;
60
61#define	GELI_BACKUP_DIR	"/var/backups/"
62#define	GELI_ENC_ALGO	"aes"
63
64static void eli_main(struct gctl_req *req, unsigned flags);
65static void eli_init(struct gctl_req *req);
66static void eli_attach(struct gctl_req *req);
67static void eli_configure(struct gctl_req *req);
68static void eli_setkey(struct gctl_req *req);
69static void eli_delkey(struct gctl_req *req);
70static void eli_resume(struct gctl_req *req);
71static void eli_kill(struct gctl_req *req);
72static void eli_backup(struct gctl_req *req);
73static void eli_restore(struct gctl_req *req);
74static void eli_resize(struct gctl_req *req);
75static void eli_clear(struct gctl_req *req);
76static void eli_dump(struct gctl_req *req);
77
78static int eli_backup_create(struct gctl_req *req, const char *prov,
79    const char *file);
80
81/*
82 * Available commands:
83 *
84 * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
85 * label - alias for 'init'
86 * attach [-dprv] [-j passfile] [-k keyfile] prov
87 * detach [-fl] prov ...
88 * stop - alias for 'detach'
89 * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov
90 * configure [-bB] prov ...
91 * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
92 * delkey [-afv] [-n keyno] prov
93 * suspend [-v] -a | prov ...
94 * resume [-pv] [-j passfile] [-k keyfile] prov
95 * kill [-av] [prov ...]
96 * backup [-v] prov file
97 * restore [-fv] file prov
98 * resize [-v] -s oldsize prov
99 * clear [-v] prov ...
100 * dump [-v] prov ...
101 */
102struct g_command class_commands[] = {
103	{ "init", G_FLAG_VERBOSE, eli_main,
104	    {
105		{ 'a', "aalgo", "", G_TYPE_STRING },
106		{ 'b', "boot", NULL, G_TYPE_BOOL },
107		{ 'B', "backupfile", "", G_TYPE_STRING },
108		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
109		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
110		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
111		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
112		{ 'l', "keylen", "0", G_TYPE_NUMBER },
113		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
114		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
115		G_OPT_SENTINEL
116	    },
117	    "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
118	},
119	{ "label", G_FLAG_VERBOSE, eli_main,
120	    {
121		{ 'a', "aalgo", "", G_TYPE_STRING },
122		{ 'b', "boot", NULL, G_TYPE_BOOL },
123		{ 'B', "backupfile", "", G_TYPE_STRING },
124		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
125		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
126		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
127		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
128		{ 'l', "keylen", "0", G_TYPE_NUMBER },
129		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
130		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
131		G_OPT_SENTINEL
132	    },
133	    "- an alias for 'init'"
134	},
135	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
136	    {
137		{ 'd', "detach", NULL, G_TYPE_BOOL },
138		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
139		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
140		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
141		{ 'r', "readonly", NULL, G_TYPE_BOOL },
142		G_OPT_SENTINEL
143	    },
144	    "[-dprv] [-j passfile] [-k keyfile] prov"
145	},
146	{ "detach", 0, NULL,
147	    {
148		{ 'f', "force", NULL, G_TYPE_BOOL },
149		{ 'l', "last", NULL, G_TYPE_BOOL },
150		G_OPT_SENTINEL
151	    },
152	    "[-fl] prov ..."
153	},
154	{ "stop", 0, NULL,
155	    {
156		{ 'f', "force", NULL, G_TYPE_BOOL },
157		{ 'l', "last", NULL, G_TYPE_BOOL },
158		G_OPT_SENTINEL
159	    },
160	    "- an alias for 'detach'"
161	},
162	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
163	    {
164		{ 'a', "aalgo", "", G_TYPE_STRING },
165		{ 'd', "detach", NULL, G_TYPE_BOOL },
166		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
167		{ 'l', "keylen", "0", G_TYPE_NUMBER },
168		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
169		G_OPT_SENTINEL
170	    },
171	    "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov"
172	},
173	{ "configure", G_FLAG_VERBOSE, eli_main,
174	    {
175		{ 'b', "boot", NULL, G_TYPE_BOOL },
176		{ 'B', "noboot", NULL, G_TYPE_BOOL },
177		G_OPT_SENTINEL
178	    },
179	    "[-bB] prov ..."
180	},
181	{ "setkey", G_FLAG_VERBOSE, eli_main,
182	    {
183		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
184		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
185		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
186		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
187		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
188		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
189		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
190		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
191		G_OPT_SENTINEL
192	    },
193	    "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
194	},
195	{ "delkey", G_FLAG_VERBOSE, eli_main,
196	    {
197		{ 'a', "all", NULL, G_TYPE_BOOL },
198		{ 'f', "force", NULL, G_TYPE_BOOL },
199		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
200		G_OPT_SENTINEL
201	    },
202	    "[-afv] [-n keyno] prov"
203	},
204	{ "suspend", G_FLAG_VERBOSE, NULL,
205	    {
206		{ 'a', "all", NULL, G_TYPE_BOOL },
207		G_OPT_SENTINEL
208	    },
209	    "[-v] -a | prov ..."
210	},
211	{ "resume", G_FLAG_VERBOSE, eli_main,
212	    {
213		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
214		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
215		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
216		G_OPT_SENTINEL
217	    },
218	    "[-pv] [-j passfile] [-k keyfile] prov"
219	},
220	{ "kill", G_FLAG_VERBOSE, eli_main,
221	    {
222		{ 'a', "all", NULL, G_TYPE_BOOL },
223		G_OPT_SENTINEL
224	    },
225	    "[-av] [prov ...]"
226	},
227	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
228	    "[-v] prov file"
229	},
230	{ "restore", G_FLAG_VERBOSE, eli_main,
231	    {
232		{ 'f', "force", NULL, G_TYPE_BOOL },
233		G_OPT_SENTINEL
234	    },
235	    "[-fv] file prov"
236	},
237	{ "resize", G_FLAG_VERBOSE, eli_main,
238	    {
239		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
240		G_OPT_SENTINEL
241	    },
242	    "[-v] -s oldsize prov"
243	},
244	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
245	    "[-v] prov ..."
246	},
247	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
248	    "[-v] prov ..."
249	},
250	G_CMD_SENTINEL
251};
252
253static int verbose = 0;
254
255static int
256eli_protect(struct gctl_req *req)
257{
258	struct rlimit rl;
259
260	/* Disable core dumps. */
261	rl.rlim_cur = 0;
262	rl.rlim_max = 0;
263	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
264		gctl_error(req, "Cannot disable core dumps: %s.",
265		    strerror(errno));
266		return (-1);
267	}
268	/* Disable swapping. */
269	if (mlockall(MCL_FUTURE) == -1) {
270		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
271		return (-1);
272	}
273	return (0);
274}
275
276static void
277eli_main(struct gctl_req *req, unsigned int flags)
278{
279	const char *name;
280
281	if (eli_protect(req) == -1)
282		return;
283
284	if ((flags & G_FLAG_VERBOSE) != 0)
285		verbose = 1;
286
287	name = gctl_get_ascii(req, "verb");
288	if (name == NULL) {
289		gctl_error(req, "No '%s' argument.", "verb");
290		return;
291	}
292	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
293		eli_init(req);
294	else if (strcmp(name, "attach") == 0)
295		eli_attach(req);
296	else if (strcmp(name, "configure") == 0)
297		eli_configure(req);
298	else if (strcmp(name, "setkey") == 0)
299		eli_setkey(req);
300	else if (strcmp(name, "delkey") == 0)
301		eli_delkey(req);
302	else if (strcmp(name, "resume") == 0)
303		eli_resume(req);
304	else if (strcmp(name, "kill") == 0)
305		eli_kill(req);
306	else if (strcmp(name, "backup") == 0)
307		eli_backup(req);
308	else if (strcmp(name, "restore") == 0)
309		eli_restore(req);
310	else if (strcmp(name, "resize") == 0)
311		eli_resize(req);
312	else if (strcmp(name, "dump") == 0)
313		eli_dump(req);
314	else if (strcmp(name, "clear") == 0)
315		eli_clear(req);
316	else
317		gctl_error(req, "Unknown command: %s.", name);
318}
319
320static void
321arc4rand(unsigned char *buf, size_t size)
322{
323	uint32_t *buf4;
324	size_t size4;
325	unsigned int i;
326
327	buf4 = (uint32_t *)buf;
328	size4 = size / 4;
329
330	for (i = 0; i < size4; i++)
331		buf4[i] = arc4random();
332	for (i *= 4; i < size; i++)
333		buf[i] = arc4random() % 0xff;
334}
335
336static bool
337eli_is_attached(const char *prov)
338{
339	char name[MAXPATHLEN];
340
341	/*
342	 * Not the best way to do it, but the easiest.
343	 * We try to open provider and check if it is a GEOM provider
344	 * by asking about its sectorsize.
345	 */
346	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
347	return (g_get_sectorsize(name) > 0);
348}
349
350static int
351eli_genkey_files(struct gctl_req *req, bool new, const char *type,
352    struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize)
353{
354	char *p, buf[MAXPHYS], argname[16];
355	const char *file;
356	int error, fd, i;
357	ssize_t done;
358
359	assert((strcmp(type, "keyfile") == 0 && ctxp != NULL &&
360	    passbuf == NULL && passbufsize == 0) ||
361	    (strcmp(type, "passfile") == 0 && ctxp == NULL &&
362	    passbuf != NULL && passbufsize > 0));
363	assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0');
364
365	for (i = 0; ; i++) {
366		snprintf(argname, sizeof(argname), "%s%s%d",
367		    new ? "new" : "", type, i);
368
369		/* No more {key,pass}files? */
370		if (!gctl_has_param(req, argname))
371			return (i);
372
373		file = gctl_get_ascii(req, "%s", argname);
374		assert(file != NULL);
375
376		if (strcmp(file, "-") == 0)
377			fd = STDIN_FILENO;
378		else {
379			fd = open(file, O_RDONLY);
380			if (fd == -1) {
381				gctl_error(req, "Cannot open %s %s: %s.",
382				    type, file, strerror(errno));
383				return (-1);
384			}
385		}
386		if (strcmp(type, "keyfile") == 0) {
387			while ((done = read(fd, buf, sizeof(buf))) > 0)
388				g_eli_crypto_hmac_update(ctxp, buf, done);
389		} else /* if (strcmp(type, "passfile") == 0) */ {
390			while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) {
391				buf[done] = '\0';
392				p = strchr(buf, '\n');
393				if (p != NULL) {
394					*p = '\0';
395					done = p - buf;
396				}
397				if (strlcat(passbuf, buf, passbufsize) >=
398				    passbufsize) {
399					gctl_error(req,
400					    "Passphrase in %s too long.", file);
401					bzero(buf, sizeof(buf));
402					return (-1);
403				}
404				if (p != NULL)
405					break;
406			}
407		}
408		error = errno;
409		if (strcmp(file, "-") != 0)
410			close(fd);
411		bzero(buf, sizeof(buf));
412		if (done == -1) {
413			gctl_error(req, "Cannot read %s %s: %s.",
414			    type, file, strerror(error));
415			return (-1);
416		}
417	}
418	/* NOTREACHED */
419}
420
421static int
422eli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf,
423    size_t passbufsize)
424{
425	char *p;
426
427	for (;;) {
428		p = readpassphrase(
429		    new ? "Enter new passphrase:" : "Enter passphrase:",
430		    passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY);
431		if (p == NULL) {
432			bzero(passbuf, passbufsize);
433			gctl_error(req, "Cannot read passphrase: %s.",
434			    strerror(errno));
435			return (-1);
436		}
437
438		if (new) {
439			char tmpbuf[BUFSIZ];
440
441			p = readpassphrase("Reenter new passphrase: ",
442			    tmpbuf, sizeof(tmpbuf),
443			    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
444			if (p == NULL) {
445				bzero(passbuf, passbufsize);
446				gctl_error(req,
447				    "Cannot read passphrase: %s.",
448				    strerror(errno));
449				return (-1);
450			}
451
452			if (strcmp(passbuf, tmpbuf) != 0) {
453				bzero(passbuf, passbufsize);
454				fprintf(stderr, "They didn't match.\n");
455				continue;
456			}
457			bzero(tmpbuf, sizeof(tmpbuf));
458		}
459		return (0);
460	}
461	/* NOTREACHED */
462}
463
464static int
465eli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new,
466    struct hmac_ctx *ctxp)
467{
468	char passbuf[MAXPHYS];
469	bool nopassphrase;
470	int nfiles;
471
472	nopassphrase =
473	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
474	if (nopassphrase) {
475		if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) {
476			gctl_error(req,
477			    "Options -%c and -%c are mutually exclusive.",
478			    new ? 'J' : 'j', new ? 'P' : 'p');
479			return (-1);
480		}
481		return (0);
482	}
483
484	if (!new && md->md_iterations == -1) {
485		gctl_error(req, "Missing -p flag.");
486		return (-1);
487	}
488	passbuf[0] = '\0';
489	nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf,
490	    sizeof(passbuf));
491	if (nfiles == -1)
492		return (-1);
493	else if (nfiles == 0) {
494		if (eli_genkey_passphrase_prompt(req, new, passbuf,
495		    sizeof(passbuf)) == -1) {
496			return (-1);
497		}
498	}
499	/*
500	 * Field md_iterations equal to -1 means "choose some sane
501	 * value for me".
502	 */
503	if (md->md_iterations == -1) {
504		assert(new);
505		if (verbose)
506			printf("Calculating number of iterations...\n");
507		md->md_iterations = pkcs5v2_calculate(2000000);
508		assert(md->md_iterations > 0);
509		if (verbose) {
510			printf("Done, using %d iterations.\n",
511			    md->md_iterations);
512		}
513	}
514	/*
515	 * If md_iterations is equal to 0, user doesn't want PKCS#5v2.
516	 */
517	if (md->md_iterations == 0) {
518		g_eli_crypto_hmac_update(ctxp, md->md_salt,
519		    sizeof(md->md_salt));
520		g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf));
521	} else /* if (md->md_iterations > 0) */ {
522		unsigned char dkey[G_ELI_USERKEYLEN];
523
524		pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
525		    sizeof(md->md_salt), passbuf, md->md_iterations);
526		g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey));
527		bzero(dkey, sizeof(dkey));
528	}
529	bzero(passbuf, sizeof(passbuf));
530
531	return (0);
532}
533
534static unsigned char *
535eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
536    bool new)
537{
538	struct hmac_ctx ctx;
539	bool nopassphrase;
540	int nfiles;
541
542	nopassphrase =
543	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
544
545	g_eli_crypto_hmac_init(&ctx, NULL, 0);
546
547	nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0);
548	if (nfiles == -1)
549		return (NULL);
550	else if (nfiles == 0 && nopassphrase) {
551		gctl_error(req, "No key components given.");
552		return (NULL);
553	}
554
555	if (eli_genkey_passphrase(req, md, new, &ctx) == -1)
556		return (NULL);
557
558	g_eli_crypto_hmac_final(&ctx, key, 0);
559
560	return (key);
561}
562
563static int
564eli_metadata_read(struct gctl_req *req, const char *prov,
565    struct g_eli_metadata *md)
566{
567	unsigned char sector[sizeof(struct g_eli_metadata)];
568	int error;
569
570	if (g_get_sectorsize(prov) == 0) {
571		int fd;
572
573		/* This is a file probably. */
574		fd = open(prov, O_RDONLY);
575		if (fd == -1) {
576			gctl_error(req, "Cannot open %s: %s.", prov,
577			    strerror(errno));
578			return (-1);
579		}
580		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
581			gctl_error(req, "Cannot read metadata from %s: %s.",
582			    prov, strerror(errno));
583			close(fd);
584			return (-1);
585		}
586		close(fd);
587	} else {
588		/* This is a GEOM provider. */
589		error = g_metadata_read(prov, sector, sizeof(sector),
590		    G_ELI_MAGIC);
591		if (error != 0) {
592			gctl_error(req, "Cannot read metadata from %s: %s.",
593			    prov, strerror(error));
594			return (-1);
595		}
596	}
597	if (eli_metadata_decode(sector, md) != 0) {
598		gctl_error(req, "MD5 hash mismatch for %s.", prov);
599		return (-1);
600	}
601	return (0);
602}
603
604static int
605eli_metadata_store(struct gctl_req *req, const char *prov,
606    struct g_eli_metadata *md)
607{
608	unsigned char sector[sizeof(struct g_eli_metadata)];
609	int error;
610
611	eli_metadata_encode(md, sector);
612	if (g_get_sectorsize(prov) == 0) {
613		int fd;
614
615		/* This is a file probably. */
616		fd = open(prov, O_WRONLY | O_TRUNC);
617		if (fd == -1) {
618			gctl_error(req, "Cannot open %s: %s.", prov,
619			    strerror(errno));
620			bzero(sector, sizeof(sector));
621			return (-1);
622		}
623		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
624			gctl_error(req, "Cannot write metadata to %s: %s.",
625			    prov, strerror(errno));
626			bzero(sector, sizeof(sector));
627			close(fd);
628			return (-1);
629		}
630		close(fd);
631	} else {
632		/* This is a GEOM provider. */
633		error = g_metadata_store(prov, sector, sizeof(sector));
634		if (error != 0) {
635			gctl_error(req, "Cannot write metadata to %s: %s.",
636			    prov, strerror(errno));
637			bzero(sector, sizeof(sector));
638			return (-1);
639		}
640	}
641	bzero(sector, sizeof(sector));
642	return (0);
643}
644
645static void
646eli_init(struct gctl_req *req)
647{
648	struct g_eli_metadata md;
649	unsigned char sector[sizeof(struct g_eli_metadata)];
650	unsigned char key[G_ELI_USERKEYLEN];
651	char backfile[MAXPATHLEN];
652	const char *str, *prov;
653	unsigned secsize;
654	off_t mediasize;
655	intmax_t val;
656	int error, nargs;
657
658	nargs = gctl_get_int(req, "nargs");
659	if (nargs != 1) {
660		gctl_error(req, "Invalid number of arguments.");
661		return;
662	}
663	prov = gctl_get_ascii(req, "arg0");
664	mediasize = g_get_mediasize(prov);
665	secsize = g_get_sectorsize(prov);
666	if (mediasize == 0 || secsize == 0) {
667		gctl_error(req, "Cannot get informations about %s: %s.", prov,
668		    strerror(errno));
669		return;
670	}
671
672	bzero(&md, sizeof(md));
673	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
674	md.md_version = G_ELI_VERSION;
675	md.md_flags = 0;
676	if (gctl_get_int(req, "boot"))
677		md.md_flags |= G_ELI_FLAG_BOOT;
678	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
679	str = gctl_get_ascii(req, "aalgo");
680	if (*str != '\0') {
681		md.md_aalgo = g_eli_str2aalgo(str);
682		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
683		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
684			md.md_flags |= G_ELI_FLAG_AUTH;
685		} else {
686			/*
687			 * For backward compatibility, check if the -a option
688			 * was used to provide encryption algorithm.
689			 */
690			md.md_ealgo = g_eli_str2ealgo(str);
691			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
692			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
693				gctl_error(req,
694				    "Invalid authentication algorithm.");
695				return;
696			} else {
697				fprintf(stderr, "warning: The -e option, not "
698				    "the -a option is now used to specify "
699				    "encryption algorithm to use.\n");
700			}
701		}
702	}
703	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
704	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
705		str = gctl_get_ascii(req, "ealgo");
706		md.md_ealgo = g_eli_str2ealgo(str);
707		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
708		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
709			gctl_error(req, "Invalid encryption algorithm.");
710			return;
711		}
712	}
713	val = gctl_get_intmax(req, "keylen");
714	md.md_keylen = val;
715	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
716	if (md.md_keylen == 0) {
717		gctl_error(req, "Invalid key length.");
718		return;
719	}
720	md.md_provsize = mediasize;
721
722	val = gctl_get_intmax(req, "iterations");
723	if (val != -1) {
724		int nonewpassphrase;
725
726		/*
727		 * Don't allow to set iterations when there will be no
728		 * passphrase.
729		 */
730		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
731		if (nonewpassphrase) {
732			gctl_error(req,
733			    "Options -i and -P are mutually exclusive.");
734			return;
735		}
736	}
737	md.md_iterations = val;
738
739	val = gctl_get_intmax(req, "sectorsize");
740	if (val == 0)
741		md.md_sectorsize = secsize;
742	else {
743		if (val < 0 || (val % secsize) != 0) {
744			gctl_error(req, "Invalid sector size.");
745			return;
746		}
747		if (val > sysconf(_SC_PAGE_SIZE)) {
748			fprintf(stderr,
749			    "warning: Using sectorsize bigger than the page size!\n");
750		}
751		md.md_sectorsize = val;
752	}
753
754	md.md_keys = 0x01;
755	arc4rand(md.md_salt, sizeof(md.md_salt));
756	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
757
758	/* Generate user key. */
759	if (eli_genkey(req, &md, key, true) == NULL) {
760		bzero(key, sizeof(key));
761		bzero(&md, sizeof(md));
762		return;
763	}
764
765	/* Encrypt the first and the only Master Key. */
766	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
767	bzero(key, sizeof(key));
768	if (error != 0) {
769		bzero(&md, sizeof(md));
770		gctl_error(req, "Cannot encrypt Master Key: %s.",
771		    strerror(error));
772		return;
773	}
774
775	eli_metadata_encode(&md, sector);
776	bzero(&md, sizeof(md));
777	error = g_metadata_store(prov, sector, sizeof(sector));
778	bzero(sector, sizeof(sector));
779	if (error != 0) {
780		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
781		    strerror(error));
782		return;
783	}
784	if (verbose)
785		printf("Metadata value stored on %s.\n", prov);
786	/* Backup metadata to a file. */
787	str = gctl_get_ascii(req, "backupfile");
788	if (str[0] != '\0') {
789		/* Backupfile given be the user, just copy it. */
790		strlcpy(backfile, str, sizeof(backfile));
791	} else {
792		/* Generate file name automatically. */
793		const char *p = prov;
794		unsigned int i;
795
796		if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
797			p += sizeof(_PATH_DEV) - 1;
798		snprintf(backfile, sizeof(backfile), "%s%s.eli",
799		    GELI_BACKUP_DIR, p);
800		/* Replace all / with _. */
801		for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
802			if (backfile[i] == '/')
803				backfile[i] = '_';
804		}
805	}
806	if (strcmp(backfile, "none") != 0 &&
807	    eli_backup_create(req, prov, backfile) == 0) {
808		printf("\nMetadata backup can be found in %s and\n", backfile);
809		printf("can be restored with the following command:\n");
810		printf("\n\t# geli restore %s %s\n\n", backfile, prov);
811	}
812}
813
814static void
815eli_attach(struct gctl_req *req)
816{
817	struct g_eli_metadata md;
818	unsigned char key[G_ELI_USERKEYLEN];
819	const char *prov;
820	off_t mediasize;
821	int nargs;
822
823	nargs = gctl_get_int(req, "nargs");
824	if (nargs != 1) {
825		gctl_error(req, "Invalid number of arguments.");
826		return;
827	}
828	prov = gctl_get_ascii(req, "arg0");
829
830	if (eli_metadata_read(req, prov, &md) == -1)
831		return;
832
833	mediasize = g_get_mediasize(prov);
834	if (md.md_provsize != (uint64_t)mediasize) {
835		gctl_error(req, "Provider size mismatch.");
836		return;
837	}
838
839	if (eli_genkey(req, &md, key, false) == NULL) {
840		bzero(key, sizeof(key));
841		return;
842	}
843
844	gctl_ro_param(req, "key", sizeof(key), key);
845	if (gctl_issue(req) == NULL) {
846		if (verbose)
847			printf("Attached to %s.\n", prov);
848	}
849	bzero(key, sizeof(key));
850}
851
852static void
853eli_configure_detached(struct gctl_req *req, const char *prov, bool boot)
854{
855	struct g_eli_metadata md;
856
857	if (eli_metadata_read(req, prov, &md) == -1)
858		return;
859
860	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
861		if (verbose)
862			printf("BOOT flag already configured for %s.\n", prov);
863	} else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) {
864		if (verbose)
865			printf("BOOT flag not configured for %s.\n", prov);
866	} else {
867		if (boot)
868			md.md_flags |= G_ELI_FLAG_BOOT;
869		else
870			md.md_flags &= ~G_ELI_FLAG_BOOT;
871		eli_metadata_store(req, prov, &md);
872	}
873	bzero(&md, sizeof(md));
874}
875
876static void
877eli_configure(struct gctl_req *req)
878{
879	const char *prov;
880	bool boot, noboot;
881	int i, nargs;
882
883	nargs = gctl_get_int(req, "nargs");
884	if (nargs == 0) {
885		gctl_error(req, "Too few arguments.");
886		return;
887	}
888
889	boot = gctl_get_int(req, "boot");
890	noboot = gctl_get_int(req, "noboot");
891
892	if (boot && noboot) {
893		gctl_error(req, "Options -b and -B are mutually exclusive.");
894		return;
895	}
896	if (!boot && !noboot) {
897		gctl_error(req, "No option given.");
898		return;
899	}
900
901	/* First attached providers. */
902	gctl_issue(req);
903	/* Now the rest. */
904	for (i = 0; i < nargs; i++) {
905		prov = gctl_get_ascii(req, "arg%d", i);
906		if (!eli_is_attached(prov))
907			eli_configure_detached(req, prov, boot);
908	}
909}
910
911static void
912eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
913{
914	unsigned char key[G_ELI_USERKEYLEN];
915	intmax_t val, old = 0;
916	int error;
917
918	val = gctl_get_intmax(req, "iterations");
919	/* Check if iterations number should be changed. */
920	if (val != -1)
921		md->md_iterations = val;
922	else
923		old = md->md_iterations;
924
925	/* Generate key for Master Key encryption. */
926	if (eli_genkey(req, md, key, true) == NULL) {
927		bzero(key, sizeof(key));
928		return;
929	}
930	/*
931	 * If number of iterations has changed, but wasn't given as a
932	 * command-line argument, update the request.
933	 */
934	if (val == -1 && md->md_iterations != old) {
935		error = gctl_change_param(req, "iterations", sizeof(intmax_t),
936		    &md->md_iterations);
937		assert(error == 0);
938	}
939
940	gctl_ro_param(req, "key", sizeof(key), key);
941	gctl_issue(req);
942	bzero(key, sizeof(key));
943}
944
945static void
946eli_setkey_detached(struct gctl_req *req, const char *prov,
947 struct g_eli_metadata *md)
948{
949	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
950	unsigned char *mkeydst;
951	unsigned int nkey;
952	intmax_t val;
953	int error;
954
955	if (md->md_keys == 0) {
956		gctl_error(req, "No valid keys on %s.", prov);
957		return;
958	}
959
960	/* Generate key for Master Key decryption. */
961	if (eli_genkey(req, md, key, false) == NULL) {
962		bzero(key, sizeof(key));
963		return;
964	}
965
966	/* Decrypt Master Key. */
967	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
968	bzero(key, sizeof(key));
969	if (error != 0) {
970		bzero(md, sizeof(*md));
971		if (error == -1)
972			gctl_error(req, "Wrong key for %s.", prov);
973		else /* if (error > 0) */ {
974			gctl_error(req, "Cannot decrypt Master Key: %s.",
975			    strerror(error));
976		}
977		return;
978	}
979	if (verbose)
980		printf("Decrypted Master Key %u.\n", nkey);
981
982	val = gctl_get_intmax(req, "keyno");
983	if (val != -1)
984		nkey = val;
985#if 0
986	else
987		; /* Use the key number which was found during decryption. */
988#endif
989	if (nkey >= G_ELI_MAXMKEYS) {
990		gctl_error(req, "Invalid '%s' argument.", "keyno");
991		return;
992	}
993
994	val = gctl_get_intmax(req, "iterations");
995	/* Check if iterations number should and can be changed. */
996	if (val != -1) {
997		if (bitcount32(md->md_keys) != 1) {
998			gctl_error(req, "To be able to use '-i' option, only "
999			    "one key can be defined.");
1000			return;
1001		}
1002		if (md->md_keys != (1 << nkey)) {
1003			gctl_error(req, "Only already defined key can be "
1004			    "changed when '-i' option is used.");
1005			return;
1006		}
1007		md->md_iterations = val;
1008	}
1009
1010	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
1011	md->md_keys |= (1 << nkey);
1012
1013	bcopy(mkey, mkeydst, sizeof(mkey));
1014	bzero(mkey, sizeof(mkey));
1015
1016	/* Generate key for Master Key encryption. */
1017	if (eli_genkey(req, md, key, true) == NULL) {
1018		bzero(key, sizeof(key));
1019		bzero(md, sizeof(*md));
1020		return;
1021	}
1022
1023	/* Encrypt the Master-Key with the new key. */
1024	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
1025	bzero(key, sizeof(key));
1026	if (error != 0) {
1027		bzero(md, sizeof(*md));
1028		gctl_error(req, "Cannot encrypt Master Key: %s.",
1029		    strerror(error));
1030		return;
1031	}
1032
1033	/* Store metadata with fresh key. */
1034	eli_metadata_store(req, prov, md);
1035	bzero(md, sizeof(*md));
1036}
1037
1038static void
1039eli_setkey(struct gctl_req *req)
1040{
1041	struct g_eli_metadata md;
1042	const char *prov;
1043	int nargs;
1044
1045	nargs = gctl_get_int(req, "nargs");
1046	if (nargs != 1) {
1047		gctl_error(req, "Invalid number of arguments.");
1048		return;
1049	}
1050	prov = gctl_get_ascii(req, "arg0");
1051
1052	if (eli_metadata_read(req, prov, &md) == -1)
1053		return;
1054
1055	if (eli_is_attached(prov))
1056		eli_setkey_attached(req, &md);
1057	else
1058		eli_setkey_detached(req, prov, &md);
1059
1060	if (req->error == NULL || req->error[0] == '\0') {
1061		printf("Note, that the master key encrypted with old keys "
1062		    "and/or passphrase may still exists in a metadata backup "
1063		    "file.\n");
1064	}
1065}
1066
1067static void
1068eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
1069{
1070
1071	gctl_issue(req);
1072}
1073
1074static void
1075eli_delkey_detached(struct gctl_req *req, const char *prov)
1076{
1077	struct g_eli_metadata md;
1078	unsigned char *mkeydst;
1079	unsigned int nkey;
1080	intmax_t val;
1081	bool all, force;
1082
1083	if (eli_metadata_read(req, prov, &md) == -1)
1084		return;
1085
1086	all = gctl_get_int(req, "all");
1087	if (all)
1088		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
1089	else {
1090		force = gctl_get_int(req, "force");
1091		val = gctl_get_intmax(req, "keyno");
1092		if (val == -1) {
1093			gctl_error(req, "Key number has to be specified.");
1094			return;
1095		}
1096		nkey = val;
1097		if (nkey >= G_ELI_MAXMKEYS) {
1098			gctl_error(req, "Invalid '%s' argument.", "keyno");
1099			return;
1100		}
1101		if (!(md.md_keys & (1 << nkey)) && !force) {
1102			gctl_error(req, "Master Key %u is not set.", nkey);
1103			return;
1104		}
1105		md.md_keys &= ~(1 << nkey);
1106		if (md.md_keys == 0 && !force) {
1107			gctl_error(req, "This is the last Master Key. Use '-f' "
1108			    "option if you really want to remove it.");
1109			return;
1110		}
1111		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
1112		arc4rand(mkeydst, G_ELI_MKEYLEN);
1113	}
1114
1115	eli_metadata_store(req, prov, &md);
1116	bzero(&md, sizeof(md));
1117}
1118
1119static void
1120eli_delkey(struct gctl_req *req)
1121{
1122	const char *prov;
1123	int nargs;
1124
1125	nargs = gctl_get_int(req, "nargs");
1126	if (nargs != 1) {
1127		gctl_error(req, "Invalid number of arguments.");
1128		return;
1129	}
1130	prov = gctl_get_ascii(req, "arg0");
1131
1132	if (eli_is_attached(prov))
1133		eli_delkey_attached(req, prov);
1134	else
1135		eli_delkey_detached(req, prov);
1136}
1137
1138static void
1139eli_resume(struct gctl_req *req)
1140{
1141	struct g_eli_metadata md;
1142	unsigned char key[G_ELI_USERKEYLEN];
1143	const char *prov;
1144	off_t mediasize;
1145	int nargs;
1146
1147	nargs = gctl_get_int(req, "nargs");
1148	if (nargs != 1) {
1149		gctl_error(req, "Invalid number of arguments.");
1150		return;
1151	}
1152	prov = gctl_get_ascii(req, "arg0");
1153
1154	if (eli_metadata_read(req, prov, &md) == -1)
1155		return;
1156
1157	mediasize = g_get_mediasize(prov);
1158	if (md.md_provsize != (uint64_t)mediasize) {
1159		gctl_error(req, "Provider size mismatch.");
1160		return;
1161	}
1162
1163	if (eli_genkey(req, &md, key, false) == NULL) {
1164		bzero(key, sizeof(key));
1165		return;
1166	}
1167
1168	gctl_ro_param(req, "key", sizeof(key), key);
1169	if (gctl_issue(req) == NULL) {
1170		if (verbose)
1171			printf("Resumed %s.\n", prov);
1172	}
1173	bzero(key, sizeof(key));
1174}
1175
1176static int
1177eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset)
1178{
1179	unsigned int overwrites;
1180	unsigned char *sector;
1181	ssize_t size;
1182	int error;
1183
1184	size = sizeof(overwrites);
1185	if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size,
1186	    NULL, 0) == -1 || overwrites == 0) {
1187		overwrites = G_ELI_OVERWRITES;
1188	}
1189
1190	size = g_sectorsize(fd);
1191	if (size <= 0) {
1192		gctl_error(req, "Cannot obtain provider sector size %s: %s.",
1193		    prov, strerror(errno));
1194		return (-1);
1195	}
1196	sector = malloc(size);
1197	if (sector == NULL) {
1198		gctl_error(req, "Cannot allocate %zd bytes of memory.", size);
1199		return (-1);
1200	}
1201
1202	error = 0;
1203	do {
1204		arc4rand(sector, size);
1205		if (pwrite(fd, sector, size, offset) != size) {
1206			if (error == 0)
1207				error = errno;
1208		}
1209		(void)g_flush(fd);
1210	} while (--overwrites > 0);
1211	if (error != 0) {
1212		gctl_error(req, "Cannot trash metadata on provider %s: %s.",
1213		    prov, strerror(error));
1214		return (-1);
1215	}
1216	return (0);
1217}
1218
1219static void
1220eli_kill_detached(struct gctl_req *req, const char *prov)
1221{
1222	off_t offset;
1223	int fd;
1224
1225	/*
1226	 * NOTE: Maybe we should verify if this is geli provider first,
1227	 *       but 'kill' command is quite critical so better don't waste
1228	 *       the time.
1229	 */
1230#if 0
1231	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
1232	    G_ELI_MAGIC);
1233	if (error != 0) {
1234		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
1235		    strerror(error));
1236		return;
1237	}
1238#endif
1239
1240	fd = g_open(prov, 1);
1241	if (fd == -1) {
1242		gctl_error(req, "Cannot open provider %s: %s.", prov,
1243		    strerror(errno));
1244		return;
1245	}
1246	offset = g_mediasize(fd) - g_sectorsize(fd);
1247	if (offset <= 0) {
1248		gctl_error(req,
1249		    "Cannot obtain media size or sector size for provider %s: %s.",
1250		    prov, strerror(errno));
1251		(void)g_close(fd);
1252		return;
1253	}
1254	(void)eli_trash_metadata(req, prov, fd, offset);
1255	(void)g_close(fd);
1256}
1257
1258static void
1259eli_kill(struct gctl_req *req)
1260{
1261	const char *prov;
1262	int i, nargs, all;
1263
1264	nargs = gctl_get_int(req, "nargs");
1265	all = gctl_get_int(req, "all");
1266	if (!all && nargs == 0) {
1267		gctl_error(req, "Too few arguments.");
1268		return;
1269	}
1270	/*
1271	 * How '-a' option combine with a list of providers:
1272	 * Delete Master Keys from all attached providers:
1273	 * geli kill -a
1274	 * Delete Master Keys from all attached providers and from
1275	 * detached da0 and da1:
1276	 * geli kill -a da0 da1
1277	 * Delete Master Keys from (attached or detached) da0 and da1:
1278	 * geli kill da0 da1
1279	 */
1280
1281	/* First detached providers. */
1282	for (i = 0; i < nargs; i++) {
1283		prov = gctl_get_ascii(req, "arg%d", i);
1284		if (!eli_is_attached(prov))
1285			eli_kill_detached(req, prov);
1286	}
1287	/* Now attached providers. */
1288	gctl_issue(req);
1289}
1290
1291static int
1292eli_backup_create(struct gctl_req *req, const char *prov, const char *file)
1293{
1294	unsigned char *sector;
1295	ssize_t secsize;
1296	int error, filefd, ret;
1297
1298	ret = -1;
1299	filefd = -1;
1300	sector = NULL;
1301	secsize = 0;
1302
1303	secsize = g_get_sectorsize(prov);
1304	if (secsize == 0) {
1305		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1306		    strerror(errno));
1307		goto out;
1308	}
1309	sector = malloc(secsize);
1310	if (sector == NULL) {
1311		gctl_error(req, "Cannot allocate memory.");
1312		goto out;
1313	}
1314	/* Read metadata from the provider. */
1315	error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC);
1316	if (error != 0) {
1317		gctl_error(req, "Unable to read metadata from %s: %s.", prov,
1318		    strerror(error));
1319		goto out;
1320	}
1321
1322	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1323	if (filefd == -1) {
1324		gctl_error(req, "Unable to open %s: %s.", file,
1325		    strerror(errno));
1326		goto out;
1327	}
1328	/* Write metadata to the destination file. */
1329	if (write(filefd, sector, secsize) != secsize) {
1330		gctl_error(req, "Unable to write to %s: %s.", file,
1331		    strerror(errno));
1332		(void)close(filefd);
1333		(void)unlink(file);
1334		goto out;
1335	}
1336	(void)fsync(filefd);
1337	(void)close(filefd);
1338	/* Success. */
1339	ret = 0;
1340out:
1341	if (sector != NULL) {
1342		bzero(sector, secsize);
1343		free(sector);
1344	}
1345	return (ret);
1346}
1347
1348static void
1349eli_backup(struct gctl_req *req)
1350{
1351	const char *file, *prov;
1352	int nargs;
1353
1354	nargs = gctl_get_int(req, "nargs");
1355	if (nargs != 2) {
1356		gctl_error(req, "Invalid number of arguments.");
1357		return;
1358	}
1359	prov = gctl_get_ascii(req, "arg0");
1360	file = gctl_get_ascii(req, "arg1");
1361
1362	eli_backup_create(req, prov, file);
1363}
1364
1365static void
1366eli_restore(struct gctl_req *req)
1367{
1368	struct g_eli_metadata md;
1369	const char *file, *prov;
1370	off_t mediasize;
1371	int nargs;
1372
1373	nargs = gctl_get_int(req, "nargs");
1374	if (nargs != 2) {
1375		gctl_error(req, "Invalid number of arguments.");
1376		return;
1377	}
1378	file = gctl_get_ascii(req, "arg0");
1379	prov = gctl_get_ascii(req, "arg1");
1380
1381	/* Read metadata from the backup file. */
1382	if (eli_metadata_read(req, file, &md) == -1)
1383		return;
1384	/* Obtain provider's mediasize. */
1385	mediasize = g_get_mediasize(prov);
1386	if (mediasize == 0) {
1387		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1388		    strerror(errno));
1389		return;
1390	}
1391	/* Check if the provider size has changed since we did the backup. */
1392	if (md.md_provsize != (uint64_t)mediasize) {
1393		if (gctl_get_int(req, "force")) {
1394			md.md_provsize = mediasize;
1395		} else {
1396			gctl_error(req, "Provider size mismatch: "
1397			    "wrong backup file?");
1398			return;
1399		}
1400	}
1401	/* Write metadata to the provider. */
1402	(void)eli_metadata_store(req, prov, &md);
1403}
1404
1405static void
1406eli_resize(struct gctl_req *req)
1407{
1408	struct g_eli_metadata md;
1409	const char *prov;
1410	unsigned char *sector;
1411	ssize_t secsize;
1412	off_t mediasize, oldsize;
1413	int nargs, provfd;
1414
1415	nargs = gctl_get_int(req, "nargs");
1416	if (nargs != 1) {
1417		gctl_error(req, "Invalid number of arguments.");
1418		return;
1419	}
1420	prov = gctl_get_ascii(req, "arg0");
1421
1422	provfd = -1;
1423	sector = NULL;
1424	secsize = 0;
1425
1426	provfd = g_open(prov, 1);
1427	if (provfd == -1) {
1428		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1429		goto out;
1430	}
1431
1432	mediasize = g_mediasize(provfd);
1433	secsize = g_sectorsize(provfd);
1434	if (mediasize == -1 || secsize == -1) {
1435		gctl_error(req, "Cannot get information about %s: %s.", prov,
1436		    strerror(errno));
1437		goto out;
1438	}
1439
1440	sector = malloc(secsize);
1441	if (sector == NULL) {
1442		gctl_error(req, "Cannot allocate memory.");
1443		goto out;
1444	}
1445
1446	oldsize = gctl_get_intmax(req, "oldsize");
1447	if (oldsize < 0 || oldsize > mediasize) {
1448		gctl_error(req, "Invalid oldsize: Out of range.");
1449		goto out;
1450	}
1451	if (oldsize == mediasize) {
1452		gctl_error(req, "Size hasn't changed.");
1453		goto out;
1454	}
1455
1456	/* Read metadata from the 'oldsize' offset. */
1457	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
1458		gctl_error(req, "Cannot read old metadata: %s.",
1459		    strerror(errno));
1460		goto out;
1461	}
1462
1463	/* Check if this sector contains geli metadata. */
1464	if (eli_metadata_decode(sector, &md) != 0) {
1465		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
1466		goto out;
1467	}
1468
1469	/*
1470	 * If the old metadata doesn't have a correct provider size, refuse
1471	 * to resize.
1472	 */
1473	if (md.md_provsize != (uint64_t)oldsize) {
1474		gctl_error(req, "Provider size mismatch at oldsize.");
1475		goto out;
1476	}
1477
1478	/*
1479	 * Update the old metadata with the current provider size and write
1480	 * it back to the correct place on the provider.
1481	 */
1482	md.md_provsize = mediasize;
1483	eli_metadata_encode(&md, sector);
1484	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
1485		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1486		goto out;
1487	}
1488	(void)g_flush(provfd);
1489
1490	/* Now trash the old metadata. */
1491	if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
1492		goto out;
1493out:
1494	if (provfd >= 0)
1495		(void)g_close(provfd);
1496	if (sector != NULL) {
1497		bzero(sector, secsize);
1498		free(sector);
1499	}
1500}
1501
1502static void
1503eli_clear(struct gctl_req *req)
1504{
1505	const char *name;
1506	int error, i, nargs;
1507
1508	nargs = gctl_get_int(req, "nargs");
1509	if (nargs < 1) {
1510		gctl_error(req, "Too few arguments.");
1511		return;
1512	}
1513
1514	for (i = 0; i < nargs; i++) {
1515		name = gctl_get_ascii(req, "arg%d", i);
1516		error = g_metadata_clear(name, G_ELI_MAGIC);
1517		if (error != 0) {
1518			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1519			    name, strerror(error));
1520			gctl_error(req, "Not fully done.");
1521			continue;
1522		}
1523		if (verbose)
1524			printf("Metadata cleared on %s.\n", name);
1525	}
1526}
1527
1528static void
1529eli_dump(struct gctl_req *req)
1530{
1531	struct g_eli_metadata md, tmpmd;
1532	const char *name;
1533	int error, i, nargs;
1534
1535	nargs = gctl_get_int(req, "nargs");
1536	if (nargs < 1) {
1537		gctl_error(req, "Too few arguments.");
1538		return;
1539	}
1540
1541	for (i = 0; i < nargs; i++) {
1542		name = gctl_get_ascii(req, "arg%d", i);
1543		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1544		    sizeof(tmpmd), G_ELI_MAGIC);
1545		if (error != 0) {
1546			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1547			    name, strerror(error));
1548			gctl_error(req, "Not fully done.");
1549			continue;
1550		}
1551		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1552			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1553			    name);
1554			gctl_error(req, "Not fully done.");
1555			continue;
1556		}
1557		printf("Metadata on %s:\n", name);
1558		eli_metadata_dump(&md);
1559		printf("\n");
1560	}
1561}
1562