geom_eli.c revision 166892
1169689Skan/*-
2169689Skan * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3169689Skan * All rights reserved.
4169689Skan *
5169689Skan * Redistribution and use in source and binary forms, with or without
6169689Skan * modification, are permitted provided that the following conditions
7169689Skan * are met:
8169689Skan * 1. Redistributions of source code must retain the above copyright
9169689Skan *    notice, this list of conditions and the following disclaimer.
10169689Skan * 2. Redistributions in binary form must reproduce the above copyright
11169689Skan *    notice, this list of conditions and the following disclaimer in the
12169689Skan *    documentation and/or other materials provided with the distribution.
13169689Skan *
14169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24169689Skan * SUCH DAMAGE.
25169689Skan */
26169689Skan
27169689Skan#include <sys/cdefs.h>
28169689Skan__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 166892 2007-02-22 19:25:37Z pjd $");
29169689Skan
30169689Skan#include <stdio.h>
31169689Skan#include <stdint.h>
32169689Skan#include <stdlib.h>
33169689Skan#include <unistd.h>
34169689Skan#include <fcntl.h>
35169689Skan#include <readpassphrase.h>
36169689Skan#include <string.h>
37169689Skan#include <strings.h>
38169689Skan#include <libgeom.h>
39169689Skan#include <paths.h>
40169689Skan#include <errno.h>
41169689Skan#include <assert.h>
42169689Skan
43169689Skan#include <sys/param.h>
44169689Skan#include <sys/mman.h>
45169689Skan#include <sys/resource.h>
46169689Skan#include <opencrypto/cryptodev.h>
47169689Skan#include <geom/eli/g_eli.h>
48169689Skan#include <geom/eli/pkcs5v2.h>
49169689Skan
50169689Skan#include "core/geom.h"
51169689Skan#include "misc/subr.h"
52169689Skan
53169689Skan
54169689Skanuint32_t lib_version = G_LIB_VERSION;
55169689Skanuint32_t version = G_ELI_VERSION;
56169689Skan
57169689Skanstatic char aalgo[] = "none";
58169689Skanstatic char ealgo[] = "aes";
59169689Skanstatic intmax_t keylen = 0;
60169689Skanstatic intmax_t keyno = -1;
61169689Skanstatic intmax_t iterations = -1;
62169689Skanstatic intmax_t sectorsize = 0;
63169689Skanstatic char keyfile[] = "", newkeyfile[] = "";
64169689Skan
65169689Skanstatic void eli_main(struct gctl_req *req, unsigned flags);
66169689Skanstatic void eli_init(struct gctl_req *req);
67169689Skanstatic void eli_attach(struct gctl_req *req);
68169689Skanstatic void eli_configure(struct gctl_req *req);
69169689Skanstatic void eli_setkey(struct gctl_req *req);
70169689Skanstatic void eli_delkey(struct gctl_req *req);
71169689Skanstatic void eli_kill(struct gctl_req *req);
72169689Skanstatic void eli_backup(struct gctl_req *req);
73169689Skanstatic void eli_restore(struct gctl_req *req);
74169689Skanstatic void eli_clear(struct gctl_req *req);
75169689Skanstatic void eli_dump(struct gctl_req *req);
76169689Skan
77169689Skan/*
78169689Skan * Available commands:
79169689Skan *
80169689Skan * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
81169689Skan * label - alias for 'init'
82169689Skan * attach [-dprv] [-k keyfile] prov
83169689Skan * detach [-fl] prov ...
84169689Skan * stop - alias for 'detach'
85169689Skan * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
86169689Skan * configure [-bB] prov ...
87169689Skan * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
88169689Skan * delkey [-afv] [-n keyno] prov
89169689Skan * kill [-av] [prov ...]
90169689Skan * backup [-v] prov file
91169689Skan * restore [-v] file prov
92169689Skan * clear [-v] prov ...
93169689Skan * dump [-v] prov ...
94169689Skan */
95169689Skanstruct g_command class_commands[] = {
96169689Skan	{ "init", G_FLAG_VERBOSE, eli_main,
97169689Skan	    {
98169689Skan		{ 'a', "aalgo", aalgo, G_TYPE_STRING },
99169689Skan		{ 'b', "boot", NULL, G_TYPE_BOOL },
100169689Skan		{ 'e', "ealgo", ealgo, G_TYPE_STRING },
101169689Skan		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
102169689Skan		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
103169689Skan		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
104169689Skan		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
105169689Skan		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
106169689Skan		G_OPT_SENTINEL
107169689Skan	    },
108169689Skan	    "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
109169689Skan	},
110169689Skan	{ "label", G_FLAG_VERBOSE, eli_main,
111169689Skan	    {
112169689Skan		{ 'a', "aalgo", aalgo, G_TYPE_STRING },
113169689Skan		{ 'b', "boot", NULL, G_TYPE_BOOL },
114169689Skan		{ 'e', "ealgo", ealgo, G_TYPE_STRING },
115169689Skan		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
116169689Skan		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
117169689Skan		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
118169689Skan		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
119169689Skan		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
120169689Skan		G_OPT_SENTINEL
121169689Skan	    },
122169689Skan	    "- an alias for 'init'"
123169689Skan	},
124169689Skan	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
125169689Skan	    {
126169689Skan		{ 'd', "detach", NULL, G_TYPE_BOOL },
127169689Skan		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
128169689Skan		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
129169689Skan		{ 'r', "readonly", NULL, G_TYPE_BOOL },
130169689Skan		G_OPT_SENTINEL
131169689Skan	    },
132169689Skan	    "[-dprv] [-k keyfile] prov"
133169689Skan	},
134169689Skan	{ "detach", 0, NULL,
135169689Skan	    {
136169689Skan		{ 'f', "force", NULL, G_TYPE_BOOL },
137169689Skan		{ 'l', "last", NULL, G_TYPE_BOOL },
138169689Skan		G_OPT_SENTINEL
139169689Skan	    },
140169689Skan	    "[-fl] prov ..."
141169689Skan	},
142169689Skan	{ "stop", 0, NULL,
143169689Skan	    {
144169689Skan		{ 'f', "force", NULL, G_TYPE_BOOL },
145169689Skan		{ 'l', "last", NULL, G_TYPE_BOOL },
146169689Skan		G_OPT_SENTINEL
147169689Skan	    },
148169689Skan	    "- an alias for 'detach'"
149169689Skan	},
150169689Skan	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
151169689Skan	    {
152169689Skan		{ 'a', "aalgo", aalgo, G_TYPE_STRING },
153169689Skan		{ 'd', "detach", NULL, G_TYPE_BOOL },
154169689Skan		{ 'e', "ealgo", ealgo, G_TYPE_STRING },
155169689Skan		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
156169689Skan		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
157169689Skan		G_OPT_SENTINEL
158169689Skan	    },
159169689Skan	    "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..."
160169689Skan	},
161169689Skan	{ "configure", G_FLAG_VERBOSE, eli_main,
162169689Skan	    {
163169689Skan		{ 'b', "boot", NULL, G_TYPE_BOOL },
164169689Skan		{ 'B', "noboot", NULL, G_TYPE_BOOL },
165169689Skan		G_OPT_SENTINEL
166169689Skan	    },
167169689Skan	    "[-bB] prov ..."
168169689Skan	},
169169689Skan	{ "setkey", G_FLAG_VERBOSE, eli_main,
170169689Skan	    {
171169689Skan		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
172169689Skan		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
173169689Skan		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
174169689Skan		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
175169689Skan		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
176169689Skan		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
177169689Skan		G_OPT_SENTINEL
178169689Skan	    },
179169689Skan	    "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
180169689Skan	},
181169689Skan	{ "delkey", G_FLAG_VERBOSE, eli_main,
182169689Skan	    {
183169689Skan		{ 'a', "all", NULL, G_TYPE_BOOL },
184169689Skan		{ 'f', "force", NULL, G_TYPE_BOOL },
185169689Skan		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
186169689Skan		G_OPT_SENTINEL
187169689Skan	    },
188169689Skan	    "[-afv] [-n keyno] prov"
189169689Skan	},
190169689Skan	{ "kill", G_FLAG_VERBOSE, eli_main,
191169689Skan	    {
192169689Skan		{ 'a', "all", NULL, G_TYPE_BOOL },
193169689Skan		G_OPT_SENTINEL
194169689Skan	    },
195169689Skan	    "[-av] [prov ...]"
196169689Skan	},
197169689Skan	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
198169689Skan	    "[-v] prov file"
199169689Skan	},
200169689Skan	{ "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
201169689Skan	    "[-v] file prov"
202169689Skan	},
203169689Skan	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
204169689Skan	    "[-v] prov ..."
205169689Skan	},
206169689Skan	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
207169689Skan	    "[-v] prov ..."
208169689Skan	},
209169689Skan	G_CMD_SENTINEL
210169689Skan};
211169689Skan
212169689Skanstatic int verbose = 0;
213169689Skan
214169689Skanstatic int
215169689Skaneli_protect(struct gctl_req *req)
216169689Skan{
217169689Skan	struct rlimit rl;
218169689Skan
219169689Skan	/* Disable core dumps. */
220169689Skan	rl.rlim_cur = 0;
221169689Skan	rl.rlim_max = 0;
222169689Skan	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
223169689Skan		gctl_error(req, "Cannot disable core dumps: %s.",
224169689Skan		    strerror(errno));
225169689Skan		return (-1);
226169689Skan	}
227169689Skan	/* Disable swapping. */
228169689Skan	if (mlockall(MCL_FUTURE) == -1) {
229169689Skan		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
230169689Skan		return (-1);
231169689Skan	}
232169689Skan	return (0);
233169689Skan}
234169689Skan
235169689Skanstatic void
236169689Skaneli_main(struct gctl_req *req, unsigned flags)
237169689Skan{
238169689Skan	const char *name;
239169689Skan
240169689Skan	if (eli_protect(req) == -1)
241169689Skan		return;
242169689Skan
243169689Skan	if ((flags & G_FLAG_VERBOSE) != 0)
244169689Skan		verbose = 1;
245169689Skan
246169689Skan	name = gctl_get_ascii(req, "verb");
247169689Skan	if (name == NULL) {
248169689Skan		gctl_error(req, "No '%s' argument.", "verb");
249169689Skan		return;
250169689Skan	}
251169689Skan	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
252169689Skan		eli_init(req);
253169689Skan	else if (strcmp(name, "attach") == 0)
254169689Skan		eli_attach(req);
255169689Skan	else if (strcmp(name, "configure") == 0)
256169689Skan		eli_configure(req);
257169689Skan	else if (strcmp(name, "setkey") == 0)
258169689Skan		eli_setkey(req);
259169689Skan	else if (strcmp(name, "delkey") == 0)
260169689Skan		eli_delkey(req);
261169689Skan	else if (strcmp(name, "kill") == 0)
262169689Skan		eli_kill(req);
263169689Skan	else if (strcmp(name, "backup") == 0)
264169689Skan		eli_backup(req);
265169689Skan	else if (strcmp(name, "restore") == 0)
266169689Skan		eli_restore(req);
267169689Skan	else if (strcmp(name, "dump") == 0)
268169689Skan		eli_dump(req);
269169689Skan	else if (strcmp(name, "clear") == 0)
270169689Skan		eli_clear(req);
271169689Skan	else
272169689Skan		gctl_error(req, "Unknown command: %s.", name);
273169689Skan}
274169689Skan
275169689Skanstatic void
276169689Skanarc4rand(unsigned char *buf, size_t size)
277169689Skan{
278169689Skan	uint32_t *buf4;
279169689Skan	size_t size4;
280169689Skan	unsigned i;
281169689Skan
282169689Skan	buf4 = (uint32_t *)buf;
283169689Skan	size4 = size / 4;
284169689Skan
285169689Skan	for (i = 0; i < size4; i++)
286169689Skan		buf4[i] = arc4random();
287169689Skan	for (i *= 4; i < size; i++)
288169689Skan		buf[i] = arc4random() % 0xff;
289169689Skan}
290169689Skan
291169689Skanstatic int
292169689Skaneli_is_attached(const char *prov)
293169689Skan{
294169689Skan	char name[MAXPATHLEN];
295169689Skan	unsigned secsize;
296169689Skan
297169689Skan	/*
298169689Skan	 * Not the best way to do it, but the easiest.
299169689Skan	 * We try to open provider and check if it is a GEOM provider
300169689Skan	 * by asking about its sectorsize.
301169689Skan	 */
302169689Skan	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
303169689Skan	secsize = g_get_sectorsize(name);
304169689Skan	if (secsize > 0)
305169689Skan		return (1);
306169689Skan	return (0);
307169689Skan}
308169689Skan
309169689Skanstatic unsigned char *
310169689Skaneli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
311169689Skan    int new)
312169689Skan{
313169689Skan	struct hmac_ctx ctx;
314169689Skan	const char *str;
315169689Skan	int error, nopassphrase;
316169689Skan
317169689Skan	nopassphrase =
318169689Skan	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
319169689Skan
320169689Skan	g_eli_crypto_hmac_init(&ctx, NULL, 0);
321169689Skan
322169689Skan	str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
323169689Skan	if (str[0] == '\0' && nopassphrase) {
324169689Skan		gctl_error(req, "No key components given.");
325169689Skan		return (NULL);
326169689Skan	} else if (str[0] != '\0') {
327169689Skan		char buf[MAXPHYS];
328169689Skan		ssize_t done;
329169689Skan		int fd;
330169689Skan
331169689Skan		if (strcmp(str, "-") == 0)
332169689Skan			fd = STDIN_FILENO;
333169689Skan		else {
334169689Skan			fd = open(str, O_RDONLY);
335169689Skan			if (fd == -1) {
336169689Skan				gctl_error(req, "Cannot open keyfile %s: %s.",
337169689Skan				    str, strerror(errno));
338169689Skan				return (NULL);
339169689Skan			}
340169689Skan		}
341169689Skan		while ((done = read(fd, buf, sizeof(buf))) > 0)
342169689Skan			g_eli_crypto_hmac_update(&ctx, buf, done);
343169689Skan		error = errno;
344169689Skan		if (strcmp(str, "-") != 0)
345169689Skan			close(fd);
346169689Skan		bzero(buf, sizeof(buf));
347169689Skan		if (done == -1) {
348169689Skan			gctl_error(req, "Cannot read keyfile %s: %s.", str,
349169689Skan			    strerror(error));
350169689Skan			return (NULL);
351169689Skan		}
352169689Skan	}
353169689Skan
354169689Skan	if (!nopassphrase) {
355169689Skan		char buf1[BUFSIZ], buf2[BUFSIZ], *p;
356169689Skan
357169689Skan		if (!new && md->md_iterations == -1) {
358169689Skan			gctl_error(req, "Missing -p flag.");
359169689Skan			return (NULL);
360169689Skan		}
361169689Skan		for (;;) {
362169689Skan			p = readpassphrase(
363169689Skan			    new ? "Enter new passphrase:" : "Enter passphrase:",
364169689Skan			    buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
365169689Skan			if (p == NULL) {
366169689Skan				bzero(buf1, sizeof(buf1));
367169689Skan				gctl_error(req, "Cannot read passphrase: %s.",
368169689Skan				    strerror(errno));
369169689Skan				return (NULL);
370169689Skan			}
371169689Skan
372169689Skan			if (new) {
373169689Skan				p = readpassphrase("Reenter new passphrase: ",
374169689Skan				    buf2, sizeof(buf2),
375169689Skan				    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
376169689Skan				if (p == NULL) {
377169689Skan					bzero(buf1, sizeof(buf1));
378169689Skan					gctl_error(req,
379169689Skan					    "Cannot read passphrase: %s.",
380169689Skan					    strerror(errno));
381169689Skan					return (NULL);
382169689Skan				}
383169689Skan
384169689Skan				if (strcmp(buf1, buf2) != 0) {
385169689Skan					bzero(buf2, sizeof(buf2));
386169689Skan					fprintf(stderr, "They didn't match.\n");
387169689Skan					continue;
388169689Skan				}
389169689Skan				bzero(buf2, sizeof(buf2));
390169689Skan			}
391169689Skan			break;
392169689Skan		}
393169689Skan		/*
394169689Skan		 * Field md_iterations equal to -1 means "choose some sane
395169689Skan		 * value for me".
396169689Skan		 */
397169689Skan		if (md->md_iterations == -1) {
398169689Skan			assert(new);
399169689Skan			if (verbose)
400169689Skan				printf("Calculating number of iterations...\n");
401169689Skan			md->md_iterations = pkcs5v2_calculate(2000000);
402169689Skan			assert(md->md_iterations > 0);
403169689Skan			if (verbose) {
404169689Skan				printf("Done, using %d iterations.\n",
405169689Skan				    md->md_iterations);
406169689Skan			}
407169689Skan		}
408169689Skan		/*
409169689Skan		 * If md_iterations is equal to 0, user don't want PKCS#5v2.
410169689Skan		 */
411169689Skan		if (md->md_iterations == 0) {
412169689Skan			g_eli_crypto_hmac_update(&ctx, md->md_salt,
413169689Skan			    sizeof(md->md_salt));
414169689Skan			g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
415169689Skan		} else /* if (md->md_iterations > 0) */ {
416169689Skan			unsigned char dkey[G_ELI_USERKEYLEN];
417169689Skan
418169689Skan			pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
419169689Skan			    sizeof(md->md_salt), buf1, md->md_iterations);
420169689Skan			g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
421169689Skan			bzero(dkey, sizeof(dkey));
422169689Skan		}
423169689Skan		bzero(buf1, sizeof(buf1));
424169689Skan	}
425169689Skan	g_eli_crypto_hmac_final(&ctx, key, 0);
426169689Skan	return (key);
427169689Skan}
428169689Skan
429169689Skanstatic int
430169689Skaneli_metadata_read(struct gctl_req *req, const char *prov,
431169689Skan    struct g_eli_metadata *md)
432169689Skan{
433169689Skan	unsigned char sector[sizeof(struct g_eli_metadata)];
434169689Skan	int error;
435169689Skan
436169689Skan	if (g_get_sectorsize(prov) == 0) {
437169689Skan		int fd;
438169689Skan
439169689Skan		/* This is a file probably. */
440169689Skan		fd = open(prov, O_RDONLY);
441169689Skan		if (fd == -1) {
442169689Skan			gctl_error(req, "Cannot open %s: %s.", prov,
443169689Skan			    strerror(errno));
444169689Skan			return (-1);
445169689Skan		}
446169689Skan		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
447169689Skan			gctl_error(req, "Cannot read metadata from %s: %s.",
448169689Skan			    prov, strerror(errno));
449169689Skan			close(fd);
450169689Skan			return (-1);
451169689Skan		}
452169689Skan		close(fd);
453169689Skan	} else {
454169689Skan		/* This is a GEOM provider. */
455169689Skan		error = g_metadata_read(prov, sector, sizeof(sector),
456169689Skan		    G_ELI_MAGIC);
457169689Skan		if (error != 0) {
458169689Skan			gctl_error(req, "Cannot read metadata from %s: %s.",
459169689Skan			    prov, strerror(error));
460169689Skan			return (-1);
461169689Skan		}
462169689Skan	}
463169689Skan	if (eli_metadata_decode(sector, md) != 0) {
464169689Skan		gctl_error(req, "MD5 hash mismatch for %s.", prov);
465169689Skan		return (-1);
466169689Skan	}
467169689Skan	return (0);
468169689Skan}
469169689Skan
470169689Skanstatic int
471169689Skaneli_metadata_store(struct gctl_req *req, const char *prov,
472169689Skan    struct g_eli_metadata *md)
473169689Skan{
474169689Skan	unsigned char sector[sizeof(struct g_eli_metadata)];
475169689Skan	int error;
476169689Skan
477169689Skan	eli_metadata_encode(md, sector);
478169689Skan	if (g_get_sectorsize(prov) == 0) {
479169689Skan		int fd;
480169689Skan
481169689Skan		/* This is a file probably. */
482169689Skan		fd = open(prov, O_WRONLY | O_TRUNC);
483169689Skan		if (fd == -1) {
484169689Skan			gctl_error(req, "Cannot open %s: %s.", prov,
485169689Skan			    strerror(errno));
486169689Skan			bzero(sector, sizeof(sector));
487169689Skan			return (-1);
488169689Skan		}
489169689Skan		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
490169689Skan			gctl_error(req, "Cannot write metadata to %s: %s.",
491169689Skan			    prov, strerror(errno));
492169689Skan			bzero(sector, sizeof(sector));
493169689Skan			close(fd);
494169689Skan			return (-1);
495169689Skan		}
496169689Skan		close(fd);
497169689Skan	} else {
498169689Skan		/* This is a GEOM provider. */
499169689Skan		error = g_metadata_store(prov, sector, sizeof(sector));
500169689Skan		if (error != 0) {
501169689Skan			gctl_error(req, "Cannot write metadata to %s: %s.",
502169689Skan			    prov, strerror(errno));
503169689Skan			bzero(sector, sizeof(sector));
504169689Skan			return (-1);
505169689Skan		}
506169689Skan	}
507169689Skan	bzero(sector, sizeof(sector));
508169689Skan	return (0);
509169689Skan}
510169689Skan
511169689Skanstatic void
512169689Skaneli_init(struct gctl_req *req)
513169689Skan{
514169689Skan	struct g_eli_metadata md;
515169689Skan	unsigned char sector[sizeof(struct g_eli_metadata)];
516169689Skan	unsigned char key[G_ELI_USERKEYLEN];
517169689Skan	const char *str, *prov;
518169689Skan	unsigned secsize;
519169689Skan	off_t mediasize;
520169689Skan	intmax_t val;
521169689Skan	int error, nargs;
522169689Skan
523169689Skan	nargs = gctl_get_int(req, "nargs");
524169689Skan	if (nargs != 1) {
525169689Skan		gctl_error(req, "Invalid number of arguments.");
526169689Skan		return;
527169689Skan	}
528169689Skan	prov = gctl_get_ascii(req, "arg0");
529169689Skan	mediasize = g_get_mediasize(prov);
530169689Skan	secsize = g_get_sectorsize(prov);
531169689Skan	if (mediasize == 0 || secsize == 0) {
532169689Skan		gctl_error(req, "Cannot get informations about %s: %s.", prov,
533169689Skan		    strerror(errno));
534169689Skan		return;
535169689Skan	}
536169689Skan
537169689Skan	bzero(&md, sizeof(md));
538169689Skan	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
539169689Skan	md.md_version = G_ELI_VERSION;
540169689Skan	md.md_flags = 0;
541169689Skan	if (gctl_get_int(req, "boot"))
542169689Skan		md.md_flags |= G_ELI_FLAG_BOOT;
543169689Skan	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
544169689Skan	str = gctl_get_ascii(req, "aalgo");
545169689Skan	if (strcmp(str, "none") != 0) {
546169689Skan		md.md_aalgo = g_eli_str2aalgo(str);
547169689Skan		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
548169689Skan		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
549169689Skan			md.md_flags |= G_ELI_FLAG_AUTH;
550169689Skan		} else {
551169689Skan			/*
552169689Skan			 * For backward compatibility, check if the -a option
553169689Skan			 * was used to provide encryption algorithm.
554169689Skan			 */
555169689Skan			md.md_ealgo = g_eli_str2ealgo(str);
556169689Skan			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
557169689Skan			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
558169689Skan				gctl_error(req,
559169689Skan				    "Invalid authentication algorithm.");
560169689Skan				return;
561169689Skan			} else {
562169689Skan				fprintf(stderr, "warning: The -e option, not "
563169689Skan				    "the -a option is now used to specify "
564169689Skan				    "encryption algorithm to use.\n");
565169689Skan			}
566169689Skan		}
567169689Skan	}
568169689Skan	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
569169689Skan	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
570169689Skan		str = gctl_get_ascii(req, "ealgo");
571169689Skan		md.md_ealgo = g_eli_str2ealgo(str);
572169689Skan		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
573169689Skan		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
574169689Skan			gctl_error(req, "Invalid encryption algorithm.");
575169689Skan			return;
576169689Skan		}
577169689Skan	}
578169689Skan	val = gctl_get_intmax(req, "keylen");
579169689Skan	md.md_keylen = val;
580169689Skan	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
581169689Skan	if (md.md_keylen == 0) {
582169689Skan		gctl_error(req, "Invalid key length.");
583169689Skan		return;
584169689Skan	}
585169689Skan	md.md_provsize = mediasize;
586169689Skan
587169689Skan	val = gctl_get_intmax(req, "iterations");
588169689Skan	if (val != -1) {
589169689Skan		int nonewpassphrase;
590169689Skan
591169689Skan		/*
592169689Skan		 * Don't allow to set iterations when there will be no
593169689Skan		 * passphrase.
594169689Skan		 */
595169689Skan		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
596169689Skan		if (nonewpassphrase) {
597169689Skan			gctl_error(req,
598169689Skan			    "Options -i and -P are mutually exclusive.");
599169689Skan			return;
600169689Skan		}
601169689Skan	}
602169689Skan	md.md_iterations = val;
603169689Skan
604169689Skan	val = gctl_get_intmax(req, "sectorsize");
605169689Skan	if (val == 0)
606169689Skan		md.md_sectorsize = secsize;
607169689Skan	else {
608169689Skan		if (val < 0 || (val % secsize) != 0) {
609169689Skan			gctl_error(req, "Invalid sector size.");
610169689Skan			return;
611169689Skan		}
612169689Skan		md.md_sectorsize = val;
613169689Skan	}
614169689Skan
615169689Skan	md.md_keys = 0x01;
616169689Skan	arc4rand(md.md_salt, sizeof(md.md_salt));
617169689Skan	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
618169689Skan
619169689Skan	/* Generate user key. */
620169689Skan	if (eli_genkey(req, &md, key, 1) == NULL) {
621169689Skan		bzero(key, sizeof(key));
622169689Skan		bzero(&md, sizeof(md));
623169689Skan		return;
624169689Skan	}
625169689Skan
626169689Skan	/* Encrypt the first and the only Master Key. */
627169689Skan	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
628169689Skan	bzero(key, sizeof(key));
629169689Skan	if (error != 0) {
630169689Skan		bzero(&md, sizeof(md));
631169689Skan		gctl_error(req, "Cannot encrypt Master Key: %s.",
632169689Skan		    strerror(error));
633169689Skan		return;
634169689Skan	}
635169689Skan
636169689Skan	eli_metadata_encode(&md, sector);
637169689Skan	bzero(&md, sizeof(md));
638169689Skan	error = g_metadata_store(prov, sector, sizeof(sector));
639169689Skan	bzero(sector, sizeof(sector));
640169689Skan	if (error != 0) {
641169689Skan		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
642169689Skan		    strerror(error));
643169689Skan		return;
644169689Skan	}
645169689Skan	if (verbose)
646169689Skan		printf("Metadata value stored on %s.\n", prov);
647169689Skan}
648169689Skan
649169689Skanstatic void
650169689Skaneli_attach(struct gctl_req *req)
651169689Skan{
652169689Skan	struct g_eli_metadata md;
653169689Skan	unsigned char key[G_ELI_USERKEYLEN];
654169689Skan	const char *prov;
655169689Skan	int nargs;
656169689Skan
657169689Skan	nargs = gctl_get_int(req, "nargs");
658169689Skan	if (nargs != 1) {
659169689Skan		gctl_error(req, "Invalid number of arguments.");
660169689Skan		return;
661169689Skan	}
662169689Skan	prov = gctl_get_ascii(req, "arg0");
663169689Skan
664169689Skan	if (eli_metadata_read(req, prov, &md) == -1)
665169689Skan		return;
666169689Skan
667169689Skan	if (eli_genkey(req, &md, key, 0) == NULL) {
668169689Skan		bzero(key, sizeof(key));
669169689Skan		return;
670169689Skan	}
671169689Skan
672169689Skan	gctl_ro_param(req, "key", sizeof(key), key);
673169689Skan	if (gctl_issue(req) == NULL) {
674169689Skan		if (verbose)
675169689Skan			printf("Attached to %s.\n", prov);
676169689Skan	}
677169689Skan	bzero(key, sizeof(key));
678169689Skan}
679169689Skan
680169689Skanstatic void
681169689Skaneli_configure_detached(struct gctl_req *req, const char *prov, int boot)
682169689Skan{
683169689Skan	struct g_eli_metadata md;
684169689Skan
685169689Skan	if (eli_metadata_read(req, prov, &md) == -1)
686169689Skan		return;
687169689Skan
688169689Skan	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
689169689Skan		if (verbose)
690169689Skan			printf("BOOT flag already configured for %s.\n", prov);
691169689Skan	} else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) {
692169689Skan		if (verbose)
693169689Skan			printf("BOOT flag not configured for %s.\n", prov);
694169689Skan	} else {
695169689Skan		if (boot)
696169689Skan			md.md_flags |= G_ELI_FLAG_BOOT;
697169689Skan		else
698169689Skan			md.md_flags &= ~G_ELI_FLAG_BOOT;
699169689Skan		eli_metadata_store(req, prov, &md);
700169689Skan	}
701169689Skan	bzero(&md, sizeof(md));
702169689Skan}
703169689Skan
704169689Skanstatic void
705169689Skaneli_configure(struct gctl_req *req)
706169689Skan{
707169689Skan	const char *prov;
708169689Skan	int i, nargs, boot, noboot;
709169689Skan
710169689Skan	nargs = gctl_get_int(req, "nargs");
711169689Skan	if (nargs == 0) {
712169689Skan		gctl_error(req, "Too few arguments.");
713169689Skan		return;
714169689Skan	}
715169689Skan
716169689Skan	boot = gctl_get_int(req, "boot");
717169689Skan	noboot = gctl_get_int(req, "noboot");
718169689Skan
719169689Skan	if (boot && noboot) {
720169689Skan		gctl_error(req, "Options -b and -B are mutually exclusive.");
721169689Skan		return;
722169689Skan	}
723169689Skan	if (!boot && !noboot) {
724169689Skan		gctl_error(req, "No option given.");
725169689Skan		return;
726169689Skan	}
727169689Skan
728169689Skan	/* First attached providers. */
729169689Skan	gctl_issue(req);
730169689Skan	/* Now the rest. */
731169689Skan	for (i = 0; i < nargs; i++) {
732169689Skan		prov = gctl_get_ascii(req, "arg%d", i);
733169689Skan		if (!eli_is_attached(prov))
734169689Skan			eli_configure_detached(req, prov, boot);
735169689Skan	}
736169689Skan}
737169689Skan
738169689Skanstatic void
739169689Skaneli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
740169689Skan{
741169689Skan	unsigned char key[G_ELI_USERKEYLEN];
742169689Skan	intmax_t val, old = 0;
743169689Skan	int error;
744169689Skan
745169689Skan	val = gctl_get_intmax(req, "iterations");
746169689Skan	/* Check if iterations number should be changed. */
747169689Skan	if (val != -1)
748169689Skan		md->md_iterations = val;
749169689Skan	else
750169689Skan		old = md->md_iterations;
751169689Skan
752169689Skan	/* Generate key for Master Key encryption. */
753169689Skan	if (eli_genkey(req, md, key, 1) == NULL) {
754169689Skan		bzero(key, sizeof(key));
755169689Skan		return;
756169689Skan	}
757169689Skan	/*
758169689Skan	 * If number of iterations has changed, but wasn't given as a
759169689Skan	 * command-line argument, update the request.
760169689Skan	 */
761169689Skan	if (val == -1 && md->md_iterations != old) {
762169689Skan		error = gctl_change_param(req, "iterations", sizeof(intmax_t),
763169689Skan		    &md->md_iterations);
764169689Skan		assert(error == 0);
765169689Skan	}
766169689Skan
767169689Skan	gctl_ro_param(req, "key", sizeof(key), key);
768169689Skan	gctl_issue(req);
769169689Skan	bzero(key, sizeof(key));
770169689Skan}
771169689Skan
772169689Skanstatic void
773169689Skaneli_setkey_detached(struct gctl_req *req, const char *prov,
774169689Skan struct g_eli_metadata *md)
775169689Skan{
776169689Skan	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
777169689Skan	unsigned char *mkeydst;
778169689Skan	intmax_t val;
779169689Skan	unsigned nkey;
780169689Skan	int error;
781169689Skan
782169689Skan	if (md->md_keys == 0) {
783169689Skan		gctl_error(req, "No valid keys on %s.", prov);
784169689Skan		return;
785169689Skan	}
786169689Skan
787169689Skan	/* Generate key for Master Key decryption. */
788169689Skan	if (eli_genkey(req, md, key, 0) == NULL) {
789169689Skan		bzero(key, sizeof(key));
790169689Skan		return;
791169689Skan	}
792169689Skan
793169689Skan	/* Decrypt Master Key. */
794169689Skan	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
795169689Skan	bzero(key, sizeof(key));
796169689Skan	if (error != 0) {
797169689Skan		bzero(md, sizeof(*md));
798169689Skan		if (error == -1)
799169689Skan			gctl_error(req, "Wrong key for %s.", prov);
800169689Skan		else /* if (error > 0) */ {
801169689Skan			gctl_error(req, "Cannot decrypt Master Key: %s.",
802169689Skan			    strerror(error));
803169689Skan		}
804169689Skan		return;
805169689Skan	}
806169689Skan	if (verbose)
807169689Skan		printf("Decrypted Master Key %u.\n", nkey);
808169689Skan
809169689Skan	val = gctl_get_intmax(req, "keyno");
810169689Skan	if (val != -1)
811169689Skan		nkey = val;
812169689Skan#if 0
813169689Skan	else
814169689Skan		; /* Use the key number which was found during decryption. */
815169689Skan#endif
816169689Skan	if (nkey >= G_ELI_MAXMKEYS) {
817169689Skan		gctl_error(req, "Invalid '%s' argument.", "keyno");
818169689Skan		return;
819169689Skan	}
820169689Skan
821169689Skan	val = gctl_get_intmax(req, "iterations");
822169689Skan	/* Check if iterations number should and can be changed. */
823169689Skan	if (val != -1) {
824169689Skan		if (bitcount32(md->md_keys) != 1) {
825169689Skan			gctl_error(req, "To be able to use '-i' option, only "
826169689Skan			    "one key can be defined.");
827169689Skan			return;
828169689Skan		}
829169689Skan		if (md->md_keys != (1 << nkey)) {
830169689Skan			gctl_error(req, "Only already defined key can be "
831169689Skan			    "changed when '-i' option is used.");
832169689Skan			return;
833169689Skan		}
834169689Skan		md->md_iterations = val;
835169689Skan	}
836169689Skan
837169689Skan	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
838169689Skan	md->md_keys |= (1 << nkey);
839169689Skan
840169689Skan	bcopy(mkey, mkeydst, sizeof(mkey));
841169689Skan	bzero(mkey, sizeof(mkey));
842169689Skan
843169689Skan	/* Generate key for Master Key encryption. */
844169689Skan	if (eli_genkey(req, md, key, 1) == NULL) {
845169689Skan		bzero(key, sizeof(key));
846169689Skan		bzero(md, sizeof(*md));
847169689Skan		return;
848169689Skan	}
849169689Skan
850169689Skan	/* Encrypt the Master-Key with the new key. */
851169689Skan	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
852169689Skan	bzero(key, sizeof(key));
853169689Skan	if (error != 0) {
854169689Skan		bzero(md, sizeof(*md));
855169689Skan		gctl_error(req, "Cannot encrypt Master Key: %s.",
856169689Skan		    strerror(error));
857169689Skan		return;
858169689Skan	}
859169689Skan
860169689Skan	/* Store metadata with fresh key. */
861169689Skan	eli_metadata_store(req, prov, md);
862169689Skan	bzero(md, sizeof(*md));
863169689Skan}
864169689Skan
865169689Skanstatic void
866169689Skaneli_setkey(struct gctl_req *req)
867169689Skan{
868169689Skan	struct g_eli_metadata md;
869169689Skan	const char *prov;
870169689Skan	int nargs;
871169689Skan
872169689Skan	nargs = gctl_get_int(req, "nargs");
873169689Skan	if (nargs != 1) {
874169689Skan		gctl_error(req, "Invalid number of arguments.");
875169689Skan		return;
876169689Skan	}
877169689Skan	prov = gctl_get_ascii(req, "arg0");
878169689Skan
879169689Skan	if (eli_metadata_read(req, prov, &md) == -1)
880169689Skan		return;
881169689Skan
882169689Skan	if (eli_is_attached(prov))
883169689Skan		eli_setkey_attached(req, &md);
884169689Skan	else
885169689Skan		eli_setkey_detached(req, prov, &md);
886169689Skan}
887169689Skan
888169689Skanstatic void
889169689Skaneli_delkey_attached(struct gctl_req *req, const char *prov __unused)
890169689Skan{
891169689Skan
892169689Skan	gctl_issue(req);
893169689Skan}
894169689Skan
895169689Skanstatic void
896169689Skaneli_delkey_detached(struct gctl_req *req, const char *prov)
897169689Skan{
898169689Skan	struct g_eli_metadata md;
899169689Skan	unsigned char *mkeydst;
900169689Skan	intmax_t val;
901169689Skan	unsigned nkey;
902169689Skan	int all, force;
903169689Skan
904169689Skan	if (eli_metadata_read(req, prov, &md) == -1)
905169689Skan		return;
906169689Skan
907169689Skan	all = gctl_get_int(req, "all");
908169689Skan	if (all)
909169689Skan		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
910169689Skan	else {
911169689Skan		force = gctl_get_int(req, "force");
912169689Skan		val = gctl_get_intmax(req, "keyno");
913169689Skan		if (val == -1) {
914169689Skan			gctl_error(req, "Key number has to be specified.");
915169689Skan			return;
916169689Skan		}
917169689Skan		nkey = val;
918169689Skan		if (nkey >= G_ELI_MAXMKEYS) {
919169689Skan			gctl_error(req, "Invalid '%s' argument.", "keyno");
920169689Skan			return;
921169689Skan		}
922169689Skan		if (!(md.md_keys & (1 << nkey)) && !force) {
923169689Skan			gctl_error(req, "Master Key %u is not set.", nkey);
924169689Skan			return;
925169689Skan		}
926169689Skan		md.md_keys &= ~(1 << nkey);
927169689Skan		if (md.md_keys == 0 && !force) {
928169689Skan			gctl_error(req, "This is the last Master Key. Use '-f' "
929169689Skan			    "option if you really want to remove it.");
930169689Skan			return;
931169689Skan		}
932169689Skan		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
933169689Skan		arc4rand(mkeydst, G_ELI_MKEYLEN);
934169689Skan	}
935169689Skan
936169689Skan	eli_metadata_store(req, prov, &md);
937169689Skan	bzero(&md, sizeof(md));
938169689Skan}
939169689Skan
940169689Skanstatic void
941169689Skaneli_delkey(struct gctl_req *req)
942169689Skan{
943169689Skan	const char *prov;
944169689Skan	int nargs;
945169689Skan
946169689Skan	nargs = gctl_get_int(req, "nargs");
947169689Skan	if (nargs != 1) {
948169689Skan		gctl_error(req, "Invalid number of arguments.");
949169689Skan		return;
950169689Skan	}
951169689Skan	prov = gctl_get_ascii(req, "arg0");
952169689Skan
953169689Skan	if (eli_is_attached(prov))
954169689Skan		eli_delkey_attached(req, prov);
955169689Skan	else
956169689Skan		eli_delkey_detached(req, prov);
957169689Skan}
958169689Skan
959169689Skanstatic void
960169689Skaneli_kill_detached(struct gctl_req *req, const char *prov)
961169689Skan{
962169689Skan	struct g_eli_metadata md;
963169689Skan	int error;
964169689Skan
965169689Skan	/*
966169689Skan	 * NOTE: Maybe we should verify if this is geli provider first,
967169689Skan	 *       but 'kill' command is quite critical so better don't waste
968169689Skan	 *       the time.
969169689Skan	 */
970169689Skan#if 0
971169689Skan	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
972169689Skan	    G_ELI_MAGIC);
973169689Skan	if (error != 0) {
974169689Skan		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
975169689Skan		    strerror(error));
976169689Skan		return;
977169689Skan	}
978169689Skan#endif
979169689Skan
980169689Skan	arc4rand((unsigned char *)&md, sizeof(md));
981169689Skan	error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
982169689Skan	if (error != 0) {
983169689Skan		gctl_error(req, "Cannot write metadata to %s: %s.", prov,
984169689Skan		    strerror(error));
985169689Skan	}
986169689Skan}
987169689Skan
988169689Skanstatic void
989169689Skaneli_kill(struct gctl_req *req)
990169689Skan{
991169689Skan	const char *prov;
992169689Skan	int i, nargs, all;
993169689Skan
994169689Skan	nargs = gctl_get_int(req, "nargs");
995169689Skan	all = gctl_get_int(req, "all");
996169689Skan	if (!all && nargs == 0) {
997169689Skan		gctl_error(req, "Too few arguments.");
998169689Skan		return;
999169689Skan	}
1000169689Skan	/*
1001169689Skan	 * How '-a' option combine with a list of providers:
1002169689Skan	 * Delete Master Keys from all attached providers:
1003169689Skan	 * geli kill -a
1004169689Skan	 * Delete Master Keys from all attached provider and from
1005169689Skan	 * detached da0 and da1:
1006169689Skan	 * geli kill -a da0 da1
1007169689Skan	 * Delete Master Keys from (attached or detached) da0 and da1:
1008169689Skan	 * geli kill da0 da1
1009169689Skan	 */
1010169689Skan
1011169689Skan	/* First detached provider. */
1012169689Skan	for (i = 0; i < nargs; i++) {
1013169689Skan		prov = gctl_get_ascii(req, "arg%d", i);
1014169689Skan		if (!eli_is_attached(prov))
1015169689Skan			eli_kill_detached(req, prov);
1016169689Skan	}
1017169689Skan	/* Now attached providers. */
1018169689Skan	gctl_issue(req);
1019169689Skan}
1020169689Skan
1021169689Skanstatic void
1022169689Skaneli_backup(struct gctl_req *req)
1023169689Skan{
1024169689Skan	struct g_eli_metadata md;
1025169689Skan	const char *file, *prov;
1026169689Skan	unsigned secsize;
1027169689Skan	unsigned char *sector;
1028169689Skan	off_t mediasize;
1029169689Skan	int nargs, filefd, provfd;
1030169689Skan
1031169689Skan	nargs = gctl_get_int(req, "nargs");
1032169689Skan	if (nargs != 2) {
1033169689Skan		gctl_error(req, "Invalid number of arguments.");
1034169689Skan		return;
1035169689Skan	}
1036169689Skan	prov = gctl_get_ascii(req, "arg0");
1037169689Skan	file = gctl_get_ascii(req, "arg1");
1038169689Skan
1039169689Skan	provfd = filefd = -1;
1040169689Skan	sector = NULL;
1041169689Skan	secsize = 0;
1042169689Skan
1043169689Skan	provfd = open(prov, O_RDONLY);
1044169689Skan	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1045169689Skan		char devprov[MAXPATHLEN];
1046169689Skan
1047169689Skan		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1048169689Skan		provfd = open(devprov, O_RDONLY);
1049169689Skan	}
1050169689Skan	if (provfd == -1) {
1051169689Skan		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1052169689Skan		return;
1053169689Skan	}
1054169689Skan	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1055169689Skan	if (filefd == -1) {
1056169689Skan		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1057169689Skan		goto out;
1058169689Skan	}
1059169689Skan
1060169689Skan	mediasize = g_get_mediasize(prov);
1061169689Skan	secsize = g_get_sectorsize(prov);
1062169689Skan	if (mediasize == 0 || secsize == 0) {
1063169689Skan		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1064169689Skan		    strerror(errno));
1065169689Skan		return;
1066169689Skan	}
1067169689Skan
1068169689Skan	sector = malloc(secsize);
1069169689Skan	if (sector == NULL) {
1070169689Skan		gctl_error(req, "Cannot allocate memory.");
1071169689Skan		return;
1072169689Skan	}
1073169689Skan
1074169689Skan	/* Read metadata from the provider. */
1075169689Skan	if (pread(provfd, sector, secsize, mediasize - secsize) !=
1076169689Skan	    (ssize_t)secsize) {
1077169689Skan		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
1078169689Skan		goto out;
1079169689Skan	}
1080169689Skan	/* Check if this is geli provider. */
1081169689Skan	if (eli_metadata_decode(sector, &md) != 0) {
1082169689Skan		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1083169689Skan		goto out;
1084169689Skan	}
1085169689Skan	/* Write metadata to the destination file. */
1086169689Skan	if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1087169689Skan		gctl_error(req, "Cannot write to %s: %s.", file,
1088169689Skan		    strerror(errno));
1089169689Skan		goto out;
1090169689Skan	}
1091169689Skanout:
1092169689Skan	if (provfd > 0)
1093169689Skan		close(provfd);
1094169689Skan	if (filefd > 0)
1095169689Skan		close(filefd);
1096169689Skan	if (sector != NULL) {
1097169689Skan		bzero(sector, secsize);
1098169689Skan		free(sector);
1099169689Skan	}
1100169689Skan}
1101169689Skan
1102169689Skanstatic void
1103169689Skaneli_restore(struct gctl_req *req)
1104169689Skan{
1105169689Skan	struct g_eli_metadata md;
1106169689Skan	const char *file, *prov;
1107169689Skan	unsigned char *sector;
1108169689Skan	unsigned secsize;
1109169689Skan	off_t mediasize;
1110169689Skan	int nargs, filefd, provfd;
1111169689Skan
1112169689Skan	nargs = gctl_get_int(req, "nargs");
1113169689Skan	if (nargs != 2) {
1114169689Skan		gctl_error(req, "Invalid number of arguments.");
1115169689Skan		return;
1116169689Skan	}
1117169689Skan	file = gctl_get_ascii(req, "arg0");
1118169689Skan	prov = gctl_get_ascii(req, "arg1");
1119169689Skan
1120169689Skan	provfd = filefd = -1;
1121169689Skan	sector = NULL;
1122169689Skan	secsize = 0;
1123169689Skan
1124169689Skan	filefd = open(file, O_RDONLY);
1125169689Skan	if (filefd == -1) {
1126169689Skan		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1127169689Skan		goto out;
1128169689Skan	}
1129169689Skan	provfd = open(prov, O_WRONLY);
1130169689Skan	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1131169689Skan		char devprov[MAXPATHLEN];
1132169689Skan
1133169689Skan		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1134169689Skan		provfd = open(devprov, O_WRONLY);
1135169689Skan	}
1136169689Skan	if (provfd == -1) {
1137169689Skan		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1138169689Skan		return;
1139169689Skan	}
1140169689Skan
1141169689Skan	mediasize = g_get_mediasize(prov);
1142169689Skan	secsize = g_get_sectorsize(prov);
1143169689Skan	if (mediasize == 0 || secsize == 0) {
1144169689Skan		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1145169689Skan		    strerror(errno));
1146169689Skan		return;
1147169689Skan	}
1148169689Skan
1149169689Skan	sector = malloc(secsize);
1150169689Skan	if (sector == NULL) {
1151169689Skan		gctl_error(req, "Cannot allocate memory.");
1152169689Skan		return;
1153169689Skan	}
1154169689Skan
1155169689Skan	/* Read metadata from the backup file. */
1156169689Skan	if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1157169689Skan		gctl_error(req, "Cannot read from %s: %s.", file,
1158169689Skan		    strerror(errno));
1159169689Skan		goto out;
1160169689Skan	}
1161169689Skan	/* Check if this file contains geli metadata. */
1162169689Skan	if (eli_metadata_decode(sector, &md) != 0) {
1163169689Skan		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1164169689Skan		goto out;
1165169689Skan	}
1166169689Skan	/* Write metadata from the provider. */
1167169689Skan	if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1168169689Skan	    (ssize_t)secsize) {
1169169689Skan		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1170169689Skan		goto out;
1171169689Skan	}
1172169689Skanout:
1173169689Skan	if (provfd > 0)
1174169689Skan		close(provfd);
1175169689Skan	if (filefd > 0)
1176169689Skan		close(filefd);
1177169689Skan	if (sector != NULL) {
1178169689Skan		bzero(sector, secsize);
1179169689Skan		free(sector);
1180169689Skan	}
1181169689Skan}
1182169689Skan
1183169689Skanstatic void
1184169689Skaneli_clear(struct gctl_req *req)
1185169689Skan{
1186169689Skan	const char *name;
1187169689Skan	int error, i, nargs;
1188169689Skan
1189169689Skan	nargs = gctl_get_int(req, "nargs");
1190169689Skan	if (nargs < 1) {
1191169689Skan		gctl_error(req, "Too few arguments.");
1192169689Skan		return;
1193169689Skan	}
1194169689Skan
1195169689Skan	for (i = 0; i < nargs; i++) {
1196169689Skan		name = gctl_get_ascii(req, "arg%d", i);
1197169689Skan		error = g_metadata_clear(name, G_ELI_MAGIC);
1198169689Skan		if (error != 0) {
1199169689Skan			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1200169689Skan			    name, strerror(error));
1201169689Skan			gctl_error(req, "Not fully done.");
1202169689Skan			continue;
1203169689Skan		}
1204169689Skan		if (verbose)
1205169689Skan			printf("Metadata cleared on %s.\n", name);
1206169689Skan	}
1207169689Skan}
1208169689Skan
1209169689Skanstatic void
1210169689Skaneli_dump(struct gctl_req *req)
1211169689Skan{
1212169689Skan	struct g_eli_metadata md, tmpmd;
1213169689Skan	const char *name;
1214169689Skan	int error, i, nargs;
1215169689Skan
1216169689Skan	nargs = gctl_get_int(req, "nargs");
1217169689Skan	if (nargs < 1) {
1218169689Skan		gctl_error(req, "Too few arguments.");
1219169689Skan		return;
1220169689Skan	}
1221169689Skan
1222169689Skan	for (i = 0; i < nargs; i++) {
1223169689Skan		name = gctl_get_ascii(req, "arg%d", i);
1224169689Skan		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1225169689Skan		    sizeof(tmpmd), G_ELI_MAGIC);
1226169689Skan		if (error != 0) {
1227169689Skan			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1228169689Skan			    name, strerror(error));
1229169689Skan			gctl_error(req, "Not fully done.");
1230169689Skan			continue;
1231169689Skan		}
1232169689Skan		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1233169689Skan			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1234169689Skan			    name);
1235169689Skan			gctl_error(req, "Not fully done.");
1236169689Skan			continue;
1237169689Skan		}
1238169689Skan		printf("Metadata on %s:\n", name);
1239169689Skan		eli_metadata_dump(&md);
1240169689Skan		printf("\n");
1241169689Skan	}
1242169689Skan}
1243169689Skan