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