geom_eli.c revision 161052
1/*-
2 * Copyright (c) 2004 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 161052 2006-08-07 20:09:09Z pjd $");
29
30#include <stdio.h>
31#include <stdint.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <readpassphrase.h>
36#include <string.h>
37#include <strings.h>
38#include <libgeom.h>
39#include <paths.h>
40#include <errno.h>
41#include <assert.h>
42
43#include <sys/param.h>
44#include <sys/mman.h>
45#include <sys/resource.h>
46#include <opencrypto/cryptodev.h>
47#include <geom/eli/g_eli.h>
48#include <geom/eli/pkcs5v2.h>
49
50#include "core/geom.h"
51#include "misc/subr.h"
52
53
54uint32_t lib_version = G_LIB_VERSION;
55uint32_t version = G_ELI_VERSION;
56
57static char aalgo[] = "none";
58static char ealgo[] = "aes";
59static intmax_t keylen = 0;
60static intmax_t keyno = -1;
61static intmax_t iterations = -1;
62static intmax_t sectorsize = 0;
63static char keyfile[] = "", newkeyfile[] = "";
64
65static void eli_main(struct gctl_req *req, unsigned flags);
66static void eli_init(struct gctl_req *req);
67static void eli_attach(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_clear(struct gctl_req *req);
74static void eli_dump(struct gctl_req *req);
75
76/*
77 * Available commands:
78 *
79 * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
80 * label - alias for 'init'
81 * attach [-dpv] [-k keyfile] prov
82 * detach [-fl] prov ...
83 * stop - alias for 'detach'
84 * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
85 * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
86 * delkey [-afv] [-n keyno] prov
87 * kill [-av] [prov ...]
88 * backup [-v] prov file
89 * restore [-v] file prov
90 * clear [-v] prov ...
91 * dump [-v] prov ...
92 */
93struct g_command class_commands[] = {
94	{ "init", G_FLAG_VERBOSE, eli_main,
95	    {
96		{ 'a', "aalgo", aalgo, G_TYPE_STRING },
97		{ 'b', "boot", NULL, G_TYPE_NONE },
98		{ 'e', "ealgo", ealgo, G_TYPE_STRING },
99		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
100		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
101		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
102		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
103		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
104		G_OPT_SENTINEL
105	    },
106	    "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
107	},
108	{ "label", G_FLAG_VERBOSE, eli_main,
109	    {
110		{ 'a', "aalgo", aalgo, G_TYPE_STRING },
111		{ 'b', "boot", NULL, G_TYPE_NONE },
112		{ 'e', "ealgo", ealgo, G_TYPE_STRING },
113		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
114		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
115		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
116		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
117		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
118		G_OPT_SENTINEL
119	    },
120	    "- an alias for 'init'"
121	},
122	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
123	    {
124		{ 'd', "detach", NULL, G_TYPE_NONE },
125		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
126		{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
127		G_OPT_SENTINEL
128	    },
129	    "[-dpv] [-k keyfile] prov"
130	},
131	{ "detach", 0, NULL,
132	    {
133		{ 'f', "force", NULL, G_TYPE_NONE },
134		{ 'l', "last", NULL, G_TYPE_NONE },
135		G_OPT_SENTINEL
136	    },
137	    "[-fl] prov ..."
138	},
139	{ "stop", 0, NULL,
140	    {
141		{ 'f', "force", NULL, G_TYPE_NONE },
142		{ 'l', "last", NULL, G_TYPE_NONE },
143		G_OPT_SENTINEL
144	    },
145	    "- an alias for 'detach'"
146	},
147	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
148	    {
149		{ 'a', "aalgo", aalgo, G_TYPE_STRING },
150		{ 'd', "detach", NULL, G_TYPE_NONE },
151		{ 'e', "ealgo", ealgo, G_TYPE_STRING },
152		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
153		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
154		G_OPT_SENTINEL
155	    },
156	    "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..."
157	},
158	{ "setkey", G_FLAG_VERBOSE, eli_main,
159	    {
160		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
161		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
162		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
163		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
164		{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
165		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
166		G_OPT_SENTINEL
167	    },
168	    "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
169	},
170	{ "delkey", G_FLAG_VERBOSE, eli_main,
171	    {
172		{ 'a', "all", NULL, G_TYPE_NONE },
173		{ 'f', "force", NULL, G_TYPE_NONE },
174		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
175		G_OPT_SENTINEL
176	    },
177	    "[-afv] [-n keyno] prov"
178	},
179	{ "kill", G_FLAG_VERBOSE, eli_main,
180	    {
181		{ 'a', "all", NULL, G_TYPE_NONE },
182		G_OPT_SENTINEL
183	    },
184	    "[-av] [prov ...]"
185	},
186	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
187	    "[-v] prov file"
188	},
189	{ "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
190	    "[-v] file prov"
191	},
192	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
193	    "[-v] prov ..."
194	},
195	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
196	    "[-v] prov ..."
197	},
198	G_CMD_SENTINEL
199};
200
201static int verbose = 0;
202
203static int
204eli_protect(struct gctl_req *req)
205{
206	struct rlimit rl;
207
208	/* Disable core dumps. */
209	rl.rlim_cur = 0;
210	rl.rlim_max = 0;
211	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
212		gctl_error(req, "Cannot disable core dumps: %s.",
213		    strerror(errno));
214		return (-1);
215	}
216	/* Disable swapping. */
217	if (mlockall(MCL_FUTURE) == -1) {
218		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
219		return (-1);
220	}
221	return (0);
222}
223
224static void
225eli_main(struct gctl_req *req, unsigned flags)
226{
227	const char *name;
228
229	if (eli_protect(req) == -1)
230		return;
231
232	if ((flags & G_FLAG_VERBOSE) != 0)
233		verbose = 1;
234
235	name = gctl_get_ascii(req, "verb");
236	if (name == NULL) {
237		gctl_error(req, "No '%s' argument.", "verb");
238		return;
239	}
240	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
241		eli_init(req);
242	else if (strcmp(name, "attach") == 0)
243		eli_attach(req);
244	else if (strcmp(name, "setkey") == 0)
245		eli_setkey(req);
246	else if (strcmp(name, "delkey") == 0)
247		eli_delkey(req);
248	else if (strcmp(name, "kill") == 0)
249		eli_kill(req);
250	else if (strcmp(name, "backup") == 0)
251		eli_backup(req);
252	else if (strcmp(name, "restore") == 0)
253		eli_restore(req);
254	else if (strcmp(name, "dump") == 0)
255		eli_dump(req);
256	else if (strcmp(name, "clear") == 0)
257		eli_clear(req);
258	else
259		gctl_error(req, "Unknown command: %s.", name);
260}
261
262static void
263arc4rand(unsigned char *buf, size_t size)
264{
265	uint32_t *buf4;
266	size_t size4;
267	unsigned i;
268
269	buf4 = (uint32_t *)buf;
270	size4 = size / 4;
271
272	for (i = 0; i < size4; i++)
273		buf4[i] = arc4random();
274	for (i *= 4; i < size; i++)
275		buf[i] = arc4random() % 0xff;
276}
277
278static int
279eli_is_attached(const char *prov)
280{
281	char name[MAXPATHLEN];
282	unsigned secsize;
283
284	/*
285	 * Not the best way to do it, but the easiest.
286	 * We try to open provider and check if it is a GEOM provider
287	 * by asking about its sectorsize.
288	 */
289	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
290	secsize = g_get_sectorsize(name);
291	if (secsize > 0)
292		return (1);
293	return (0);
294}
295
296static unsigned char *
297eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
298    int new)
299{
300	struct hmac_ctx ctx;
301	const char *str;
302	int error, nopassphrase;
303
304	nopassphrase =
305	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
306
307	g_eli_crypto_hmac_init(&ctx, NULL, 0);
308
309	str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
310	if (str[0] == '\0' && nopassphrase) {
311		gctl_error(req, "No key components given.");
312		return (NULL);
313	} else if (str[0] != '\0') {
314		char buf[MAXPHYS];
315		ssize_t done;
316		int fd;
317
318		if (strcmp(str, "-") == 0)
319			fd = STDIN_FILENO;
320		else {
321			fd = open(str, O_RDONLY);
322			if (fd == -1) {
323				gctl_error(req, "Cannot open keyfile %s: %s.",
324				    str, strerror(errno));
325				return (NULL);
326			}
327		}
328		while ((done = read(fd, buf, sizeof(buf))) > 0)
329			g_eli_crypto_hmac_update(&ctx, buf, done);
330		error = errno;
331		if (strcmp(str, "-") != 0)
332			close(fd);
333		bzero(buf, sizeof(buf));
334		if (done == -1) {
335			gctl_error(req, "Cannot read keyfile %s: %s.", str,
336			    strerror(error));
337			return (NULL);
338		}
339	}
340
341	if (!nopassphrase) {
342		char buf1[BUFSIZ], buf2[BUFSIZ], *p;
343
344		if (!new && md->md_iterations == -1) {
345			gctl_error(req, "Missing -p flag.");
346			return (NULL);
347		}
348		for (;;) {
349			p = readpassphrase(
350			    new ? "Enter new passphrase:" : "Enter passphrase:",
351			    buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
352			if (p == NULL) {
353				bzero(buf1, sizeof(buf1));
354				gctl_error(req, "Cannot read passphrase: %s.",
355				    strerror(errno));
356				return (NULL);
357			}
358
359			if (new) {
360				p = readpassphrase("Reenter new passphrase: ",
361				    buf2, sizeof(buf2),
362				    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
363				if (p == NULL) {
364					bzero(buf1, sizeof(buf1));
365					gctl_error(req,
366					    "Cannot read passphrase: %s.",
367					    strerror(errno));
368					return (NULL);
369				}
370
371				if (strcmp(buf1, buf2) != 0) {
372					bzero(buf2, sizeof(buf2));
373					fprintf(stderr, "They didn't match.\n");
374					continue;
375				}
376				bzero(buf2, sizeof(buf2));
377			}
378			break;
379		}
380		/*
381		 * Field md_iterations equal to -1 means "choose some sane
382		 * value for me".
383		 */
384		if (md->md_iterations == -1) {
385			assert(new);
386			if (verbose)
387				printf("Calculating number of iterations...\n");
388			md->md_iterations = pkcs5v2_calculate(2000000);
389			assert(md->md_iterations > 0);
390			if (verbose) {
391				printf("Done, using %d iterations.\n",
392				    md->md_iterations);
393			}
394		}
395		/*
396		 * If md_iterations is equal to 0, user don't want PKCS#5v2.
397		 */
398		if (md->md_iterations == 0) {
399			g_eli_crypto_hmac_update(&ctx, md->md_salt,
400			    sizeof(md->md_salt));
401			g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
402		} else /* if (md->md_iterations > 0) */ {
403			unsigned char dkey[G_ELI_USERKEYLEN];
404
405			pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
406			    sizeof(md->md_salt), buf1, md->md_iterations);
407			g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
408			bzero(dkey, sizeof(dkey));
409		}
410		bzero(buf1, sizeof(buf1));
411	}
412	g_eli_crypto_hmac_final(&ctx, key, 0);
413	return (key);
414}
415
416static int
417eli_metadata_read(struct gctl_req *req, const char *prov,
418    struct g_eli_metadata *md)
419{
420	unsigned char sector[sizeof(struct g_eli_metadata)];
421	int error;
422
423	if (g_get_sectorsize(prov) == 0) {
424		int fd;
425
426		/* This is a file probably. */
427		fd = open(prov, O_RDONLY);
428		if (fd == -1) {
429			gctl_error(req, "Cannot open %s: %s.", prov,
430			    strerror(errno));
431			return (-1);
432		}
433		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
434			gctl_error(req, "Cannot read metadata from %s: %s.",
435			    prov, strerror(errno));
436			close(fd);
437			return (-1);
438		}
439		close(fd);
440	} else {
441		/* This is a GEOM provider. */
442		error = g_metadata_read(prov, sector, sizeof(sector),
443		    G_ELI_MAGIC);
444		if (error != 0) {
445			gctl_error(req, "Cannot read metadata from %s: %s.",
446			    prov, strerror(error));
447			return (-1);
448		}
449	}
450	if (eli_metadata_decode(sector, md) != 0) {
451		gctl_error(req, "MD5 hash mismatch for %s.", prov);
452		return (-1);
453	}
454	return (0);
455}
456
457static int
458eli_metadata_store(struct gctl_req *req, const char *prov,
459    struct g_eli_metadata *md)
460{
461	unsigned char sector[sizeof(struct g_eli_metadata)];
462	int error;
463
464	eli_metadata_encode(md, sector);
465	if (g_get_sectorsize(prov) == 0) {
466		int fd;
467
468		/* This is a file probably. */
469		fd = open(prov, O_WRONLY | O_TRUNC);
470		if (fd == -1) {
471			gctl_error(req, "Cannot open %s: %s.", prov,
472			    strerror(errno));
473			bzero(sector, sizeof(sector));
474			return (-1);
475		}
476		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
477			gctl_error(req, "Cannot write metadata to %s: %s.",
478			    prov, strerror(errno));
479			bzero(sector, sizeof(sector));
480			close(fd);
481			return (-1);
482		}
483		close(fd);
484	} else {
485		/* This is a GEOM provider. */
486		error = g_metadata_store(prov, sector, sizeof(sector));
487		if (error != 0) {
488			gctl_error(req, "Cannot write metadata to %s: %s.",
489			    prov, strerror(errno));
490			bzero(sector, sizeof(sector));
491			return (-1);
492		}
493	}
494	bzero(sector, sizeof(sector));
495	return (0);
496}
497
498static void
499eli_init(struct gctl_req *req)
500{
501	struct g_eli_metadata md;
502	unsigned char sector[sizeof(struct g_eli_metadata)];
503	unsigned char key[G_ELI_USERKEYLEN];
504	const char *str, *prov;
505	unsigned secsize;
506	off_t mediasize;
507	intmax_t val;
508	int error, nargs;
509
510	nargs = gctl_get_int(req, "nargs");
511	if (nargs != 1) {
512		gctl_error(req, "Invalid number of arguments.");
513		return;
514	}
515	prov = gctl_get_ascii(req, "arg0");
516	mediasize = g_get_mediasize(prov);
517	secsize = g_get_sectorsize(prov);
518	if (mediasize == 0 || secsize == 0) {
519		gctl_error(req, "Cannot get informations about %s: %s.", prov,
520		    strerror(errno));
521		return;
522	}
523
524	bzero(&md, sizeof(md));
525	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
526	md.md_version = G_ELI_VERSION;
527	md.md_flags = 0;
528	if (gctl_get_int(req, "boot"))
529		md.md_flags |= G_ELI_FLAG_BOOT;
530	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
531	str = gctl_get_ascii(req, "aalgo");
532	if (strcmp(str, "none") != 0) {
533		md.md_aalgo = g_eli_str2aalgo(str);
534		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
535		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
536			md.md_flags |= G_ELI_FLAG_AUTH;
537		} else {
538			/*
539			 * For backward compatibility, check if the -a option
540			 * was used to provide encryption algorithm.
541			 */
542			md.md_ealgo = g_eli_str2ealgo(str);
543			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
544			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
545				gctl_error(req,
546				    "Invalid authentication algorithm.");
547				return;
548			} else {
549				fprintf(stderr, "warning: The -e option, not "
550				    "the -a option is now used to specify "
551				    "encryption algorithm to use.\n");
552			}
553		}
554	}
555	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
556	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
557		str = gctl_get_ascii(req, "ealgo");
558		md.md_ealgo = g_eli_str2ealgo(str);
559		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
560		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
561			gctl_error(req, "Invalid encryption algorithm.");
562			return;
563		}
564	}
565	val = gctl_get_intmax(req, "keylen");
566	md.md_keylen = val;
567	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
568	if (md.md_keylen == 0) {
569		gctl_error(req, "Invalid key length.");
570		return;
571	}
572	md.md_provsize = mediasize;
573
574	val = gctl_get_intmax(req, "iterations");
575	if (val != -1) {
576		int nonewpassphrase;
577
578		/*
579		 * Don't allow to set iterations when there will be no
580		 * passphrase.
581		 */
582		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
583		if (nonewpassphrase) {
584			gctl_error(req,
585			    "Options -i and -P are mutually exclusive.");
586			return;
587		}
588	}
589	md.md_iterations = val;
590
591	val = gctl_get_intmax(req, "sectorsize");
592	if (val == 0)
593		md.md_sectorsize = secsize;
594	else {
595		if (val < 0 || (val % secsize) != 0) {
596			gctl_error(req, "Invalid sector size.");
597			return;
598		}
599		md.md_sectorsize = val;
600	}
601
602	md.md_keys = 0x01;
603	arc4rand(md.md_salt, sizeof(md.md_salt));
604	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
605
606	/* Generate user key. */
607	if (eli_genkey(req, &md, key, 1) == NULL) {
608		bzero(key, sizeof(key));
609		bzero(&md, sizeof(md));
610		return;
611	}
612
613	/* Encrypt the first and the only Master Key. */
614	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
615	bzero(key, sizeof(key));
616	if (error != 0) {
617		bzero(&md, sizeof(md));
618		gctl_error(req, "Cannot encrypt Master Key: %s.",
619		    strerror(error));
620		return;
621	}
622
623	eli_metadata_encode(&md, sector);
624	bzero(&md, sizeof(md));
625	error = g_metadata_store(prov, sector, sizeof(sector));
626	bzero(sector, sizeof(sector));
627	if (error != 0) {
628		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
629		    strerror(error));
630		return;
631	}
632	if (verbose)
633		printf("Metadata value stored on %s.\n", prov);
634}
635
636static void
637eli_attach(struct gctl_req *req)
638{
639	struct g_eli_metadata md;
640	unsigned char key[G_ELI_USERKEYLEN];
641	const char *prov;
642	int nargs;
643
644	nargs = gctl_get_int(req, "nargs");
645	if (nargs != 1) {
646		gctl_error(req, "Invalid number of arguments.");
647		return;
648	}
649	prov = gctl_get_ascii(req, "arg0");
650
651	if (eli_metadata_read(req, prov, &md) == -1)
652		return;
653
654	if (eli_genkey(req, &md, key, 0) == NULL) {
655		bzero(key, sizeof(key));
656		return;
657	}
658
659	gctl_ro_param(req, "key", sizeof(key), key);
660	if (gctl_issue(req) == NULL) {
661		if (verbose)
662			printf("Attched to %s.\n", prov);
663	}
664	bzero(key, sizeof(key));
665}
666
667static void
668eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
669{
670	unsigned char key[G_ELI_USERKEYLEN];
671	intmax_t val;
672
673	val = gctl_get_intmax(req, "iterations");
674	/* Check if iterations number should be changed. */
675	if (val != -1)
676		md->md_iterations = val;
677
678	/* Generate key for Master Key encryption. */
679	if (eli_genkey(req, md, key, 1) == NULL) {
680		bzero(key, sizeof(key));
681		return;
682	}
683
684	gctl_ro_param(req, "key", sizeof(key), key);
685	gctl_issue(req);
686	bzero(key, sizeof(key));
687}
688
689static void
690eli_setkey_detached(struct gctl_req *req, const char *prov,
691 struct g_eli_metadata *md)
692{
693	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
694	unsigned char *mkeydst;
695	intmax_t val;
696	unsigned nkey;
697	int error;
698
699	if (md->md_keys == 0) {
700		gctl_error(req, "No valid keys on %s.", prov);
701		return;
702	}
703
704	/* Generate key for Master Key decryption. */
705	if (eli_genkey(req, md, key, 0) == NULL) {
706		bzero(key, sizeof(key));
707		return;
708	}
709
710	/* Decrypt Master Key. */
711	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
712	bzero(key, sizeof(key));
713	if (error != 0) {
714		bzero(md, sizeof(*md));
715		if (error == -1)
716			gctl_error(req, "Wrong key for %s.", prov);
717		else /* if (error > 0) */ {
718			gctl_error(req, "Cannot decrypt Master Key: %s.",
719			    strerror(error));
720		}
721		return;
722	}
723	if (verbose)
724		printf("Decrypted Master Key %u.\n", nkey);
725
726	val = gctl_get_intmax(req, "keyno");
727	if (val != -1)
728		nkey = val;
729#if 0
730	else
731		; /* Use the key number which was found during decryption. */
732#endif
733	if (nkey >= G_ELI_MAXMKEYS) {
734		gctl_error(req, "Invalid '%s' argument.", "keyno");
735		return;
736	}
737
738	val = gctl_get_intmax(req, "iterations");
739	/* Check if iterations number should and can be changed. */
740	if (val != -1) {
741		if (bitcount32(md->md_keys) != 1) {
742			gctl_error(req, "To be able to use '-i' option, only "
743			    "one key can be defined.");
744			return;
745		}
746		if (md->md_keys != (1 << nkey)) {
747			gctl_error(req, "Only already defined key can be "
748			    "changed when '-i' option is used.");
749			return;
750		}
751		md->md_iterations = val;
752	}
753
754	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
755	md->md_keys |= (1 << nkey);
756
757	bcopy(mkey, mkeydst, sizeof(mkey));
758	bzero(mkey, sizeof(mkey));
759
760	/* Generate key for Master Key encryption. */
761	if (eli_genkey(req, md, key, 1) == NULL) {
762		bzero(key, sizeof(key));
763		bzero(md, sizeof(*md));
764		return;
765	}
766
767	/* Encrypt the Master-Key with the new key. */
768	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
769	bzero(key, sizeof(key));
770	if (error != 0) {
771		bzero(md, sizeof(*md));
772		gctl_error(req, "Cannot encrypt Master Key: %s.",
773		    strerror(error));
774		return;
775	}
776
777	/* Store metadata with fresh key. */
778	eli_metadata_store(req, prov, md);
779	bzero(md, sizeof(*md));
780}
781
782static void
783eli_setkey(struct gctl_req *req)
784{
785	struct g_eli_metadata md;
786	const char *prov;
787	int nargs;
788
789	nargs = gctl_get_int(req, "nargs");
790	if (nargs != 1) {
791		gctl_error(req, "Invalid number of arguments.");
792		return;
793	}
794	prov = gctl_get_ascii(req, "arg0");
795
796	if (eli_metadata_read(req, prov, &md) == -1)
797		return;
798
799	if (eli_is_attached(prov))
800		eli_setkey_attached(req, &md);
801	else
802		eli_setkey_detached(req, prov, &md);
803}
804
805static void
806eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
807{
808
809	gctl_issue(req);
810}
811
812static void
813eli_delkey_detached(struct gctl_req *req, const char *prov)
814{
815	struct g_eli_metadata md;
816	unsigned char *mkeydst;
817	intmax_t val;
818	unsigned nkey;
819	int all, force;
820
821	if (eli_metadata_read(req, prov, &md) == -1)
822		return;
823
824	all = gctl_get_int(req, "all");
825	if (all)
826		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
827	else {
828		force = gctl_get_int(req, "force");
829		val = gctl_get_intmax(req, "keyno");
830		if (val == -1) {
831			gctl_error(req, "Key number has to be specified.");
832			return;
833		}
834		nkey = val;
835		if (nkey >= G_ELI_MAXMKEYS) {
836			gctl_error(req, "Invalid '%s' argument.", "keyno");
837			return;
838		}
839		if (!(md.md_keys & (1 << nkey)) && !force) {
840			gctl_error(req, "Master Key %u is not set.", nkey);
841			return;
842		}
843		md.md_keys &= ~(1 << nkey);
844		if (md.md_keys == 0 && !force) {
845			gctl_error(req, "This is the last Master Key. Use '-f' "
846			    "option if you really want to remove it.");
847			return;
848		}
849		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
850		arc4rand(mkeydst, G_ELI_MKEYLEN);
851	}
852
853	eli_metadata_store(req, prov, &md);
854	bzero(&md, sizeof(md));
855}
856
857static void
858eli_delkey(struct gctl_req *req)
859{
860	const char *prov;
861	int nargs;
862
863	nargs = gctl_get_int(req, "nargs");
864	if (nargs != 1) {
865		gctl_error(req, "Invalid number of arguments.");
866		return;
867	}
868	prov = gctl_get_ascii(req, "arg0");
869
870	if (eli_is_attached(prov))
871		eli_delkey_attached(req, prov);
872	else
873		eli_delkey_detached(req, prov);
874}
875
876static void
877eli_kill_detached(struct gctl_req *req, const char *prov)
878{
879	struct g_eli_metadata md;
880	int error;
881
882	/*
883	 * NOTE: Maybe we should verify if this is geli provider first,
884	 *       but 'kill' command is quite critical so better don't waste
885	 *       the time.
886	 */
887#if 0
888	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
889	    G_ELI_MAGIC);
890	if (error != 0) {
891		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
892		    strerror(error));
893		return;
894	}
895#endif
896
897	arc4rand((unsigned char *)&md, sizeof(md));
898	error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
899	if (error != 0) {
900		gctl_error(req, "Cannot write metadata to %s: %s.", prov,
901		    strerror(error));
902	}
903}
904
905static void
906eli_kill(struct gctl_req *req)
907{
908	const char *prov;
909	int i, nargs, all;
910
911	nargs = gctl_get_int(req, "nargs");
912	all = gctl_get_int(req, "all");
913	if (!all && nargs == 0) {
914		gctl_error(req, "Too few arguments.");
915		return;
916	}
917	/*
918	 * How '-a' option combine with a list of providers:
919	 * Delete Master Keys from all attached providers:
920	 * geli kill -a
921	 * Delete Master Keys from all attached provider and from
922	 * detached da0 and da1:
923	 * geli kill -a da0 da1
924	 * Delete Master Keys from (attached or detached) da0 and da1:
925	 * geli kill da0 da1
926	 */
927
928	/*
929	 * First attached providers.
930	 */
931	gctl_issue(req);
932	/*
933	 * Now the rest.
934	 */
935	for (i = 0; i < nargs; i++) {
936		prov = gctl_get_ascii(req, "arg%d", i);
937		if (!eli_is_attached(prov))
938			eli_kill_detached(req, prov);
939	}
940}
941
942static void
943eli_backup(struct gctl_req *req)
944{
945	struct g_eli_metadata md;
946	const char *file, *prov;
947	unsigned secsize;
948	unsigned char *sector;
949	off_t mediasize;
950	int nargs, filefd, provfd;
951
952	nargs = gctl_get_int(req, "nargs");
953	if (nargs != 2) {
954		gctl_error(req, "Invalid number of arguments.");
955		return;
956	}
957	prov = gctl_get_ascii(req, "arg0");
958	file = gctl_get_ascii(req, "arg1");
959
960	provfd = filefd = -1;
961	sector = NULL;
962	secsize = 0;
963
964	provfd = open(prov, O_RDONLY);
965	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
966		char devprov[MAXPATHLEN];
967
968		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
969		provfd = open(devprov, O_RDONLY);
970	}
971	if (provfd == -1) {
972		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
973		return;
974	}
975	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
976	if (filefd == -1) {
977		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
978		goto out;
979	}
980
981	mediasize = g_get_mediasize(prov);
982	secsize = g_get_sectorsize(prov);
983	if (mediasize == 0 || secsize == 0) {
984		gctl_error(req, "Cannot get informations about %s: %s.", prov,
985		    strerror(errno));
986		return;
987	}
988
989	sector = malloc(secsize);
990	if (sector == NULL) {
991		gctl_error(req, "Cannot allocate memory.");
992		return;
993	}
994
995	/* Read metadata from the provider. */
996	if (pread(provfd, sector, secsize, mediasize - secsize) !=
997	    (ssize_t)secsize) {
998		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
999		goto out;
1000	}
1001	/* Check if this is geli provider. */
1002	if (eli_metadata_decode(sector, &md) != 0) {
1003		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1004		goto out;
1005	}
1006	/* Write metadata to the destination file. */
1007	if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1008		gctl_error(req, "Cannot write to %s: %s.", file,
1009		    strerror(errno));
1010		goto out;
1011	}
1012out:
1013	if (provfd > 0)
1014		close(provfd);
1015	if (filefd > 0)
1016		close(filefd);
1017	if (sector != NULL) {
1018		bzero(sector, secsize);
1019		free(sector);
1020	}
1021}
1022
1023static void
1024eli_restore(struct gctl_req *req)
1025{
1026	struct g_eli_metadata md;
1027	const char *file, *prov;
1028	unsigned char *sector;
1029	unsigned secsize;
1030	off_t mediasize;
1031	int nargs, filefd, provfd;
1032
1033	nargs = gctl_get_int(req, "nargs");
1034	if (nargs != 2) {
1035		gctl_error(req, "Invalid number of arguments.");
1036		return;
1037	}
1038	file = gctl_get_ascii(req, "arg0");
1039	prov = gctl_get_ascii(req, "arg1");
1040
1041	provfd = filefd = -1;
1042	sector = NULL;
1043	secsize = 0;
1044
1045	filefd = open(file, O_RDONLY);
1046	if (filefd == -1) {
1047		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1048		goto out;
1049	}
1050	provfd = open(prov, O_WRONLY);
1051	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1052		char devprov[MAXPATHLEN];
1053
1054		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1055		provfd = open(devprov, O_WRONLY);
1056	}
1057	if (provfd == -1) {
1058		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1059		return;
1060	}
1061
1062	mediasize = g_get_mediasize(prov);
1063	secsize = g_get_sectorsize(prov);
1064	if (mediasize == 0 || secsize == 0) {
1065		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1066		    strerror(errno));
1067		return;
1068	}
1069
1070	sector = malloc(secsize);
1071	if (sector == NULL) {
1072		gctl_error(req, "Cannot allocate memory.");
1073		return;
1074	}
1075
1076	/* Read metadata from the backup file. */
1077	if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1078		gctl_error(req, "Cannot read from %s: %s.", file,
1079		    strerror(errno));
1080		goto out;
1081	}
1082	/* Check if this file contains geli metadata. */
1083	if (eli_metadata_decode(sector, &md) != 0) {
1084		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1085		goto out;
1086	}
1087	/* Read metadata from the provider. */
1088	if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1089	    (ssize_t)secsize) {
1090		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1091		goto out;
1092	}
1093out:
1094	if (provfd > 0)
1095		close(provfd);
1096	if (filefd > 0)
1097		close(filefd);
1098	if (sector != NULL) {
1099		bzero(sector, secsize);
1100		free(sector);
1101	}
1102}
1103
1104static void
1105eli_clear(struct gctl_req *req)
1106{
1107	const char *name;
1108	int error, i, nargs;
1109
1110	nargs = gctl_get_int(req, "nargs");
1111	if (nargs < 1) {
1112		gctl_error(req, "Too few arguments.");
1113		return;
1114	}
1115
1116	for (i = 0; i < nargs; i++) {
1117		name = gctl_get_ascii(req, "arg%d", i);
1118		error = g_metadata_clear(name, G_ELI_MAGIC);
1119		if (error != 0) {
1120			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1121			    name, strerror(error));
1122			gctl_error(req, "Not fully done.");
1123			continue;
1124		}
1125		if (verbose)
1126			printf("Metadata cleared on %s.\n", name);
1127	}
1128}
1129
1130static void
1131eli_dump(struct gctl_req *req)
1132{
1133	struct g_eli_metadata md, tmpmd;
1134	const char *name;
1135	int error, i, nargs;
1136
1137	nargs = gctl_get_int(req, "nargs");
1138	if (nargs < 1) {
1139		gctl_error(req, "Too few arguments.");
1140		return;
1141	}
1142
1143	for (i = 0; i < nargs; i++) {
1144		name = gctl_get_ascii(req, "arg%d", i);
1145		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1146		    sizeof(tmpmd), G_ELI_MAGIC);
1147		if (error != 0) {
1148			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1149			    name, strerror(error));
1150			gctl_error(req, "Not fully done.");
1151			continue;
1152		}
1153		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1154			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1155			    name);
1156			gctl_error(req, "Not fully done.");
1157			continue;
1158		}
1159		printf("Metadata on %s:\n", name);
1160		eli_metadata_dump(&md);
1161		printf("\n");
1162	}
1163}
1164