geom_eli.c revision 155536
1148456Spjd/*-
2148456Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3148456Spjd * All rights reserved.
4148456Spjd *
5148456Spjd * Redistribution and use in source and binary forms, with or without
6148456Spjd * modification, are permitted provided that the following conditions
7148456Spjd * are met:
8148456Spjd * 1. Redistributions of source code must retain the above copyright
9148456Spjd *    notice, this list of conditions and the following disclaimer.
10148456Spjd * 2. Redistributions in binary form must reproduce the above copyright
11148456Spjd *    notice, this list of conditions and the following disclaimer in the
12148456Spjd *    documentation and/or other materials provided with the distribution.
13155175Spjd *
14148456Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15148456Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16148456Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17148456Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18148456Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19148456Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148456Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148456Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22148456Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23148456Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24148456Spjd * SUCH DAMAGE.
25148456Spjd */
26148456Spjd
27148456Spjd#include <sys/cdefs.h>
28148456Spjd__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 155536 2006-02-11 13:04:10Z pjd $");
29148456Spjd
30148456Spjd#include <stdio.h>
31148456Spjd#include <stdint.h>
32148456Spjd#include <stdlib.h>
33148456Spjd#include <unistd.h>
34148456Spjd#include <fcntl.h>
35148456Spjd#include <readpassphrase.h>
36148456Spjd#include <string.h>
37148456Spjd#include <strings.h>
38148456Spjd#include <libgeom.h>
39148456Spjd#include <paths.h>
40148456Spjd#include <errno.h>
41148456Spjd#include <assert.h>
42148456Spjd
43148456Spjd#include <sys/param.h>
44148456Spjd#include <sys/mman.h>
45148456Spjd#include <sys/resource.h>
46148456Spjd#include <opencrypto/cryptodev.h>
47148456Spjd#include <geom/eli/g_eli.h>
48148456Spjd#include <geom/eli/pkcs5v2.h>
49148456Spjd
50148456Spjd#include "core/geom.h"
51148456Spjd#include "misc/subr.h"
52148456Spjd
53148456Spjd
54148456Spjduint32_t lib_version = G_LIB_VERSION;
55148456Spjduint32_t version = G_ELI_VERSION;
56148456Spjd
57148456Spjdstatic char algo[] = "aes";
58148456Spjdstatic intmax_t keylen = 0;
59148456Spjdstatic intmax_t keyno = -1;
60148456Spjdstatic intmax_t iterations = -1;
61148456Spjdstatic intmax_t sectorsize = 0;
62148456Spjdstatic char keyfile[] = "", newkeyfile[] = "";
63148456Spjd
64148456Spjdstatic void eli_main(struct gctl_req *req, unsigned flags);
65148456Spjdstatic void eli_init(struct gctl_req *req);
66148456Spjdstatic void eli_attach(struct gctl_req *req);
67148456Spjdstatic void eli_setkey(struct gctl_req *req);
68148456Spjdstatic void eli_delkey(struct gctl_req *req);
69148456Spjdstatic void eli_kill(struct gctl_req *req);
70148456Spjdstatic void eli_backup(struct gctl_req *req);
71148456Spjdstatic void eli_restore(struct gctl_req *req);
72148456Spjdstatic void eli_clear(struct gctl_req *req);
73148456Spjdstatic void eli_dump(struct gctl_req *req);
74148456Spjd
75148456Spjd/*
76148456Spjd * Available commands:
77148456Spjd *
78148456Spjd * init [-bhPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] prov
79148456Spjd * label - alias for 'init'
80148456Spjd * attach [-dpv] [-k keyfile] prov
81148456Spjd * detach [-fl] prov ...
82148456Spjd * stop - alias for 'detach'
83148456Spjd * onetime [-d] [-a algo] [-l keylen] prov ...
84148456Spjd * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
85148456Spjd * delkey [-afv] [-n keyno] prov
86148456Spjd * kill [-av] [prov ...]
87148456Spjd * backup [-v] prov file
88148456Spjd * restore [-v] file prov
89148456Spjd * clear [-v] prov ...
90148456Spjd * dump [-v] prov ...
91148456Spjd */
92148456Spjdstruct g_command class_commands[] = {
93148456Spjd	{ "init", G_FLAG_VERBOSE, eli_main,
94148456Spjd	    {
95148456Spjd		{ 'a', "algo", algo, G_TYPE_STRING },
96148456Spjd		{ 'b', "boot", NULL, G_TYPE_NONE },
97148456Spjd		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
98148456Spjd		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
99148456Spjd		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
100148456Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
101148456Spjd		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
102148456Spjd		G_OPT_SENTINEL
103148456Spjd	    },
104148456Spjd	    "[-bPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
105148456Spjd	},
106148456Spjd	{ "label", G_FLAG_VERBOSE, eli_main,
107148456Spjd	    {
108148456Spjd		{ 'a', "algo", algo, G_TYPE_STRING },
109148456Spjd		{ 'b', "boot", NULL, G_TYPE_NONE },
110148456Spjd		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
111148456Spjd		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
112148456Spjd		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
113148456Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
114148456Spjd		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
115148456Spjd		G_OPT_SENTINEL
116148456Spjd	    },
117148456Spjd	    "- an alias for 'init'"
118148456Spjd	},
119148456Spjd	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
120148456Spjd	    {
121148456Spjd		{ 'd', "detach", NULL, G_TYPE_NONE },
122148456Spjd		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
123148456Spjd		{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
124148456Spjd		G_OPT_SENTINEL
125148456Spjd	    },
126148456Spjd	    "[-dpv] [-k keyfile] prov"
127148456Spjd	},
128148456Spjd	{ "detach", 0, NULL,
129148456Spjd	    {
130148456Spjd		{ 'f', "force", NULL, G_TYPE_NONE },
131148456Spjd		{ 'l', "last", NULL, G_TYPE_NONE },
132148456Spjd		G_OPT_SENTINEL
133148456Spjd	    },
134148456Spjd	    "[-fl] prov ..."
135148456Spjd	},
136148456Spjd	{ "stop", 0, NULL,
137148456Spjd	    {
138148456Spjd		{ 'f', "force", NULL, G_TYPE_NONE },
139148456Spjd		{ 'l', "last", NULL, G_TYPE_NONE },
140148456Spjd		G_OPT_SENTINEL
141148456Spjd	    },
142148456Spjd	    "- an alias for 'detach'"
143148456Spjd	},
144148456Spjd	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
145148456Spjd	    {
146148456Spjd		{ 'a', "algo", algo, G_TYPE_STRING },
147148456Spjd		{ 'd', "detach", NULL, G_TYPE_NONE },
148148456Spjd		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
149148456Spjd		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
150148456Spjd		G_OPT_SENTINEL
151148456Spjd	    },
152148456Spjd	    "[-d] [-a algo] [-l keylen] [-s sectorsize] prov ..."
153148456Spjd	},
154148456Spjd	{ "setkey", G_FLAG_VERBOSE, eli_main,
155148456Spjd	    {
156149304Spjd		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
157148456Spjd		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
158148456Spjd		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
159148456Spjd		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
160148456Spjd		{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
161148456Spjd		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
162148456Spjd		G_OPT_SENTINEL
163148456Spjd	    },
164149304Spjd	    "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
165148456Spjd	},
166148456Spjd	{ "delkey", G_FLAG_VERBOSE, eli_main,
167148456Spjd	    {
168148456Spjd		{ 'a', "all", NULL, G_TYPE_NONE },
169148456Spjd		{ 'f', "force", NULL, G_TYPE_NONE },
170148456Spjd		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
171148456Spjd		G_OPT_SENTINEL
172148456Spjd	    },
173148456Spjd	    "[-afv] [-n keyno] prov"
174148456Spjd	},
175148456Spjd	{ "kill", G_FLAG_VERBOSE, eli_main,
176148456Spjd	    {
177148456Spjd		{ 'a', "all", NULL, G_TYPE_NONE },
178148456Spjd		G_OPT_SENTINEL
179148456Spjd	    },
180148456Spjd	    "[-av] [prov ...]"
181148456Spjd	},
182148456Spjd	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
183148456Spjd	    "[-v] prov file"
184148456Spjd	},
185148456Spjd	{ "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
186148456Spjd	    "[-v] file prov"
187148456Spjd	},
188148456Spjd	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
189148456Spjd	    "[-v] prov ..."
190148456Spjd	},
191148456Spjd	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
192148456Spjd	    "[-v] prov ..."
193148456Spjd	},
194148456Spjd	G_CMD_SENTINEL
195148456Spjd};
196148456Spjd
197148456Spjdstatic int verbose = 0;
198148456Spjd
199148456Spjdstatic int
200148456Spjdeli_protect(struct gctl_req *req)
201148456Spjd{
202148456Spjd	struct rlimit rl;
203148456Spjd
204148456Spjd	/* Disable core dumps. */
205148456Spjd	rl.rlim_cur = 0;
206148456Spjd	rl.rlim_max = 0;
207148456Spjd	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
208148456Spjd		gctl_error(req, "Cannot disable core dumps: %s.",
209148456Spjd		    strerror(errno));
210148456Spjd		return (-1);
211148456Spjd	}
212148456Spjd	/* Disable swapping. */
213148456Spjd	if (mlockall(MCL_FUTURE) == -1) {
214148456Spjd		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
215148456Spjd		return (-1);
216148456Spjd	}
217148456Spjd	return (0);
218148456Spjd}
219148456Spjd
220148456Spjdstatic void
221148456Spjdeli_main(struct gctl_req *req, unsigned flags)
222148456Spjd{
223148456Spjd	const char *name;
224148456Spjd
225148456Spjd	if (eli_protect(req) == -1)
226148456Spjd		return;
227148456Spjd
228148456Spjd	if ((flags & G_FLAG_VERBOSE) != 0)
229148456Spjd		verbose = 1;
230148456Spjd
231153190Spjd	name = gctl_get_ascii(req, "verb");
232148456Spjd	if (name == NULL) {
233148456Spjd		gctl_error(req, "No '%s' argument.", "verb");
234148456Spjd		return;
235148456Spjd	}
236148456Spjd	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
237148456Spjd		eli_init(req);
238148456Spjd	else if (strcmp(name, "attach") == 0)
239148456Spjd		eli_attach(req);
240148456Spjd	else if (strcmp(name, "setkey") == 0)
241148456Spjd		eli_setkey(req);
242148456Spjd	else if (strcmp(name, "delkey") == 0)
243148456Spjd		eli_delkey(req);
244148456Spjd	else if (strcmp(name, "kill") == 0)
245148456Spjd		eli_kill(req);
246148456Spjd	else if (strcmp(name, "backup") == 0)
247148456Spjd		eli_backup(req);
248148456Spjd	else if (strcmp(name, "restore") == 0)
249148456Spjd		eli_restore(req);
250148456Spjd	else if (strcmp(name, "dump") == 0)
251148456Spjd		eli_dump(req);
252148456Spjd	else if (strcmp(name, "clear") == 0)
253148456Spjd		eli_clear(req);
254148456Spjd	else
255148456Spjd		gctl_error(req, "Unknown command: %s.", name);
256148456Spjd}
257148456Spjd
258148456Spjdstatic void
259148456Spjdarc4rand(unsigned char *buf, size_t size)
260148456Spjd{
261148456Spjd	uint32_t *buf4;
262148456Spjd	size_t size4;
263148456Spjd	unsigned i;
264148456Spjd
265148456Spjd	buf4 = (uint32_t *)buf;
266148456Spjd	size4 = size / 4;
267148456Spjd
268148456Spjd	for (i = 0; i < size4; i++)
269148456Spjd		buf4[i] = arc4random();
270148456Spjd	for (i *= 4; i < size; i++)
271148456Spjd		buf[i] = arc4random() % 0xff;
272148456Spjd}
273148456Spjd
274148456Spjdstatic int
275148456Spjdeli_is_attached(const char *prov)
276148456Spjd{
277148456Spjd	char name[MAXPATHLEN];
278148456Spjd	unsigned secsize;
279148456Spjd
280148456Spjd	/*
281148456Spjd	 * Not the best way to do it, but the easiest.
282148456Spjd	 * We try to open provider and check if it is a GEOM provider
283148456Spjd	 * by asking about its sectorsize.
284148456Spjd	 */
285148456Spjd	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
286148456Spjd	secsize = g_get_sectorsize(name);
287148456Spjd	if (secsize > 0)
288148456Spjd		return (1);
289148456Spjd	return (0);
290148456Spjd}
291148456Spjd
292148456Spjdstatic unsigned char *
293148456Spjdeli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
294148456Spjd    int new)
295148456Spjd{
296148456Spjd	struct hmac_ctx ctx;
297148456Spjd	const char *str;
298153190Spjd	int error, nopassphrase;
299148456Spjd
300153190Spjd	nopassphrase =
301153190Spjd	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
302148456Spjd
303148456Spjd	g_eli_crypto_hmac_init(&ctx, NULL, 0);
304148456Spjd
305153190Spjd	str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
306155183Spjd	if (str[0] == '\0' && nopassphrase) {
307155183Spjd		gctl_error(req, "No key components given.");
308155183Spjd		return (NULL);
309155183Spjd	} else if (str[0] != '\0') {
310148456Spjd		char buf[MAXPHYS];
311148456Spjd		ssize_t done;
312148456Spjd		int fd;
313148456Spjd
314148456Spjd		if (strcmp(str, "-") == 0)
315148456Spjd			fd = STDIN_FILENO;
316148456Spjd		else {
317148456Spjd			fd = open(str, O_RDONLY);
318148456Spjd			if (fd == -1) {
319148456Spjd				gctl_error(req, "Cannot open keyfile %s: %s.",
320148456Spjd				    str, strerror(errno));
321148456Spjd				return (NULL);
322148456Spjd			}
323148456Spjd		}
324148456Spjd		while ((done = read(fd, buf, sizeof(buf))) > 0)
325148456Spjd			g_eli_crypto_hmac_update(&ctx, buf, done);
326148456Spjd		error = errno;
327148456Spjd		if (strcmp(str, "-") != 0)
328148456Spjd			close(fd);
329148456Spjd		bzero(buf, sizeof(buf));
330148456Spjd		if (done == -1) {
331148456Spjd			gctl_error(req, "Cannot read keyfile %s: %s.", str,
332148456Spjd			    strerror(error));
333148456Spjd			return (NULL);
334148456Spjd		}
335148456Spjd	}
336148456Spjd
337153190Spjd	if (!nopassphrase) {
338148456Spjd		char buf1[BUFSIZ], buf2[BUFSIZ], *p;
339148456Spjd
340149047Spjd		if (!new && md->md_iterations == -1) {
341149047Spjd			gctl_error(req, "Missing -p flag.");
342149047Spjd			return (NULL);
343149047Spjd		}
344148456Spjd		for (;;) {
345148456Spjd			p = readpassphrase(
346148456Spjd			    new ? "Enter new passphrase:" : "Enter passphrase:",
347148456Spjd			    buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
348148456Spjd			if (p == NULL) {
349148456Spjd				bzero(buf1, sizeof(buf1));
350148456Spjd				gctl_error(req, "Cannot read passphrase: %s.",
351148456Spjd				    strerror(errno));
352148456Spjd				return (NULL);
353148456Spjd			}
354148456Spjd
355148456Spjd			if (new) {
356148456Spjd				p = readpassphrase("Reenter new passphrase: ",
357148456Spjd				    buf2, sizeof(buf2),
358148456Spjd				    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
359148456Spjd				if (p == NULL) {
360148456Spjd					bzero(buf1, sizeof(buf1));
361148456Spjd					gctl_error(req,
362148456Spjd					    "Cannot read passphrase: %s.",
363148456Spjd					    strerror(errno));
364148456Spjd					return (NULL);
365148456Spjd				}
366148456Spjd
367148456Spjd				if (strcmp(buf1, buf2) != 0) {
368148456Spjd					bzero(buf2, sizeof(buf2));
369148456Spjd					fprintf(stderr, "They didn't match.\n");
370148456Spjd					continue;
371148456Spjd				}
372148456Spjd				bzero(buf2, sizeof(buf2));
373148456Spjd			}
374148456Spjd			break;
375148456Spjd		}
376148456Spjd		/*
377148456Spjd		 * Field md_iterations equal to -1 means "choose some sane
378148456Spjd		 * value for me".
379148456Spjd		 */
380148456Spjd		if (md->md_iterations == -1) {
381148456Spjd			assert(new);
382148456Spjd			if (verbose)
383148456Spjd				printf("Calculating number of iterations...\n");
384148456Spjd			md->md_iterations = pkcs5v2_calculate(2000000);
385148456Spjd			assert(md->md_iterations > 0);
386148456Spjd			if (verbose) {
387148456Spjd				printf("Done, using %d iterations.\n",
388148456Spjd				    md->md_iterations);
389148456Spjd			}
390148456Spjd		}
391148456Spjd		/*
392148456Spjd		 * If md_iterations is equal to 0, user don't want PKCS5v2.
393148456Spjd		 */
394148456Spjd		if (md->md_iterations == 0) {
395148456Spjd			g_eli_crypto_hmac_update(&ctx, md->md_salt,
396148456Spjd			    sizeof(md->md_salt));
397148456Spjd			g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
398148456Spjd		} else /* if (md->md_iterations > 0) */ {
399148456Spjd			unsigned char dkey[G_ELI_USERKEYLEN];
400148456Spjd
401148456Spjd			pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
402148456Spjd			    sizeof(md->md_salt), buf1, md->md_iterations);
403148456Spjd			g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
404148456Spjd			bzero(dkey, sizeof(dkey));
405148456Spjd		}
406148456Spjd		bzero(buf1, sizeof(buf1));
407148456Spjd	}
408148456Spjd	g_eli_crypto_hmac_final(&ctx, key, 0);
409148456Spjd	return (key);
410148456Spjd}
411148456Spjd
412148456Spjdstatic int
413148456Spjdeli_metadata_read(struct gctl_req *req, const char *prov,
414148456Spjd    struct g_eli_metadata *md)
415148456Spjd{
416148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
417148456Spjd	int error;
418148456Spjd
419148456Spjd	if (g_get_sectorsize(prov) == 0) {
420148456Spjd		int fd;
421148456Spjd
422148456Spjd		/* This is a file probably. */
423148456Spjd		fd = open(prov, O_RDONLY);
424148456Spjd		if (fd == -1) {
425148456Spjd			gctl_error(req, "Cannot open %s: %s.", prov,
426148456Spjd			    strerror(errno));
427148456Spjd			return (-1);
428148456Spjd		}
429148456Spjd		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
430148456Spjd			gctl_error(req, "Cannot read metadata from %s: %s.",
431148456Spjd			    prov, strerror(errno));
432148456Spjd			close(fd);
433148456Spjd			return (-1);
434148456Spjd		}
435148456Spjd		close(fd);
436148456Spjd	} else {
437148456Spjd		/* This is a GEOM provider. */
438148456Spjd		error = g_metadata_read(prov, sector, sizeof(sector),
439148456Spjd		    G_ELI_MAGIC);
440148456Spjd		if (error != 0) {
441148456Spjd			gctl_error(req, "Cannot read metadata from %s: %s.",
442148456Spjd			    prov, strerror(error));
443148456Spjd			return (-1);
444148456Spjd		}
445148456Spjd	}
446148456Spjd	if (eli_metadata_decode(sector, md) != 0) {
447148456Spjd		gctl_error(req, "MD5 hash mismatch for %s.", prov);
448148456Spjd		return (-1);
449148456Spjd	}
450148456Spjd	return (0);
451148456Spjd}
452148456Spjd
453148456Spjdstatic int
454148456Spjdeli_metadata_store(struct gctl_req *req, const char *prov,
455148456Spjd    struct g_eli_metadata *md)
456148456Spjd{
457148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
458148456Spjd	int error;
459148456Spjd
460148456Spjd	eli_metadata_encode(md, sector);
461148456Spjd	if (g_get_sectorsize(prov) == 0) {
462148456Spjd		int fd;
463148456Spjd
464148456Spjd		/* This is a file probably. */
465148456Spjd		fd = open(prov, O_WRONLY | O_TRUNC);
466148456Spjd		if (fd == -1) {
467148456Spjd			gctl_error(req, "Cannot open %s: %s.", prov,
468148456Spjd			    strerror(errno));
469148456Spjd			bzero(sector, sizeof(sector));
470148456Spjd			return (-1);
471148456Spjd		}
472148456Spjd		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
473148456Spjd			gctl_error(req, "Cannot write metadata to %s: %s.",
474148456Spjd			    prov, strerror(errno));
475148456Spjd			bzero(sector, sizeof(sector));
476148456Spjd			close(fd);
477148456Spjd			return (-1);
478148456Spjd		}
479148456Spjd		close(fd);
480148456Spjd	} else {
481148456Spjd		/* This is a GEOM provider. */
482148456Spjd		error = g_metadata_store(prov, sector, sizeof(sector));
483148456Spjd		if (error != 0) {
484148456Spjd			gctl_error(req, "Cannot write metadata to %s: %s.",
485148456Spjd			    prov, strerror(errno));
486148456Spjd			bzero(sector, sizeof(sector));
487148456Spjd			return (-1);
488148456Spjd		}
489148456Spjd	}
490148456Spjd	bzero(sector, sizeof(sector));
491148456Spjd	return (0);
492148456Spjd}
493148456Spjd
494148456Spjdstatic void
495148456Spjdeli_init(struct gctl_req *req)
496148456Spjd{
497148456Spjd	struct g_eli_metadata md;
498148456Spjd	unsigned char sector[sizeof(struct g_eli_metadata)];
499148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
500148456Spjd	const char *str, *prov;
501148456Spjd	unsigned secsize;
502148456Spjd	off_t mediasize;
503153190Spjd	intmax_t val;
504155536Spjd	int error, nargs;
505148456Spjd
506153190Spjd	nargs = gctl_get_int(req, "nargs");
507153190Spjd	if (nargs != 1) {
508148456Spjd		gctl_error(req, "Too few arguments.");
509148456Spjd		return;
510148456Spjd	}
511153190Spjd	prov = gctl_get_ascii(req, "arg0");
512148456Spjd	mediasize = g_get_mediasize(prov);
513148456Spjd	secsize = g_get_sectorsize(prov);
514148456Spjd	if (mediasize == 0 || secsize == 0) {
515148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
516148456Spjd		    strerror(errno));
517148456Spjd		return;
518148456Spjd	}
519148456Spjd
520148456Spjd	bzero(&md, sizeof(md));
521148456Spjd	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
522148456Spjd	md.md_version = G_ELI_VERSION;
523148456Spjd	md.md_flags = 0;
524155536Spjd	if (gctl_get_int(req, "boot"))
525148456Spjd		md.md_flags |= G_ELI_FLAG_BOOT;
526153190Spjd	str = gctl_get_ascii(req, "algo");
527148456Spjd	md.md_algo = g_eli_str2algo(str);
528148456Spjd	if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
529148456Spjd	    md.md_algo > CRYPTO_ALGORITHM_MAX) {
530148456Spjd		gctl_error(req, "Invalid encryption algorithm.");
531148456Spjd		return;
532148456Spjd	}
533153190Spjd	val = gctl_get_intmax(req, "keylen");
534153190Spjd	md.md_keylen = val;
535148456Spjd	md.md_keylen = g_eli_keylen(md.md_algo, md.md_keylen);
536148456Spjd	if (md.md_keylen == 0) {
537148456Spjd		gctl_error(req, "Invalid key length.");
538148456Spjd		return;
539148456Spjd	}
540148456Spjd	md.md_provsize = mediasize;
541148456Spjd
542153190Spjd	val = gctl_get_intmax(req, "iterations");
543155536Spjd	if (val != -1) {
544155536Spjd		int nonewpassphrase;
545155536Spjd
546155536Spjd		/*
547155536Spjd		 * Don't allow to set iterations when there will be no
548155536Spjd		 * passphrase.
549155536Spjd		 */
550155536Spjd		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
551155536Spjd		if (nonewpassphrase) {
552155536Spjd			gctl_error(req,
553155536Spjd			    "Options -i and -P are mutually exclusive.");
554155536Spjd			return;
555155536Spjd		}
556155536Spjd	}
557153190Spjd	md.md_iterations = val;
558148456Spjd
559153190Spjd	val = gctl_get_intmax(req, "sectorsize");
560153190Spjd	if (val == 0)
561148456Spjd		md.md_sectorsize = secsize;
562148456Spjd	else {
563153190Spjd		if (val < 0 || (val % secsize) != 0) {
564148456Spjd			gctl_error(req, "Invalid sector size.");
565148456Spjd			return;
566148456Spjd		}
567153190Spjd		md.md_sectorsize = val;
568148456Spjd	}
569148456Spjd
570148456Spjd	md.md_keys = 0x01;
571148456Spjd	arc4rand(md.md_salt, sizeof(md.md_salt));
572148456Spjd	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
573148456Spjd
574148456Spjd	/* Generate user key. */
575148456Spjd	if (eli_genkey(req, &md, key, 1) == NULL) {
576148456Spjd		bzero(key, sizeof(key));
577148456Spjd		bzero(&md, sizeof(md));
578148456Spjd		return;
579148456Spjd	}
580148456Spjd
581148456Spjd	/* Encrypt the first and the only Master Key. */
582148456Spjd	error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, md.md_mkeys);
583148456Spjd	bzero(key, sizeof(key));
584148456Spjd	if (error != 0) {
585148456Spjd		bzero(&md, sizeof(md));
586148456Spjd		gctl_error(req, "Cannot encrypt Master Key: %s.",
587148456Spjd		    strerror(error));
588148456Spjd		return;
589148456Spjd	}
590148456Spjd
591148456Spjd	eli_metadata_encode(&md, sector);
592148456Spjd	bzero(&md, sizeof(md));
593148456Spjd	error = g_metadata_store(prov, sector, sizeof(sector));
594148456Spjd	bzero(sector, sizeof(sector));
595148456Spjd	if (error != 0) {
596148456Spjd		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
597148456Spjd		    strerror(error));
598148456Spjd		return;
599148456Spjd	}
600148456Spjd	if (verbose)
601148456Spjd		printf("Metadata value stored on %s.\n", prov);
602148456Spjd}
603148456Spjd
604148456Spjdstatic void
605148456Spjdeli_attach(struct gctl_req *req)
606148456Spjd{
607148456Spjd	struct g_eli_metadata md;
608148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
609148456Spjd	const char *prov;
610153190Spjd	int nargs;
611148456Spjd
612153190Spjd	nargs = gctl_get_int(req, "nargs");
613153190Spjd	if (nargs != 1) {
614148456Spjd		gctl_error(req, "Too few arguments.");
615148456Spjd		return;
616148456Spjd	}
617153190Spjd	prov = gctl_get_ascii(req, "arg0");
618148456Spjd
619148456Spjd	if (eli_metadata_read(req, prov, &md) == -1)
620148456Spjd		return;
621148456Spjd
622148456Spjd	if (eli_genkey(req, &md, key, 0) == NULL) {
623148456Spjd		bzero(key, sizeof(key));
624148456Spjd		return;
625148456Spjd	}
626148456Spjd
627148456Spjd	gctl_ro_param(req, "key", sizeof(key), key);
628148456Spjd	if (gctl_issue(req) == NULL) {
629148456Spjd		if (verbose)
630148456Spjd			printf("Attched to %s.\n", prov);
631148456Spjd	}
632148456Spjd	bzero(key, sizeof(key));
633148456Spjd}
634148456Spjd
635148456Spjdstatic void
636155101Spjdeli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
637148456Spjd{
638148456Spjd	unsigned char key[G_ELI_USERKEYLEN];
639153190Spjd	intmax_t val;
640148456Spjd
641153190Spjd	val = gctl_get_intmax(req, "iterations");
642149304Spjd	/* Check if iterations number should be changed. */
643153190Spjd	if (val != -1)
644153190Spjd		md->md_iterations = val;
645148456Spjd
646148456Spjd	/* Generate key for Master Key encryption. */
647149304Spjd	if (eli_genkey(req, md, key, 1) == NULL) {
648148456Spjd		bzero(key, sizeof(key));
649148456Spjd		return;
650148456Spjd	}
651148456Spjd
652148456Spjd	gctl_ro_param(req, "key", sizeof(key), key);
653148456Spjd	gctl_issue(req);
654148456Spjd	bzero(key, sizeof(key));
655148456Spjd}
656148456Spjd
657148456Spjdstatic void
658149304Spjdeli_setkey_detached(struct gctl_req *req, const char *prov,
659149304Spjd struct g_eli_metadata *md)
660148456Spjd{
661148456Spjd	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
662148456Spjd	unsigned char *mkeydst;
663153190Spjd	intmax_t val;
664148456Spjd	unsigned nkey;
665148456Spjd	int error;
666148456Spjd
667149928Spjd	if (md->md_keys == 0) {
668149928Spjd		gctl_error(req, "No valid keys on %s.", prov);
669149928Spjd		return;
670149928Spjd	}
671149928Spjd
672148456Spjd	/* Generate key for Master Key decryption. */
673149304Spjd	if (eli_genkey(req, md, key, 0) == NULL) {
674148456Spjd		bzero(key, sizeof(key));
675148456Spjd		return;
676148456Spjd	}
677148456Spjd
678148456Spjd	/* Decrypt Master Key. */
679149304Spjd	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
680148456Spjd	bzero(key, sizeof(key));
681148456Spjd	if (error != 0) {
682149304Spjd		bzero(md, sizeof(*md));
683148456Spjd		if (error == -1)
684148456Spjd			gctl_error(req, "Wrong key for %s.", prov);
685148456Spjd		else /* if (error > 0) */ {
686148456Spjd			gctl_error(req, "Cannot decrypt Master Key: %s.",
687148456Spjd			    strerror(error));
688148456Spjd		}
689148456Spjd		return;
690148456Spjd	}
691148456Spjd	if (verbose)
692148456Spjd		printf("Decrypted Master Key %u.\n", nkey);
693148456Spjd
694153190Spjd	val = gctl_get_intmax(req, "keyno");
695153190Spjd	if (val != -1)
696153190Spjd		nkey = val;
697148456Spjd#if 0
698148456Spjd	else
699148456Spjd		; /* Use the key number which was found during decryption. */
700148456Spjd#endif
701148456Spjd	if (nkey >= G_ELI_MAXMKEYS) {
702148456Spjd		gctl_error(req, "Invalid '%s' argument.", "keyno");
703148456Spjd		return;
704148456Spjd	}
705148456Spjd
706153190Spjd	val = gctl_get_intmax(req, "iterations");
707149304Spjd	/* Check if iterations number should and can be changed. */
708153190Spjd	if (val != -1) {
709149304Spjd		if (bitcount32(md->md_keys) != 1) {
710149304Spjd			gctl_error(req, "To be able to use '-i' option, only "
711149304Spjd			    "one key can be defined.");
712149304Spjd			return;
713149304Spjd		}
714149304Spjd		if (md->md_keys != (1 << nkey)) {
715149304Spjd			gctl_error(req, "Only already defined key can be "
716149304Spjd			    "changed when '-i' option is used.");
717149304Spjd			return;
718149304Spjd		}
719153190Spjd		md->md_iterations = val;
720149304Spjd	}
721148456Spjd
722149304Spjd	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
723149304Spjd	md->md_keys |= (1 << nkey);
724149304Spjd
725148456Spjd	bcopy(mkey, mkeydst, sizeof(mkey));
726148456Spjd	bzero(mkey, sizeof(mkey));
727148456Spjd
728148456Spjd	/* Generate key for Master Key encryption. */
729149304Spjd	if (eli_genkey(req, md, key, 1) == NULL) {
730148456Spjd		bzero(key, sizeof(key));
731149304Spjd		bzero(md, sizeof(*md));
732148456Spjd		return;
733148456Spjd	}
734148456Spjd
735148456Spjd	/* Encrypt the Master-Key with the new key. */
736149304Spjd	error = g_eli_mkey_encrypt(md->md_algo, key, md->md_keylen, mkeydst);
737148456Spjd	bzero(key, sizeof(key));
738148456Spjd	if (error != 0) {
739149304Spjd		bzero(md, sizeof(*md));
740148456Spjd		gctl_error(req, "Cannot encrypt Master Key: %s.",
741148456Spjd		    strerror(error));
742148456Spjd		return;
743148456Spjd	}
744148456Spjd
745148456Spjd	/* Store metadata with fresh key. */
746149304Spjd	eli_metadata_store(req, prov, md);
747149304Spjd	bzero(md, sizeof(*md));
748148456Spjd}
749148456Spjd
750148456Spjdstatic void
751148456Spjdeli_setkey(struct gctl_req *req)
752148456Spjd{
753149304Spjd	struct g_eli_metadata md;
754148456Spjd	const char *prov;
755153190Spjd	int nargs;
756148456Spjd
757153190Spjd	nargs = gctl_get_int(req, "nargs");
758153190Spjd	if (nargs != 1) {
759148456Spjd		gctl_error(req, "Too few arguments.");
760148456Spjd		return;
761148456Spjd	}
762153190Spjd	prov = gctl_get_ascii(req, "arg0");
763148456Spjd
764149304Spjd	if (eli_metadata_read(req, prov, &md) == -1)
765149304Spjd		return;
766149304Spjd
767148456Spjd	if (eli_is_attached(prov))
768155101Spjd		eli_setkey_attached(req, &md);
769148456Spjd	else
770149304Spjd		eli_setkey_detached(req, prov, &md);
771148456Spjd}
772148456Spjd
773148456Spjdstatic void
774148456Spjdeli_delkey_attached(struct gctl_req *req, const char *prov __unused)
775148456Spjd{
776148456Spjd
777148456Spjd	gctl_issue(req);
778148456Spjd}
779148456Spjd
780148456Spjdstatic void
781148456Spjdeli_delkey_detached(struct gctl_req *req, const char *prov)
782148456Spjd{
783148456Spjd	struct g_eli_metadata md;
784148456Spjd	unsigned char *mkeydst;
785153190Spjd	intmax_t val;
786148456Spjd	unsigned nkey;
787153190Spjd	int all, force;
788148456Spjd
789148456Spjd	if (eli_metadata_read(req, prov, &md) == -1)
790148456Spjd		return;
791148456Spjd
792153190Spjd	all = gctl_get_int(req, "all");
793153190Spjd	if (all)
794148456Spjd		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
795148456Spjd	else {
796153190Spjd		force = gctl_get_int(req, "force");
797153190Spjd		val = gctl_get_intmax(req, "keyno");
798153190Spjd		if (val == -1) {
799148456Spjd			gctl_error(req, "Key number has to be specified.");
800148456Spjd			return;
801148456Spjd		}
802153190Spjd		nkey = val;
803148456Spjd		if (nkey >= G_ELI_MAXMKEYS) {
804148456Spjd			gctl_error(req, "Invalid '%s' argument.", "keyno");
805148456Spjd			return;
806148456Spjd		}
807153190Spjd		if (!(md.md_keys & (1 << nkey)) && !force) {
808148456Spjd			gctl_error(req, "Master Key %u is not set.", nkey);
809148456Spjd			return;
810148456Spjd		}
811148456Spjd		md.md_keys &= ~(1 << nkey);
812153190Spjd		if (md.md_keys == 0 && !force) {
813148456Spjd			gctl_error(req, "This is the last Master Key. Use '-f' "
814148456Spjd			    "option if you really want to remove it.");
815148456Spjd			return;
816148456Spjd		}
817148456Spjd		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
818148456Spjd		arc4rand(mkeydst, G_ELI_MKEYLEN);
819148456Spjd	}
820148456Spjd
821148456Spjd	eli_metadata_store(req, prov, &md);
822148456Spjd	bzero(&md, sizeof(md));
823148456Spjd}
824148456Spjd
825148456Spjdstatic void
826148456Spjdeli_delkey(struct gctl_req *req)
827148456Spjd{
828148456Spjd	const char *prov;
829153190Spjd	int nargs;
830148456Spjd
831153190Spjd	nargs = gctl_get_int(req, "nargs");
832153190Spjd	if (nargs != 1) {
833148456Spjd		gctl_error(req, "Too few arguments.");
834148456Spjd		return;
835148456Spjd	}
836153190Spjd	prov = gctl_get_ascii(req, "arg0");
837148456Spjd
838148456Spjd	if (eli_is_attached(prov))
839148456Spjd		eli_delkey_attached(req, prov);
840148456Spjd	else
841148456Spjd		eli_delkey_detached(req, prov);
842148456Spjd}
843148456Spjd
844148456Spjdstatic void
845148456Spjdeli_kill_detached(struct gctl_req *req, const char *prov)
846148456Spjd{
847148456Spjd	struct g_eli_metadata md;
848148456Spjd	int error;
849148456Spjd
850148456Spjd	/*
851148456Spjd	 * NOTE: Maybe we should verify if this is geli provider first,
852148456Spjd	 *       but 'kill' command is quite critical so better don't waste
853148456Spjd	 *       the time.
854148456Spjd	 */
855148456Spjd#if 0
856148456Spjd	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
857148456Spjd	    G_ELI_MAGIC);
858148456Spjd	if (error != 0) {
859148456Spjd		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
860148456Spjd		    strerror(error));
861148456Spjd		return;
862148456Spjd	}
863148456Spjd#endif
864148456Spjd
865148456Spjd	arc4rand((unsigned char *)&md, sizeof(md));
866148456Spjd	error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
867148456Spjd	if (error != 0) {
868148456Spjd		gctl_error(req, "Cannot write metadata to %s: %s.", prov,
869148456Spjd		    strerror(error));
870148456Spjd	}
871148456Spjd}
872148456Spjd
873148456Spjdstatic void
874148456Spjdeli_kill(struct gctl_req *req)
875148456Spjd{
876148456Spjd	const char *prov;
877153190Spjd	int i, nargs, all;
878148456Spjd
879153190Spjd	nargs = gctl_get_int(req, "nargs");
880153190Spjd	all = gctl_get_int(req, "all");
881153190Spjd	if (!all && nargs == 0) {
882148456Spjd		gctl_error(req, "Too few arguments.");
883148456Spjd		return;
884148456Spjd	}
885148456Spjd	/*
886148456Spjd	 * How '-a' option combine with a list of providers:
887148456Spjd	 * Delete Master Keys from all attached providers:
888148456Spjd	 * geli kill -a
889148456Spjd	 * Delete Master Keys from all attached provider and from
890148456Spjd	 * detached da0 and da1:
891148456Spjd	 * geli kill -a da0 da1
892148456Spjd	 * Delete Master Keys from (attached or detached) da0 and da1:
893148456Spjd	 * geli kill da0 da1
894148456Spjd	 */
895148456Spjd
896148456Spjd	/*
897148456Spjd	 * First attached providers.
898148456Spjd	 */
899148456Spjd	gctl_issue(req);
900148456Spjd	/*
901148456Spjd	 * Now the rest.
902148456Spjd	 */
903153190Spjd	for (i = 0; i < nargs; i++) {
904153190Spjd		prov = gctl_get_ascii(req, "arg%d", i);
905148456Spjd		if (!eli_is_attached(prov))
906148456Spjd			eli_kill_detached(req, prov);
907148456Spjd	}
908148456Spjd}
909148456Spjd
910148456Spjdstatic void
911148456Spjdeli_backup(struct gctl_req *req)
912148456Spjd{
913148456Spjd	struct g_eli_metadata md;
914148456Spjd	const char *file, *prov;
915148456Spjd	unsigned secsize;
916148456Spjd	unsigned char *sector;
917148456Spjd	off_t mediasize;
918153190Spjd	int nargs, filefd, provfd;
919148456Spjd
920153190Spjd	nargs = gctl_get_int(req, "nargs");
921153190Spjd	if (nargs != 2) {
922148456Spjd		gctl_error(req, "Invalid number of arguments.");
923148456Spjd		return;
924148456Spjd	}
925153190Spjd	prov = gctl_get_ascii(req, "arg0");
926153190Spjd	file = gctl_get_ascii(req, "arg1");
927148456Spjd
928148456Spjd	provfd = filefd = -1;
929148456Spjd	sector = NULL;
930148456Spjd	secsize = 0;
931148456Spjd
932148456Spjd	provfd = open(prov, O_RDONLY);
933148456Spjd	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
934148456Spjd		char devprov[MAXPATHLEN];
935148456Spjd
936148456Spjd		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
937148456Spjd		provfd = open(devprov, O_RDONLY);
938148456Spjd	}
939148456Spjd	if (provfd == -1) {
940148456Spjd		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
941148456Spjd		return;
942148456Spjd	}
943148456Spjd	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
944148456Spjd	if (filefd == -1) {
945148456Spjd		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
946148456Spjd		goto out;
947148456Spjd	}
948148456Spjd
949148456Spjd	mediasize = g_get_mediasize(prov);
950148456Spjd	secsize = g_get_sectorsize(prov);
951148456Spjd	if (mediasize == 0 || secsize == 0) {
952148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
953148456Spjd		    strerror(errno));
954148456Spjd		return;
955148456Spjd	}
956148456Spjd
957148456Spjd	sector = malloc(secsize);
958148456Spjd	if (sector == NULL) {
959148456Spjd		gctl_error(req, "Cannot allocate memory.");
960148456Spjd		return;
961148456Spjd	}
962148456Spjd
963148456Spjd	/* Read metadata from the provider. */
964148456Spjd	if (pread(provfd, sector, secsize, mediasize - secsize) !=
965148456Spjd	    (ssize_t)secsize) {
966148456Spjd		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
967148456Spjd		goto out;
968148456Spjd	}
969148456Spjd	/* Check if this is geli provider. */
970148456Spjd	if (eli_metadata_decode(sector, &md) != 0) {
971148456Spjd		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
972148456Spjd		goto out;
973148456Spjd	}
974148456Spjd	/* Write metadata to the destination file. */
975148456Spjd	if (write(filefd, sector, secsize) != (ssize_t)secsize) {
976148456Spjd		gctl_error(req, "Cannot write to %s: %s.", file,
977148456Spjd		    strerror(errno));
978148456Spjd		goto out;
979148456Spjd	}
980148456Spjdout:
981148456Spjd	if (provfd > 0)
982148456Spjd		close(provfd);
983148456Spjd	if (filefd > 0)
984148456Spjd		close(filefd);
985148456Spjd	if (sector != NULL) {
986148456Spjd		bzero(sector, secsize);
987148456Spjd		free(sector);
988148456Spjd	}
989148456Spjd}
990148456Spjd
991148456Spjdstatic void
992148456Spjdeli_restore(struct gctl_req *req)
993148456Spjd{
994148456Spjd	struct g_eli_metadata md;
995148456Spjd	const char *file, *prov;
996148456Spjd	unsigned char *sector;
997148456Spjd	unsigned secsize;
998148456Spjd	off_t mediasize;
999153190Spjd	int nargs, filefd, provfd;
1000148456Spjd
1001153190Spjd	nargs = gctl_get_int(req, "nargs");
1002153190Spjd	if (nargs != 2) {
1003148456Spjd		gctl_error(req, "Invalid number of arguments.");
1004148456Spjd		return;
1005148456Spjd	}
1006153190Spjd	file = gctl_get_ascii(req, "arg0");
1007153190Spjd	prov = gctl_get_ascii(req, "arg1");
1008148456Spjd
1009148456Spjd	provfd = filefd = -1;
1010148456Spjd	sector = NULL;
1011148456Spjd	secsize = 0;
1012148456Spjd
1013148456Spjd	filefd = open(file, O_RDONLY);
1014148456Spjd	if (filefd == -1) {
1015148456Spjd		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1016148456Spjd		goto out;
1017148456Spjd	}
1018148456Spjd	provfd = open(prov, O_WRONLY);
1019148456Spjd	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1020148456Spjd		char devprov[MAXPATHLEN];
1021148456Spjd
1022148456Spjd		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1023148456Spjd		provfd = open(devprov, O_WRONLY);
1024148456Spjd	}
1025148456Spjd	if (provfd == -1) {
1026148456Spjd		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1027148456Spjd		return;
1028148456Spjd	}
1029148456Spjd
1030148456Spjd	mediasize = g_get_mediasize(prov);
1031148456Spjd	secsize = g_get_sectorsize(prov);
1032148456Spjd	if (mediasize == 0 || secsize == 0) {
1033148456Spjd		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1034148456Spjd		    strerror(errno));
1035148456Spjd		return;
1036148456Spjd	}
1037148456Spjd
1038148456Spjd	sector = malloc(secsize);
1039148456Spjd	if (sector == NULL) {
1040148456Spjd		gctl_error(req, "Cannot allocate memory.");
1041148456Spjd		return;
1042148456Spjd	}
1043148456Spjd
1044148456Spjd	/* Read metadata from the backup file. */
1045148456Spjd	if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1046148456Spjd		gctl_error(req, "Cannot read from %s: %s.", file,
1047148456Spjd		    strerror(errno));
1048148456Spjd		goto out;
1049148456Spjd	}
1050148456Spjd	/* Check if this file contains geli metadata. */
1051148456Spjd	if (eli_metadata_decode(sector, &md) != 0) {
1052148456Spjd		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1053148456Spjd		goto out;
1054148456Spjd	}
1055148456Spjd	/* Read metadata from the provider. */
1056148456Spjd	if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1057148456Spjd	    (ssize_t)secsize) {
1058148456Spjd		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1059148456Spjd		goto out;
1060148456Spjd	}
1061148456Spjdout:
1062148456Spjd	if (provfd > 0)
1063148456Spjd		close(provfd);
1064148456Spjd	if (filefd > 0)
1065148456Spjd		close(filefd);
1066148456Spjd	if (sector != NULL) {
1067148456Spjd		bzero(sector, secsize);
1068148456Spjd		free(sector);
1069148456Spjd	}
1070148456Spjd}
1071148456Spjd
1072148456Spjdstatic void
1073148456Spjdeli_clear(struct gctl_req *req)
1074148456Spjd{
1075148456Spjd	const char *name;
1076153190Spjd	int error, i, nargs;
1077148456Spjd
1078153190Spjd	nargs = gctl_get_int(req, "nargs");
1079153190Spjd	if (nargs < 1) {
1080148456Spjd		gctl_error(req, "Too few arguments.");
1081148456Spjd		return;
1082148456Spjd	}
1083148456Spjd
1084153190Spjd	for (i = 0; i < nargs; i++) {
1085153190Spjd		name = gctl_get_ascii(req, "arg%d", i);
1086148456Spjd		error = g_metadata_clear(name, G_ELI_MAGIC);
1087148456Spjd		if (error != 0) {
1088148456Spjd			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1089148456Spjd			    name, strerror(error));
1090148456Spjd			gctl_error(req, "Not fully done.");
1091148456Spjd			continue;
1092148456Spjd		}
1093148456Spjd		if (verbose)
1094155175Spjd			printf("Metadata cleared on %s.\n", name);
1095148456Spjd	}
1096148456Spjd}
1097148456Spjd
1098148456Spjdstatic void
1099148456Spjdeli_dump(struct gctl_req *req)
1100148456Spjd{
1101148456Spjd	struct g_eli_metadata md, tmpmd;
1102148456Spjd	const char *name;
1103153190Spjd	int error, i, nargs;
1104148456Spjd
1105153190Spjd	nargs = gctl_get_int(req, "nargs");
1106153190Spjd	if (nargs < 1) {
1107148456Spjd		gctl_error(req, "Too few arguments.");
1108148456Spjd		return;
1109148456Spjd	}
1110148456Spjd
1111153190Spjd	for (i = 0; i < nargs; i++) {
1112153190Spjd		name = gctl_get_ascii(req, "arg%d", i);
1113148456Spjd		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1114148456Spjd		    sizeof(tmpmd), G_ELI_MAGIC);
1115148456Spjd		if (error != 0) {
1116148456Spjd			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1117148456Spjd			    name, strerror(error));
1118148456Spjd			gctl_error(req, "Not fully done.");
1119148456Spjd			continue;
1120148456Spjd		}
1121148456Spjd		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1122148456Spjd			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1123148456Spjd			    name);
1124148456Spjd			gctl_error(req, "Not fully done.");
1125148456Spjd			continue;
1126148456Spjd		}
1127148456Spjd		printf("Metadata on %s:\n", name);
1128148456Spjd		eli_metadata_dump(&md);
1129148456Spjd		printf("\n");
1130148456Spjd	}
1131148456Spjd}
1132