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