geom_eli.c revision 162347
162583Sitojun/*-
278064Sume * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
362583Sitojun * All rights reserved.
462583Sitojun *
562583Sitojun * Redistribution and use in source and binary forms, with or without
662583Sitojun * modification, are permitted provided that the following conditions
762583Sitojun * are met:
862583Sitojun * 1. Redistributions of source code must retain the above copyright
962583Sitojun *    notice, this list of conditions and the following disclaimer.
1062583Sitojun * 2. Redistributions in binary form must reproduce the above copyright
1162583Sitojun *    notice, this list of conditions and the following disclaimer in the
1262583Sitojun *    documentation and/or other materials provided with the distribution.
1362583Sitojun *
1462583Sitojun * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1562583Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1662583Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1762583Sitojun * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1862583Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1962583Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2062583Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2162583Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2262583Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2362583Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2462583Sitojun * SUCH DAMAGE.
2562583Sitojun */
2662583Sitojun
2762583Sitojun#include <sys/cdefs.h>
2862583Sitojun__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 162347 2006-09-16 09:26:57Z pjd $");
2962583Sitojun
3062583Sitojun#include <stdio.h>
3162583Sitojun#include <stdint.h>
3262583Sitojun#include <stdlib.h>
3378064Sume#include <unistd.h>
3492917Sobrien#include <fcntl.h>
3592917Sobrien#include <readpassphrase.h>
3662583Sitojun#include <string.h>
3762583Sitojun#include <strings.h>
3878064Sume#include <libgeom.h>
3992917Sobrien#include <paths.h>
4092917Sobrien#include <errno.h>
4192917Sobrien#include <assert.h>
4292917Sobrien
4392917Sobrien#include <sys/param.h>
4492941Sobrien#include <sys/mman.h>
4592941Sobrien#include <sys/resource.h>
4692941Sobrien#include <opencrypto/cryptodev.h>
4792941Sobrien#include <geom/eli/g_eli.h>
4892941Sobrien#include <geom/eli/pkcs5v2.h>
4992941Sobrien
5092941Sobrien#include "core/geom.h"
5192941Sobrien#include "misc/subr.h"
5292941Sobrien
5392941Sobrien
5492941Sobrienuint32_t lib_version = G_LIB_VERSION;
5592941Sobrienuint32_t version = G_ELI_VERSION;
5692941Sobrien
5792941Sobrienstatic char aalgo[] = "none";
5892917Sobrienstatic char ealgo[] = "aes";
5992917Sobrienstatic intmax_t keylen = 0;
6092917Sobrienstatic intmax_t keyno = -1;
6192917Sobrienstatic intmax_t iterations = -1;
6292917Sobrienstatic intmax_t sectorsize = 0;
6392917Sobrienstatic char keyfile[] = "", newkeyfile[] = "";
6492941Sobrien
6592941Sobrienstatic void eli_main(struct gctl_req *req, unsigned flags);
6692941Sobrienstatic void eli_init(struct gctl_req *req);
6792941Sobrienstatic void eli_attach(struct gctl_req *req);
6892941Sobrienstatic void eli_setkey(struct gctl_req *req);
6992941Sobrienstatic void eli_delkey(struct gctl_req *req);
7092941Sobrienstatic void eli_kill(struct gctl_req *req);
7192941Sobrienstatic void eli_backup(struct gctl_req *req);
7292941Sobrienstatic void eli_restore(struct gctl_req *req);
7392941Sobrienstatic void eli_clear(struct gctl_req *req);
7492917Sobrienstatic void eli_dump(struct gctl_req *req);
7592917Sobrien
7692941Sobrien/*
7792941Sobrien * Available commands:
7892917Sobrien *
7992917Sobrien * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
8062583Sitojun * label - alias for 'init'
8192917Sobrien * attach [-dprv] [-k keyfile] prov
8292917Sobrien * detach [-fl] prov ...
8392917Sobrien * stop - alias for 'detach'
8492917Sobrien * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
8592917Sobrien * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
8692917Sobrien * 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	/* First detached provider. */
930	for (i = 0; i < nargs; i++) {
931		prov = gctl_get_ascii(req, "arg%d", i);
932		if (!eli_is_attached(prov))
933			eli_kill_detached(req, prov);
934	}
935	/* Now attached providers. */
936	gctl_issue(req);
937}
938
939static void
940eli_backup(struct gctl_req *req)
941{
942	struct g_eli_metadata md;
943	const char *file, *prov;
944	unsigned secsize;
945	unsigned char *sector;
946	off_t mediasize;
947	int nargs, filefd, provfd;
948
949	nargs = gctl_get_int(req, "nargs");
950	if (nargs != 2) {
951		gctl_error(req, "Invalid number of arguments.");
952		return;
953	}
954	prov = gctl_get_ascii(req, "arg0");
955	file = gctl_get_ascii(req, "arg1");
956
957	provfd = filefd = -1;
958	sector = NULL;
959	secsize = 0;
960
961	provfd = open(prov, O_RDONLY);
962	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
963		char devprov[MAXPATHLEN];
964
965		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
966		provfd = open(devprov, O_RDONLY);
967	}
968	if (provfd == -1) {
969		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
970		return;
971	}
972	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
973	if (filefd == -1) {
974		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
975		goto out;
976	}
977
978	mediasize = g_get_mediasize(prov);
979	secsize = g_get_sectorsize(prov);
980	if (mediasize == 0 || secsize == 0) {
981		gctl_error(req, "Cannot get informations about %s: %s.", prov,
982		    strerror(errno));
983		return;
984	}
985
986	sector = malloc(secsize);
987	if (sector == NULL) {
988		gctl_error(req, "Cannot allocate memory.");
989		return;
990	}
991
992	/* Read metadata from the provider. */
993	if (pread(provfd, sector, secsize, mediasize - secsize) !=
994	    (ssize_t)secsize) {
995		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
996		goto out;
997	}
998	/* Check if this is geli provider. */
999	if (eli_metadata_decode(sector, &md) != 0) {
1000		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1001		goto out;
1002	}
1003	/* Write metadata to the destination file. */
1004	if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1005		gctl_error(req, "Cannot write to %s: %s.", file,
1006		    strerror(errno));
1007		goto out;
1008	}
1009out:
1010	if (provfd > 0)
1011		close(provfd);
1012	if (filefd > 0)
1013		close(filefd);
1014	if (sector != NULL) {
1015		bzero(sector, secsize);
1016		free(sector);
1017	}
1018}
1019
1020static void
1021eli_restore(struct gctl_req *req)
1022{
1023	struct g_eli_metadata md;
1024	const char *file, *prov;
1025	unsigned char *sector;
1026	unsigned secsize;
1027	off_t mediasize;
1028	int nargs, filefd, provfd;
1029
1030	nargs = gctl_get_int(req, "nargs");
1031	if (nargs != 2) {
1032		gctl_error(req, "Invalid number of arguments.");
1033		return;
1034	}
1035	file = gctl_get_ascii(req, "arg0");
1036	prov = gctl_get_ascii(req, "arg1");
1037
1038	provfd = filefd = -1;
1039	sector = NULL;
1040	secsize = 0;
1041
1042	filefd = open(file, O_RDONLY);
1043	if (filefd == -1) {
1044		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1045		goto out;
1046	}
1047	provfd = open(prov, O_WRONLY);
1048	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1049		char devprov[MAXPATHLEN];
1050
1051		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1052		provfd = open(devprov, O_WRONLY);
1053	}
1054	if (provfd == -1) {
1055		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1056		return;
1057	}
1058
1059	mediasize = g_get_mediasize(prov);
1060	secsize = g_get_sectorsize(prov);
1061	if (mediasize == 0 || secsize == 0) {
1062		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1063		    strerror(errno));
1064		return;
1065	}
1066
1067	sector = malloc(secsize);
1068	if (sector == NULL) {
1069		gctl_error(req, "Cannot allocate memory.");
1070		return;
1071	}
1072
1073	/* Read metadata from the backup file. */
1074	if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1075		gctl_error(req, "Cannot read from %s: %s.", file,
1076		    strerror(errno));
1077		goto out;
1078	}
1079	/* Check if this file contains geli metadata. */
1080	if (eli_metadata_decode(sector, &md) != 0) {
1081		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1082		goto out;
1083	}
1084	/* Read metadata from the provider. */
1085	if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1086	    (ssize_t)secsize) {
1087		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1088		goto out;
1089	}
1090out:
1091	if (provfd > 0)
1092		close(provfd);
1093	if (filefd > 0)
1094		close(filefd);
1095	if (sector != NULL) {
1096		bzero(sector, secsize);
1097		free(sector);
1098	}
1099}
1100
1101static void
1102eli_clear(struct gctl_req *req)
1103{
1104	const char *name;
1105	int error, i, nargs;
1106
1107	nargs = gctl_get_int(req, "nargs");
1108	if (nargs < 1) {
1109		gctl_error(req, "Too few arguments.");
1110		return;
1111	}
1112
1113	for (i = 0; i < nargs; i++) {
1114		name = gctl_get_ascii(req, "arg%d", i);
1115		error = g_metadata_clear(name, G_ELI_MAGIC);
1116		if (error != 0) {
1117			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1118			    name, strerror(error));
1119			gctl_error(req, "Not fully done.");
1120			continue;
1121		}
1122		if (verbose)
1123			printf("Metadata cleared on %s.\n", name);
1124	}
1125}
1126
1127static void
1128eli_dump(struct gctl_req *req)
1129{
1130	struct g_eli_metadata md, tmpmd;
1131	const char *name;
1132	int error, i, nargs;
1133
1134	nargs = gctl_get_int(req, "nargs");
1135	if (nargs < 1) {
1136		gctl_error(req, "Too few arguments.");
1137		return;
1138	}
1139
1140	for (i = 0; i < nargs; i++) {
1141		name = gctl_get_ascii(req, "arg%d", i);
1142		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1143		    sizeof(tmpmd), G_ELI_MAGIC);
1144		if (error != 0) {
1145			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1146			    name, strerror(error));
1147			gctl_error(req, "Not fully done.");
1148			continue;
1149		}
1150		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1151			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1152			    name);
1153			gctl_error(req, "Not fully done.");
1154			continue;
1155		}
1156		printf("Metadata on %s:\n", name);
1157		eli_metadata_dump(&md);
1158		printf("\n");
1159	}
1160}
1161