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