geom_eli.c revision 214404
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 214404 2010-10-26 22:46:15Z pjd $");
29
30#include <sys/types.h>
31#include <sys/sysctl.h>
32
33#include <stdbool.h>
34#include <stdio.h>
35#include <stdint.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <readpassphrase.h>
40#include <string.h>
41#include <strings.h>
42#include <libgeom.h>
43#include <paths.h>
44#include <errno.h>
45#include <assert.h>
46
47#include <sys/param.h>
48#include <sys/mman.h>
49#include <sys/resource.h>
50#include <opencrypto/cryptodev.h>
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 int
337eli_is_attached(const char *prov)
338{
339	char name[MAXPATHLEN];
340	unsigned secsize;
341
342	/*
343	 * Not the best way to do it, but the easiest.
344	 * We try to open provider and check if it is a GEOM provider
345	 * by asking about its sectorsize.
346	 */
347	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
348	secsize = g_get_sectorsize(name);
349	if (secsize > 0)
350		return (1);
351	return (0);
352}
353
354static int
355eli_genkey_files(struct gctl_req *req, bool new, const char *type,
356    struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize)
357{
358	char *p, buf[MAXPHYS], argname[16];
359	const char *file;
360	int error, fd, i;
361	ssize_t done;
362
363	assert((strcmp(type, "keyfile") == 0 && ctxp != NULL &&
364	    passbuf == NULL && passbufsize == 0) ||
365	    (strcmp(type, "passfile") == 0 && ctxp == NULL &&
366	    passbuf != NULL && passbufsize > 0));
367	assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0');
368
369	for (i = 0; ; i++) {
370		snprintf(argname, sizeof(argname), "%s%s%d",
371		    new ? "new" : "", type, i);
372
373		/* No more {key,pass}files? */
374		if (!gctl_has_param(req, argname))
375			return (i);
376
377		file = gctl_get_ascii(req, argname);
378		assert(file != NULL);
379
380		if (strcmp(file, "-") == 0)
381			fd = STDIN_FILENO;
382		else {
383			fd = open(file, O_RDONLY);
384			if (fd == -1) {
385				gctl_error(req, "Cannot open %s %s: %s.",
386				    type, file, strerror(errno));
387				return (-1);
388			}
389		}
390		if (strcmp(type, "keyfile") == 0) {
391			while ((done = read(fd, buf, sizeof(buf))) > 0)
392				g_eli_crypto_hmac_update(ctxp, buf, done);
393		} else /* if (strcmp(type, "passfile") == 0) */ {
394			while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) {
395				buf[done] = '\0';
396				p = strchr(buf, '\n');
397				if (p != NULL) {
398					*p = '\0';
399					done = p - buf;
400				}
401				if (strlcat(passbuf, buf, passbufsize) >=
402				    passbufsize) {
403					gctl_error(req,
404					    "Passphrase in %s too long.", file);
405					bzero(buf, sizeof(buf));
406					return (-1);
407				}
408				if (p != NULL)
409					break;
410			}
411		}
412		error = errno;
413		if (strcmp(file, "-") != 0)
414			close(fd);
415		bzero(buf, sizeof(buf));
416		if (done == -1) {
417			gctl_error(req, "Cannot read %s %s: %s.",
418			    type, file, strerror(error));
419			return (-1);
420		}
421	}
422	/* NOTREACHED */
423}
424
425static int
426eli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf,
427    size_t passbufsize)
428{
429	char *p;
430
431	for (;;) {
432		p = readpassphrase(
433		    new ? "Enter new passphrase:" : "Enter passphrase:",
434		    passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY);
435		if (p == NULL) {
436			bzero(passbuf, passbufsize);
437			gctl_error(req, "Cannot read passphrase: %s.",
438			    strerror(errno));
439			return (-1);
440		}
441
442		if (new) {
443			char tmpbuf[BUFSIZ];
444
445			p = readpassphrase("Reenter new passphrase: ",
446			    tmpbuf, sizeof(tmpbuf),
447			    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
448			if (p == NULL) {
449				bzero(passbuf, passbufsize);
450				gctl_error(req,
451				    "Cannot read passphrase: %s.",
452				    strerror(errno));
453				return (-1);
454			}
455
456			if (strcmp(passbuf, tmpbuf) != 0) {
457				bzero(passbuf, passbufsize);
458				fprintf(stderr, "They didn't match.\n");
459				continue;
460			}
461			bzero(tmpbuf, sizeof(tmpbuf));
462		}
463		return (0);
464	}
465	/* NOTREACHED */
466}
467
468static int
469eli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new,
470    struct hmac_ctx *ctxp)
471{
472	char passbuf[MAXPHYS];
473	bool nopassphrase;
474	int nfiles;
475
476	nopassphrase =
477	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
478	if (nopassphrase) {
479		if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) {
480			gctl_error(req,
481			    "Options -%c and -%c are mutually exclusive.",
482			    new ? 'J' : 'j', new ? 'P' : 'p');
483			return (-1);
484		}
485		return (0);
486	}
487
488	if (!new && md->md_iterations == -1) {
489		gctl_error(req, "Missing -p flag.");
490		return (-1);
491	}
492	passbuf[0] = '\0';
493	nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf,
494	    sizeof(passbuf));
495	if (nfiles == -1)
496		return (-1);
497	else if (nfiles == 0) {
498		if (eli_genkey_passphrase_prompt(req, new, passbuf,
499		    sizeof(passbuf)) == -1) {
500			return (-1);
501		}
502	}
503	/*
504	 * Field md_iterations equal to -1 means "choose some sane
505	 * value for me".
506	 */
507	if (md->md_iterations == -1) {
508		assert(new);
509		if (verbose)
510			printf("Calculating number of iterations...\n");
511		md->md_iterations = pkcs5v2_calculate(2000000);
512		assert(md->md_iterations > 0);
513		if (verbose) {
514			printf("Done, using %d iterations.\n",
515			    md->md_iterations);
516		}
517	}
518	/*
519	 * If md_iterations is equal to 0, user doesn't want PKCS#5v2.
520	 */
521	if (md->md_iterations == 0) {
522		g_eli_crypto_hmac_update(ctxp, md->md_salt,
523		    sizeof(md->md_salt));
524		g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf));
525	} else /* if (md->md_iterations > 0) */ {
526		unsigned char dkey[G_ELI_USERKEYLEN];
527
528		pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
529		    sizeof(md->md_salt), passbuf, md->md_iterations);
530		g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey));
531		bzero(dkey, sizeof(dkey));
532	}
533	bzero(passbuf, sizeof(passbuf));
534
535	return (0);
536}
537
538static unsigned char *
539eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
540    bool new)
541{
542	struct hmac_ctx ctx;
543	bool nopassphrase;
544	int nfiles;
545
546	nopassphrase =
547	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
548
549	g_eli_crypto_hmac_init(&ctx, NULL, 0);
550
551	nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0);
552	if (nfiles == -1)
553		return (NULL);
554	else if (nfiles == 0 && nopassphrase) {
555		gctl_error(req, "No key components given.");
556		return (NULL);
557	}
558
559	if (eli_genkey_passphrase(req, md, new, &ctx) == -1)
560		return (NULL);
561
562	g_eli_crypto_hmac_final(&ctx, key, 0);
563
564	return (key);
565}
566
567static int
568eli_metadata_read(struct gctl_req *req, const char *prov,
569    struct g_eli_metadata *md)
570{
571	unsigned char sector[sizeof(struct g_eli_metadata)];
572	int error;
573
574	if (g_get_sectorsize(prov) == 0) {
575		int fd;
576
577		/* This is a file probably. */
578		fd = open(prov, O_RDONLY);
579		if (fd == -1) {
580			gctl_error(req, "Cannot open %s: %s.", prov,
581			    strerror(errno));
582			return (-1);
583		}
584		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
585			gctl_error(req, "Cannot read metadata from %s: %s.",
586			    prov, strerror(errno));
587			close(fd);
588			return (-1);
589		}
590		close(fd);
591	} else {
592		/* This is a GEOM provider. */
593		error = g_metadata_read(prov, sector, sizeof(sector),
594		    G_ELI_MAGIC);
595		if (error != 0) {
596			gctl_error(req, "Cannot read metadata from %s: %s.",
597			    prov, strerror(error));
598			return (-1);
599		}
600	}
601	if (eli_metadata_decode(sector, md) != 0) {
602		gctl_error(req, "MD5 hash mismatch for %s.", prov);
603		return (-1);
604	}
605	return (0);
606}
607
608static int
609eli_metadata_store(struct gctl_req *req, const char *prov,
610    struct g_eli_metadata *md)
611{
612	unsigned char sector[sizeof(struct g_eli_metadata)];
613	int error;
614
615	eli_metadata_encode(md, sector);
616	if (g_get_sectorsize(prov) == 0) {
617		int fd;
618
619		/* This is a file probably. */
620		fd = open(prov, O_WRONLY | O_TRUNC);
621		if (fd == -1) {
622			gctl_error(req, "Cannot open %s: %s.", prov,
623			    strerror(errno));
624			bzero(sector, sizeof(sector));
625			return (-1);
626		}
627		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
628			gctl_error(req, "Cannot write metadata to %s: %s.",
629			    prov, strerror(errno));
630			bzero(sector, sizeof(sector));
631			close(fd);
632			return (-1);
633		}
634		close(fd);
635	} else {
636		/* This is a GEOM provider. */
637		error = g_metadata_store(prov, sector, sizeof(sector));
638		if (error != 0) {
639			gctl_error(req, "Cannot write metadata to %s: %s.",
640			    prov, strerror(errno));
641			bzero(sector, sizeof(sector));
642			return (-1);
643		}
644	}
645	bzero(sector, sizeof(sector));
646	return (0);
647}
648
649static void
650eli_init(struct gctl_req *req)
651{
652	struct g_eli_metadata md;
653	unsigned char sector[sizeof(struct g_eli_metadata)];
654	unsigned char key[G_ELI_USERKEYLEN];
655	char backfile[MAXPATHLEN];
656	const char *str, *prov;
657	unsigned secsize;
658	off_t mediasize;
659	intmax_t val;
660	int error, nargs;
661
662	nargs = gctl_get_int(req, "nargs");
663	if (nargs != 1) {
664		gctl_error(req, "Invalid number of arguments.");
665		return;
666	}
667	prov = gctl_get_ascii(req, "arg0");
668	mediasize = g_get_mediasize(prov);
669	secsize = g_get_sectorsize(prov);
670	if (mediasize == 0 || secsize == 0) {
671		gctl_error(req, "Cannot get informations about %s: %s.", prov,
672		    strerror(errno));
673		return;
674	}
675
676	bzero(&md, sizeof(md));
677	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
678	md.md_version = G_ELI_VERSION;
679	md.md_flags = 0;
680	if (gctl_get_int(req, "boot"))
681		md.md_flags |= G_ELI_FLAG_BOOT;
682	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
683	str = gctl_get_ascii(req, "aalgo");
684	if (*str != '\0') {
685		md.md_aalgo = g_eli_str2aalgo(str);
686		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
687		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
688			md.md_flags |= G_ELI_FLAG_AUTH;
689		} else {
690			/*
691			 * For backward compatibility, check if the -a option
692			 * was used to provide encryption algorithm.
693			 */
694			md.md_ealgo = g_eli_str2ealgo(str);
695			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
696			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
697				gctl_error(req,
698				    "Invalid authentication algorithm.");
699				return;
700			} else {
701				fprintf(stderr, "warning: The -e option, not "
702				    "the -a option is now used to specify "
703				    "encryption algorithm to use.\n");
704			}
705		}
706	}
707	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
708	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
709		str = gctl_get_ascii(req, "ealgo");
710		md.md_ealgo = g_eli_str2ealgo(str);
711		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
712		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
713			gctl_error(req, "Invalid encryption algorithm.");
714			return;
715		}
716	}
717	val = gctl_get_intmax(req, "keylen");
718	md.md_keylen = val;
719	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
720	if (md.md_keylen == 0) {
721		gctl_error(req, "Invalid key length.");
722		return;
723	}
724	md.md_provsize = mediasize;
725
726	val = gctl_get_intmax(req, "iterations");
727	if (val != -1) {
728		int nonewpassphrase;
729
730		/*
731		 * Don't allow to set iterations when there will be no
732		 * passphrase.
733		 */
734		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
735		if (nonewpassphrase) {
736			gctl_error(req,
737			    "Options -i and -P are mutually exclusive.");
738			return;
739		}
740	}
741	md.md_iterations = val;
742
743	val = gctl_get_intmax(req, "sectorsize");
744	if (val == 0)
745		md.md_sectorsize = secsize;
746	else {
747		if (val < 0 || (val % secsize) != 0) {
748			gctl_error(req, "Invalid sector size.");
749			return;
750		}
751		if (val > sysconf(_SC_PAGE_SIZE)) {
752			fprintf(stderr,
753			    "warning: Using sectorsize bigger than the page size!\n");
754		}
755		md.md_sectorsize = val;
756	}
757
758	md.md_keys = 0x01;
759	arc4rand(md.md_salt, sizeof(md.md_salt));
760	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
761
762	/* Generate user key. */
763	if (eli_genkey(req, &md, key, true) == NULL) {
764		bzero(key, sizeof(key));
765		bzero(&md, sizeof(md));
766		return;
767	}
768
769	/* Encrypt the first and the only Master Key. */
770	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
771	bzero(key, sizeof(key));
772	if (error != 0) {
773		bzero(&md, sizeof(md));
774		gctl_error(req, "Cannot encrypt Master Key: %s.",
775		    strerror(error));
776		return;
777	}
778
779	eli_metadata_encode(&md, sector);
780	bzero(&md, sizeof(md));
781	error = g_metadata_store(prov, sector, sizeof(sector));
782	bzero(sector, sizeof(sector));
783	if (error != 0) {
784		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
785		    strerror(error));
786		return;
787	}
788	if (verbose)
789		printf("Metadata value stored on %s.\n", prov);
790	/* Backup metadata to a file. */
791	str = gctl_get_ascii(req, "backupfile");
792	if (str[0] != '\0') {
793		/* Backupfile given be the user, just copy it. */
794		strlcpy(backfile, str, sizeof(backfile));
795	} else {
796		/* Generate file name automatically. */
797		const char *p = prov;
798		unsigned int i;
799
800		if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
801			p += sizeof(_PATH_DEV) - 1;
802		snprintf(backfile, sizeof(backfile), "%s%s.eli",
803		    GELI_BACKUP_DIR, p);
804		/* Replace all / with _. */
805		for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
806			if (backfile[i] == '/')
807				backfile[i] = '_';
808		}
809	}
810	if (strcmp(backfile, "none") != 0 &&
811	    eli_backup_create(req, prov, backfile) == 0) {
812		printf("\nMetadata backup can be found in %s and\n", backfile);
813		printf("can be restored with the following command:\n");
814		printf("\n\t# geli restore %s %s\n\n", backfile, prov);
815	}
816}
817
818static void
819eli_attach(struct gctl_req *req)
820{
821	struct g_eli_metadata md;
822	unsigned char key[G_ELI_USERKEYLEN];
823	const char *prov;
824	off_t mediasize;
825	int nargs;
826
827	nargs = gctl_get_int(req, "nargs");
828	if (nargs != 1) {
829		gctl_error(req, "Invalid number of arguments.");
830		return;
831	}
832	prov = gctl_get_ascii(req, "arg0");
833
834	if (eli_metadata_read(req, prov, &md) == -1)
835		return;
836
837	mediasize = g_get_mediasize(prov);
838	if (md.md_provsize != (uint64_t)mediasize) {
839		gctl_error(req, "Provider size mismatch.");
840		return;
841	}
842
843	if (eli_genkey(req, &md, key, false) == NULL) {
844		bzero(key, sizeof(key));
845		return;
846	}
847
848	gctl_ro_param(req, "key", sizeof(key), key);
849	if (gctl_issue(req) == NULL) {
850		if (verbose)
851			printf("Attached to %s.\n", prov);
852	}
853	bzero(key, sizeof(key));
854}
855
856static void
857eli_configure_detached(struct gctl_req *req, const char *prov, bool boot)
858{
859	struct g_eli_metadata md;
860
861	if (eli_metadata_read(req, prov, &md) == -1)
862		return;
863
864	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
865		if (verbose)
866			printf("BOOT flag already configured for %s.\n", prov);
867	} else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) {
868		if (verbose)
869			printf("BOOT flag not configured for %s.\n", prov);
870	} else {
871		if (boot)
872			md.md_flags |= G_ELI_FLAG_BOOT;
873		else
874			md.md_flags &= ~G_ELI_FLAG_BOOT;
875		eli_metadata_store(req, prov, &md);
876	}
877	bzero(&md, sizeof(md));
878}
879
880static void
881eli_configure(struct gctl_req *req)
882{
883	const char *prov;
884	bool boot, noboot;
885	int i, nargs;
886
887	nargs = gctl_get_int(req, "nargs");
888	if (nargs == 0) {
889		gctl_error(req, "Too few arguments.");
890		return;
891	}
892
893	boot = gctl_get_int(req, "boot");
894	noboot = gctl_get_int(req, "noboot");
895
896	if (boot && noboot) {
897		gctl_error(req, "Options -b and -B are mutually exclusive.");
898		return;
899	}
900	if (!boot && !noboot) {
901		gctl_error(req, "No option given.");
902		return;
903	}
904
905	/* First attached providers. */
906	gctl_issue(req);
907	/* Now the rest. */
908	for (i = 0; i < nargs; i++) {
909		prov = gctl_get_ascii(req, "arg%d", i);
910		if (!eli_is_attached(prov))
911			eli_configure_detached(req, prov, boot);
912	}
913}
914
915static void
916eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
917{
918	unsigned char key[G_ELI_USERKEYLEN];
919	intmax_t val, old = 0;
920	int error;
921
922	val = gctl_get_intmax(req, "iterations");
923	/* Check if iterations number should be changed. */
924	if (val != -1)
925		md->md_iterations = val;
926	else
927		old = md->md_iterations;
928
929	/* Generate key for Master Key encryption. */
930	if (eli_genkey(req, md, key, true) == NULL) {
931		bzero(key, sizeof(key));
932		return;
933	}
934	/*
935	 * If number of iterations has changed, but wasn't given as a
936	 * command-line argument, update the request.
937	 */
938	if (val == -1 && md->md_iterations != old) {
939		error = gctl_change_param(req, "iterations", sizeof(intmax_t),
940		    &md->md_iterations);
941		assert(error == 0);
942	}
943
944	gctl_ro_param(req, "key", sizeof(key), key);
945	gctl_issue(req);
946	bzero(key, sizeof(key));
947}
948
949static void
950eli_setkey_detached(struct gctl_req *req, const char *prov,
951 struct g_eli_metadata *md)
952{
953	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
954	unsigned char *mkeydst;
955	unsigned int nkey;
956	intmax_t val;
957	int error;
958
959	if (md->md_keys == 0) {
960		gctl_error(req, "No valid keys on %s.", prov);
961		return;
962	}
963
964	/* Generate key for Master Key decryption. */
965	if (eli_genkey(req, md, key, false) == NULL) {
966		bzero(key, sizeof(key));
967		return;
968	}
969
970	/* Decrypt Master Key. */
971	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
972	bzero(key, sizeof(key));
973	if (error != 0) {
974		bzero(md, sizeof(*md));
975		if (error == -1)
976			gctl_error(req, "Wrong key for %s.", prov);
977		else /* if (error > 0) */ {
978			gctl_error(req, "Cannot decrypt Master Key: %s.",
979			    strerror(error));
980		}
981		return;
982	}
983	if (verbose)
984		printf("Decrypted Master Key %u.\n", nkey);
985
986	val = gctl_get_intmax(req, "keyno");
987	if (val != -1)
988		nkey = val;
989#if 0
990	else
991		; /* Use the key number which was found during decryption. */
992#endif
993	if (nkey >= G_ELI_MAXMKEYS) {
994		gctl_error(req, "Invalid '%s' argument.", "keyno");
995		return;
996	}
997
998	val = gctl_get_intmax(req, "iterations");
999	/* Check if iterations number should and can be changed. */
1000	if (val != -1) {
1001		if (bitcount32(md->md_keys) != 1) {
1002			gctl_error(req, "To be able to use '-i' option, only "
1003			    "one key can be defined.");
1004			return;
1005		}
1006		if (md->md_keys != (1 << nkey)) {
1007			gctl_error(req, "Only already defined key can be "
1008			    "changed when '-i' option is used.");
1009			return;
1010		}
1011		md->md_iterations = val;
1012	}
1013
1014	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
1015	md->md_keys |= (1 << nkey);
1016
1017	bcopy(mkey, mkeydst, sizeof(mkey));
1018	bzero(mkey, sizeof(mkey));
1019
1020	/* Generate key for Master Key encryption. */
1021	if (eli_genkey(req, md, key, true) == NULL) {
1022		bzero(key, sizeof(key));
1023		bzero(md, sizeof(*md));
1024		return;
1025	}
1026
1027	/* Encrypt the Master-Key with the new key. */
1028	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
1029	bzero(key, sizeof(key));
1030	if (error != 0) {
1031		bzero(md, sizeof(*md));
1032		gctl_error(req, "Cannot encrypt Master Key: %s.",
1033		    strerror(error));
1034		return;
1035	}
1036
1037	/* Store metadata with fresh key. */
1038	eli_metadata_store(req, prov, md);
1039	bzero(md, sizeof(*md));
1040}
1041
1042static void
1043eli_setkey(struct gctl_req *req)
1044{
1045	struct g_eli_metadata md;
1046	const char *prov;
1047	int nargs;
1048
1049	nargs = gctl_get_int(req, "nargs");
1050	if (nargs != 1) {
1051		gctl_error(req, "Invalid number of arguments.");
1052		return;
1053	}
1054	prov = gctl_get_ascii(req, "arg0");
1055
1056	if (eli_metadata_read(req, prov, &md) == -1)
1057		return;
1058
1059	if (eli_is_attached(prov))
1060		eli_setkey_attached(req, &md);
1061	else
1062		eli_setkey_detached(req, prov, &md);
1063
1064	if (req->error == NULL || req->error[0] == '\0') {
1065		printf("Note, that the master key encrypted with old keys "
1066		    "and/or passphrase may still exists in a metadata backup "
1067		    "file.\n");
1068	}
1069}
1070
1071static void
1072eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
1073{
1074
1075	gctl_issue(req);
1076}
1077
1078static void
1079eli_delkey_detached(struct gctl_req *req, const char *prov)
1080{
1081	struct g_eli_metadata md;
1082	unsigned char *mkeydst;
1083	unsigned int nkey;
1084	intmax_t val;
1085	bool all, force;
1086
1087	if (eli_metadata_read(req, prov, &md) == -1)
1088		return;
1089
1090	all = gctl_get_int(req, "all");
1091	if (all)
1092		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
1093	else {
1094		force = gctl_get_int(req, "force");
1095		val = gctl_get_intmax(req, "keyno");
1096		if (val == -1) {
1097			gctl_error(req, "Key number has to be specified.");
1098			return;
1099		}
1100		nkey = val;
1101		if (nkey >= G_ELI_MAXMKEYS) {
1102			gctl_error(req, "Invalid '%s' argument.", "keyno");
1103			return;
1104		}
1105		if (!(md.md_keys & (1 << nkey)) && !force) {
1106			gctl_error(req, "Master Key %u is not set.", nkey);
1107			return;
1108		}
1109		md.md_keys &= ~(1 << nkey);
1110		if (md.md_keys == 0 && !force) {
1111			gctl_error(req, "This is the last Master Key. Use '-f' "
1112			    "option if you really want to remove it.");
1113			return;
1114		}
1115		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
1116		arc4rand(mkeydst, G_ELI_MKEYLEN);
1117	}
1118
1119	eli_metadata_store(req, prov, &md);
1120	bzero(&md, sizeof(md));
1121}
1122
1123static void
1124eli_delkey(struct gctl_req *req)
1125{
1126	const char *prov;
1127	int nargs;
1128
1129	nargs = gctl_get_int(req, "nargs");
1130	if (nargs != 1) {
1131		gctl_error(req, "Invalid number of arguments.");
1132		return;
1133	}
1134	prov = gctl_get_ascii(req, "arg0");
1135
1136	if (eli_is_attached(prov))
1137		eli_delkey_attached(req, prov);
1138	else
1139		eli_delkey_detached(req, prov);
1140}
1141
1142static void
1143eli_resume(struct gctl_req *req)
1144{
1145	struct g_eli_metadata md;
1146	unsigned char key[G_ELI_USERKEYLEN];
1147	const char *prov;
1148	off_t mediasize;
1149	int nargs;
1150
1151	nargs = gctl_get_int(req, "nargs");
1152	if (nargs != 1) {
1153		gctl_error(req, "Invalid number of arguments.");
1154		return;
1155	}
1156	prov = gctl_get_ascii(req, "arg0");
1157
1158	if (eli_metadata_read(req, prov, &md) == -1)
1159		return;
1160
1161	mediasize = g_get_mediasize(prov);
1162	if (md.md_provsize != (uint64_t)mediasize) {
1163		gctl_error(req, "Provider size mismatch.");
1164		return;
1165	}
1166
1167	if (eli_genkey(req, &md, key, false) == NULL) {
1168		bzero(key, sizeof(key));
1169		return;
1170	}
1171
1172	gctl_ro_param(req, "key", sizeof(key), key);
1173	if (gctl_issue(req) == NULL) {
1174		if (verbose)
1175			printf("Resumed %s.\n", prov);
1176	}
1177	bzero(key, sizeof(key));
1178}
1179
1180static int
1181eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset)
1182{
1183	unsigned int overwrites;
1184	unsigned char *sector;
1185	ssize_t size;
1186	int error;
1187
1188	size = sizeof(overwrites);
1189	if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size,
1190	    NULL, 0) == -1 || overwrites == 0) {
1191		overwrites = G_ELI_OVERWRITES;
1192	}
1193
1194	size = g_sectorsize(fd);
1195	if (size <= 0) {
1196		gctl_error(req, "Cannot obtain provider sector size %s: %s.",
1197		    prov, strerror(errno));
1198		return (-1);
1199	}
1200	sector = malloc(size);
1201	if (sector == NULL) {
1202		gctl_error(req, "Cannot allocate %zd bytes of memory.", size);
1203		return (-1);
1204	}
1205
1206	error = 0;
1207	do {
1208		arc4rand(sector, size);
1209		if (pwrite(fd, sector, size, offset) != size) {
1210			if (error == 0)
1211				error = errno;
1212		}
1213		(void)g_flush(fd);
1214	} while (--overwrites > 0);
1215	if (error != 0) {
1216		gctl_error(req, "Cannot trash metadata on provider %s: %s.",
1217		    prov, strerror(error));
1218		return (-1);
1219	}
1220	return (0);
1221}
1222
1223static void
1224eli_kill_detached(struct gctl_req *req, const char *prov)
1225{
1226	off_t offset;
1227	int fd;
1228
1229	/*
1230	 * NOTE: Maybe we should verify if this is geli provider first,
1231	 *       but 'kill' command is quite critical so better don't waste
1232	 *       the time.
1233	 */
1234#if 0
1235	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
1236	    G_ELI_MAGIC);
1237	if (error != 0) {
1238		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
1239		    strerror(error));
1240		return;
1241	}
1242#endif
1243
1244	fd = g_open(prov, 1);
1245	if (fd == -1) {
1246		gctl_error(req, "Cannot open provider %s: %s.", prov,
1247		    strerror(errno));
1248		return;
1249	}
1250	offset = g_mediasize(fd) - g_sectorsize(fd);
1251	if (offset <= 0) {
1252		gctl_error(req,
1253		    "Cannot obtain media size or sector size for provider %s: %s.",
1254		    prov, strerror(errno));
1255		(void)g_close(fd);
1256		return;
1257	}
1258	(void)eli_trash_metadata(req, prov, fd, offset);
1259	(void)g_close(fd);
1260}
1261
1262static void
1263eli_kill(struct gctl_req *req)
1264{
1265	const char *prov;
1266	int i, nargs, all;
1267
1268	nargs = gctl_get_int(req, "nargs");
1269	all = gctl_get_int(req, "all");
1270	if (!all && nargs == 0) {
1271		gctl_error(req, "Too few arguments.");
1272		return;
1273	}
1274	/*
1275	 * How '-a' option combine with a list of providers:
1276	 * Delete Master Keys from all attached providers:
1277	 * geli kill -a
1278	 * Delete Master Keys from all attached providers and from
1279	 * detached da0 and da1:
1280	 * geli kill -a da0 da1
1281	 * Delete Master Keys from (attached or detached) da0 and da1:
1282	 * geli kill da0 da1
1283	 */
1284
1285	/* First detached providers. */
1286	for (i = 0; i < nargs; i++) {
1287		prov = gctl_get_ascii(req, "arg%d", i);
1288		if (!eli_is_attached(prov))
1289			eli_kill_detached(req, prov);
1290	}
1291	/* Now attached providers. */
1292	gctl_issue(req);
1293}
1294
1295static int
1296eli_backup_create(struct gctl_req *req, const char *prov, const char *file)
1297{
1298	struct g_eli_metadata md;
1299	unsigned char *sector;
1300	ssize_t secsize;
1301	off_t mediasize;
1302	int filefd, provfd, ret;
1303
1304	ret = -1;
1305	provfd = filefd = -1;
1306	sector = NULL;
1307	secsize = 0;
1308
1309	provfd = g_open(prov, 0);
1310	if (provfd == -1) {
1311		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1312		goto out;
1313	}
1314	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1315	if (filefd == -1) {
1316		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1317		goto out;
1318	}
1319
1320	mediasize = g_mediasize(provfd);
1321	secsize = g_sectorsize(provfd);
1322	if (mediasize == -1 || secsize == -1) {
1323		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1324		    strerror(errno));
1325		goto out;
1326	}
1327
1328	sector = malloc(secsize);
1329	if (sector == NULL) {
1330		gctl_error(req, "Cannot allocate memory.");
1331		goto out;
1332	}
1333
1334	/* Read metadata from the provider. */
1335	if (pread(provfd, sector, secsize, mediasize - secsize) != secsize) {
1336		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
1337		goto out;
1338	}
1339	/* Check if this is geli provider. */
1340	if (eli_metadata_decode(sector, &md) != 0) {
1341		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1342		goto out;
1343	}
1344	/* Write metadata to the destination file. */
1345	if (write(filefd, sector, secsize) != secsize) {
1346		gctl_error(req, "Cannot write to %s: %s.", file,
1347		    strerror(errno));
1348		goto out;
1349	}
1350	(void)fsync(filefd);
1351	/* Success. */
1352	ret = 0;
1353out:
1354	if (provfd >= 0)
1355		(void)g_close(provfd);
1356	if (filefd >= 0)
1357		(void)close(filefd);
1358	if (sector != NULL) {
1359		bzero(sector, secsize);
1360		free(sector);
1361	}
1362	return (ret);
1363}
1364
1365static void
1366eli_backup(struct gctl_req *req)
1367{
1368	const char *file, *prov;
1369	int nargs;
1370
1371	nargs = gctl_get_int(req, "nargs");
1372	if (nargs != 2) {
1373		gctl_error(req, "Invalid number of arguments.");
1374		return;
1375	}
1376	prov = gctl_get_ascii(req, "arg0");
1377	file = gctl_get_ascii(req, "arg1");
1378
1379	eli_backup_create(req, prov, file);
1380}
1381
1382static void
1383eli_restore(struct gctl_req *req)
1384{
1385	struct g_eli_metadata md;
1386	const char *file, *prov;
1387	unsigned char *sector;
1388	ssize_t secsize;
1389	off_t mediasize;
1390	int nargs, filefd, provfd;
1391
1392	nargs = gctl_get_int(req, "nargs");
1393	if (nargs != 2) {
1394		gctl_error(req, "Invalid number of arguments.");
1395		return;
1396	}
1397	file = gctl_get_ascii(req, "arg0");
1398	prov = gctl_get_ascii(req, "arg1");
1399
1400	provfd = filefd = -1;
1401	sector = NULL;
1402	secsize = 0;
1403
1404	filefd = open(file, O_RDONLY);
1405	if (filefd == -1) {
1406		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1407		goto out;
1408	}
1409	provfd = g_open(prov, 1);
1410	if (provfd == -1) {
1411		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1412		goto out;
1413	}
1414
1415	mediasize = g_mediasize(provfd);
1416	secsize = g_sectorsize(provfd);
1417	if (mediasize == -1 || secsize == -1) {
1418		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1419		    strerror(errno));
1420		goto out;
1421	}
1422
1423	sector = malloc(secsize);
1424	if (sector == NULL) {
1425		gctl_error(req, "Cannot allocate memory.");
1426		goto out;
1427	}
1428
1429	/* Read metadata from the backup file. */
1430	if (read(filefd, sector, secsize) != secsize) {
1431		gctl_error(req, "Cannot read from %s: %s.", file,
1432		    strerror(errno));
1433		goto out;
1434	}
1435	/* Check if this file contains geli metadata. */
1436	if (eli_metadata_decode(sector, &md) != 0) {
1437		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1438		goto out;
1439	}
1440	/* Check if the provider size has changed since we did the backup. */
1441	if (md.md_provsize != (uint64_t)mediasize) {
1442		if (gctl_get_int(req, "force")) {
1443			md.md_provsize = mediasize;
1444			eli_metadata_encode(&md, sector);
1445		} else {
1446			gctl_error(req, "Provider size mismatch: "
1447			    "wrong backup file?");
1448			goto out;
1449		}
1450	}
1451	/* Write metadata from the provider. */
1452	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
1453		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1454		goto out;
1455	}
1456	(void)g_flush(provfd);
1457out:
1458	if (provfd >= 0)
1459		(void)g_close(provfd);
1460	if (filefd >= 0)
1461		(void)close(filefd);
1462	if (sector != NULL) {
1463		bzero(sector, secsize);
1464		free(sector);
1465	}
1466}
1467
1468static void
1469eli_resize(struct gctl_req *req)
1470{
1471	struct g_eli_metadata md;
1472	const char *prov;
1473	unsigned char *sector;
1474	ssize_t secsize;
1475	off_t mediasize, oldsize;
1476	int nargs, provfd;
1477
1478	nargs = gctl_get_int(req, "nargs");
1479	if (nargs != 1) {
1480		gctl_error(req, "Invalid number of arguments.");
1481		return;
1482	}
1483	prov = gctl_get_ascii(req, "arg0");
1484
1485	provfd = -1;
1486	sector = NULL;
1487	secsize = 0;
1488
1489	provfd = g_open(prov, 1);
1490	if (provfd == -1) {
1491		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1492		goto out;
1493	}
1494
1495	mediasize = g_mediasize(provfd);
1496	secsize = g_sectorsize(provfd);
1497	if (mediasize == -1 || secsize == -1) {
1498		gctl_error(req, "Cannot get information about %s: %s.", prov,
1499		    strerror(errno));
1500		goto out;
1501	}
1502
1503	sector = malloc(secsize);
1504	if (sector == NULL) {
1505		gctl_error(req, "Cannot allocate memory.");
1506		goto out;
1507	}
1508
1509	oldsize = gctl_get_intmax(req, "oldsize");
1510	if (oldsize < 0 || oldsize > mediasize) {
1511		gctl_error(req, "Invalid oldsize: Out of range.");
1512		goto out;
1513	}
1514	if (oldsize == mediasize) {
1515		gctl_error(req, "Size hasn't changed.");
1516		goto out;
1517	}
1518
1519	/* Read metadata from the 'oldsize' offset. */
1520	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
1521		gctl_error(req, "Cannot read old metadata: %s.",
1522		    strerror(errno));
1523		goto out;
1524	}
1525
1526	/* Check if this sector contains geli metadata. */
1527	if (eli_metadata_decode(sector, &md) != 0) {
1528		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
1529		goto out;
1530	}
1531
1532	/*
1533	 * If the old metadata doesn't have a correct provider size, refuse
1534	 * to resize.
1535	 */
1536	if (md.md_provsize != (uint64_t)oldsize) {
1537		gctl_error(req, "Provider size mismatch at oldsize.");
1538		goto out;
1539	}
1540
1541	/*
1542	 * Update the old metadata with the current provider size and write
1543	 * it back to the correct place on the provider.
1544	 */
1545	md.md_provsize = mediasize;
1546	eli_metadata_encode(&md, sector);
1547	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
1548		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1549		goto out;
1550	}
1551	(void)g_flush(provfd);
1552
1553	/* Now trash the old metadata. */
1554	if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
1555		goto out;
1556out:
1557	if (provfd >= 0)
1558		(void)g_close(provfd);
1559	if (sector != NULL) {
1560		bzero(sector, secsize);
1561		free(sector);
1562	}
1563}
1564
1565static void
1566eli_clear(struct gctl_req *req)
1567{
1568	const char *name;
1569	int error, i, nargs;
1570
1571	nargs = gctl_get_int(req, "nargs");
1572	if (nargs < 1) {
1573		gctl_error(req, "Too few arguments.");
1574		return;
1575	}
1576
1577	for (i = 0; i < nargs; i++) {
1578		name = gctl_get_ascii(req, "arg%d", i);
1579		error = g_metadata_clear(name, G_ELI_MAGIC);
1580		if (error != 0) {
1581			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1582			    name, strerror(error));
1583			gctl_error(req, "Not fully done.");
1584			continue;
1585		}
1586		if (verbose)
1587			printf("Metadata cleared on %s.\n", name);
1588	}
1589}
1590
1591static void
1592eli_dump(struct gctl_req *req)
1593{
1594	struct g_eli_metadata md, tmpmd;
1595	const char *name;
1596	int error, i, nargs;
1597
1598	nargs = gctl_get_int(req, "nargs");
1599	if (nargs < 1) {
1600		gctl_error(req, "Too few arguments.");
1601		return;
1602	}
1603
1604	for (i = 0; i < nargs; i++) {
1605		name = gctl_get_ascii(req, "arg%d", i);
1606		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1607		    sizeof(tmpmd), G_ELI_MAGIC);
1608		if (error != 0) {
1609			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1610			    name, strerror(error));
1611			gctl_error(req, "Not fully done.");
1612			continue;
1613		}
1614		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1615			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1616			    name);
1617			gctl_error(req, "Not fully done.");
1618			continue;
1619		}
1620		printf("Metadata on %s:\n", name);
1621		eli_metadata_dump(&md);
1622		printf("\n");
1623	}
1624}
1625