geom_eli.c revision 153190
12061Sjkh/*-
250479Speter * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
32061Sjkh * All rights reserved.
438666Sjb *
532427Sjb * Redistribution and use in source and binary forms, with or without
6111131Sru * modification, are permitted provided that the following conditions
7111131Sru * are met:
838666Sjb * 1. Redistributions of source code must retain the above copyright
938666Sjb *    notice, this list of conditions and the following disclaimer.
1038666Sjb * 2. Redistributions in binary form must reproduce the above copyright
11159363Strhodes *    notice, this list of conditions and the following disclaimer in the
1264049Salex *    documentation and/or other materials provided with the distribution.
1364049Salex *
14116679Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1566071Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16116679Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1773504Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18158962Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938666Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148330Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148330Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22148330Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2332427Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438666Sjb * SUCH DAMAGE.
25108451Sschweikh */
2638666Sjb
2738666Sjb#include <sys/cdefs.h>
2838666Sjb__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 153190 2005-12-07 01:38:27Z pjd $");
2938666Sjb
3017308Speter#include <stdio.h>
3191606Skeramida#include <stdint.h>
3219175Sbde#include <stdlib.h>
3396205Sjwd#include <unistd.h>
3496205Sjwd#include <fcntl.h>
3538042Sbde#include <readpassphrase.h>
3696205Sjwd#include <string.h>
3796205Sjwd#include <strings.h>
3838042Sbde#include <libgeom.h>
3996205Sjwd#include <paths.h>
40159363Strhodes#include <errno.h>
41159363Strhodes#include <assert.h>
4217308Speter
4396205Sjwd#include <sys/param.h>
4496205Sjwd#include <sys/mman.h>
4517308Speter#include <sys/resource.h>
46148330Snetchild#include <opencrypto/cryptodev.h>
47148330Snetchild#include <geom/eli/g_eli.h>
48148330Snetchild#include <geom/eli/pkcs5v2.h>
49148330Snetchild
50159831Sobrien#include "core/geom.h"
51148330Snetchild#include "misc/subr.h"
52148330Snetchild
53148330Snetchild
54148330Snetchilduint32_t lib_version = G_LIB_VERSION;
55148330Snetchilduint32_t version = G_ELI_VERSION;
56148330Snetchild
57148330Snetchildstatic char algo[] = "aes";
5896205Sjwdstatic intmax_t keylen = 0;
5996205Sjwdstatic intmax_t keyno = -1;
6096205Sjwdstatic intmax_t iterations = -1;
61162147Srustatic intmax_t sectorsize = 0;
62162147Srustatic char keyfile[] = "", newkeyfile[] = "";
6398723Sdillon
6498723Sdillonstatic void eli_main(struct gctl_req *req, unsigned flags);
6598723Sdillonstatic void eli_init(struct gctl_req *req);
6638666Sjbstatic void eli_attach(struct gctl_req *req);
6738666Sjbstatic void eli_setkey(struct gctl_req *req);
6817308Speterstatic void eli_delkey(struct gctl_req *req);
69123311Speterstatic void eli_kill(struct gctl_req *req);
70123311Speterstatic void eli_backup(struct gctl_req *req);
71123311Speterstatic void eli_restore(struct gctl_req *req);
72123311Speterstatic void eli_clear(struct gctl_req *req);
73159349Simpstatic void eli_dump(struct gctl_req *req);
74159349Simp
75159349Simp/*
76158962Snetchild * Available commands:
77158962Snetchild *
78158962Snetchild * init [-bhPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] prov
79156840Sru * label - alias for 'init'
80123311Speter * attach [-dpv] [-k keyfile] prov
81137288Speter * detach [-fl] prov ...
82147425Sru * stop - alias for 'detach'
83156740Sru * onetime [-d] [-a algo] [-l keylen] prov ...
842061Sjkh * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
8597769Sru * delkey [-afv] [-n keyno] prov
8697252Sru * kill [-av] [prov ...]
87119579Sru * backup [-v] prov file
8897252Sru * restore [-v] file prov
8995730Sru * clear [-v] prov ...
9095793Sru * dump [-v] prov ...
91111617Sru */
9295730Srustruct g_command class_commands[] = {
93116679Ssimokawa	{ "init", G_FLAG_VERBOSE, eli_main,
9495730Sru	    {
95116679Ssimokawa		{ 'a', "algo", algo, G_TYPE_STRING },
9695730Sru		{ 'b', "boot", NULL, G_TYPE_NONE },
97110035Sru		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
98107516Sru		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
99138921Sru		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
100156145Syar		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
101138921Sru		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
102133942Sru		G_OPT_SENTINEL
103133942Sru	    },
104156145Syar	    "[-bPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
105133942Sru	},
106110035Sru	{ "label", G_FLAG_VERBOSE, eli_main,
107117234Sru	    {
108110035Sru		{ 'a', "algo", algo, G_TYPE_STRING },
109117229Sru		{ 'b', "boot", NULL, G_TYPE_NONE },
110117234Sru		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
11154324Smarcel		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
11217308Speter		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
113119519Smarcel		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
114119519Smarcel		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
115119519Smarcel		G_OPT_SENTINEL
116119519Smarcel	    },
117119519Smarcel	    "- an alias for 'init'"
118119519Smarcel	},
119119579Sru	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
120119519Smarcel	    {
121119519Smarcel		{ 'd', "detach", NULL, G_TYPE_NONE },
122119519Smarcel		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
123119519Smarcel		{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
124119519Smarcel		G_OPT_SENTINEL
125126031Sgad	    },
126126024Sgad	    "[-dpv] [-k keyfile] prov"
127126024Sgad	},
128126024Sgad	{ "detach", 0, NULL,
129126024Sgad	    {
130126024Sgad		{ 'f', "force", NULL, G_TYPE_NONE },
131126024Sgad		{ 'l', "last", NULL, G_TYPE_NONE },
132126024Sgad		G_OPT_SENTINEL
133126024Sgad	    },
134126024Sgad	    "[-fl] prov ..."
135126024Sgad	},
136126024Sgad	{ "stop", 0, NULL,
137126024Sgad	    {
138126024Sgad		{ 'f', "force", NULL, G_TYPE_NONE },
139126031Sgad		{ 'l', "last", NULL, G_TYPE_NONE },
140126024Sgad		G_OPT_SENTINEL
141126024Sgad	    },
142126024Sgad	    "- an alias for 'detach'"
143126024Sgad	},
144126024Sgad	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
145126024Sgad	    {
146126024Sgad		{ 'a', "algo", algo, G_TYPE_STRING },
147133376Sharti		{ 'd', "detach", NULL, G_TYPE_NONE },
148126024Sgad		{ 'l', "keylen", &keylen, G_TYPE_NUMBER },
149126024Sgad		{ 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
150126024Sgad		G_OPT_SENTINEL
151126024Sgad	    },
152126024Sgad	    "[-d] [-a algo] [-l keylen] [-s sectorsize] prov ..."
153125885Sgad	},
154125885Sgad	{ "setkey", G_FLAG_VERBOSE, eli_main,
15538666Sjb	    {
15617308Speter		{ 'i', "iterations", &iterations, G_TYPE_NUMBER },
157119519Smarcel		{ 'k', "keyfile", keyfile, G_TYPE_STRING },
158119579Sru		{ 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
159133376Sharti		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
160110035Sru		{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
1612302Spaul		{ 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
16239206Sjkh		G_OPT_SENTINEL
16339206Sjkh	    },
16439206Sjkh	    "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
165133945Sru	},
166133945Sru	{ "delkey", G_FLAG_VERBOSE, eli_main,
167132358Smarkm	    {
16817308Speter		{ 'a', "all", NULL, G_TYPE_NONE },
16954324Smarcel		{ 'f', "force", NULL, G_TYPE_NONE },
17054324Smarcel		{ 'n', "keyno", &keyno, G_TYPE_NUMBER },
171132234Smarcel		G_OPT_SENTINEL
172132234Smarcel	    },
173132234Smarcel	    "[-afv] [-n keyno] prov"
174132234Smarcel	},
17554324Smarcel	{ "kill", G_FLAG_VERBOSE, eli_main,
17654324Smarcel	    {
17754324Smarcel		{ 'a', "all", NULL, G_TYPE_NONE },
178118531Sru		G_OPT_SENTINEL
17954324Smarcel	    },
18054324Smarcel	    "[-av] [prov ...]"
18154324Smarcel	},
18254324Smarcel	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
18354324Smarcel	    "[-v] prov file"
18454324Smarcel	},
185133376Sharti	{ "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
18654324Smarcel	    "[-v] file prov"
187133376Sharti	},
188133376Sharti	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
18954324Smarcel	    "[-v] prov ..."
19054324Smarcel	},
19154324Smarcel	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
19254324Smarcel	    "[-v] prov ..."
19354324Smarcel	},
194133376Sharti	G_CMD_SENTINEL
19554324Smarcel};
19654324Smarcel
19754324Smarcelstatic int verbose = 0;
198118531Sru
199118531Srustatic int
20054324Smarceleli_protect(struct gctl_req *req)
201132234Smarcel{
202132234Smarcel	struct rlimit rl;
203132234Smarcel
204132234Smarcel	/* Disable core dumps. */
205132234Smarcel	rl.rlim_cur = 0;
206132588Skensmith	rl.rlim_max = 0;
207132358Smarkm	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
208132234Smarcel		gctl_error(req, "Cannot disable core dumps: %s.",
209132358Smarkm		    strerror(errno));
210132234Smarcel		return (-1);
211132234Smarcel	}
212132234Smarcel	/* Disable swapping. */
21354324Smarcel	if (mlockall(MCL_FUTURE) == -1) {
21454324Smarcel		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
21595730Sru		return (-1);
21695730Sru	}
21795730Sru	return (0);
21895730Sru}
21995730Sru
22095730Srustatic void
22195730Srueli_main(struct gctl_req *req, unsigned flags)
22238666Sjb{
223107374Sru	const char *name;
22417308Speter
22555678Smarcel	if (eli_protect(req) == -1)
226143032Sharti		return;
227138515Sharti
228117793Sru	if ((flags & G_FLAG_VERBOSE) != 0)
229110035Sru		verbose = 1;
230110035Sru
231110035Sru	name = gctl_get_ascii(req, "verb");
2322061Sjkh	if (name == NULL) {
23317308Speter		gctl_error(req, "No '%s' argument.", "verb");
234107516Sru		return;
235107374Sru	}
23655678Smarcel	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
237107516Sru		eli_init(req);
238107516Sru	else if (strcmp(name, "attach") == 0)
239107516Sru		eli_attach(req);
240107516Sru	else if (strcmp(name, "setkey") == 0)
241107516Sru		eli_setkey(req);
242139112Sru	else if (strcmp(name, "delkey") == 0)
243164470Sjb		eli_delkey(req);
244107516Sru	else if (strcmp(name, "kill") == 0)
245122204Skris		eli_kill(req);
24655678Smarcel	else if (strcmp(name, "backup") == 0)
24755678Smarcel		eli_backup(req);
248116696Sru	else if (strcmp(name, "restore") == 0)
24955678Smarcel		eli_restore(req);
250133376Sharti	else if (strcmp(name, "dump") == 0)
251107516Sru		eli_dump(req);
252107516Sru	else if (strcmp(name, "clear") == 0)
253107516Sru		eli_clear(req);
254107516Sru	else
25555678Smarcel		gctl_error(req, "Unknown command: %s.", name);
25655678Smarcel}
257111131Sru
258111131Srustatic void
259111131Sruarc4rand(unsigned char *buf, size_t size)
260133945Sru{
261111131Sru	uint32_t *buf4;
262111131Sru	size_t size4;
263148154Sru	unsigned i;
264168280Smarcel
265168280Smarcel	buf4 = (uint32_t *)buf;
266133945Sru	size4 = size / 4;
267133945Sru
268103985Sphk	for (i = 0; i < size4; i++)
269103985Sphk		buf4[i] = arc4random();
270103985Sphk	for (i *= 4; i < size; i++)
271168280Smarcel		buf[i] = arc4random() % 0xff;
272162147Sru}
273152879Sru
274152880Srustatic int
275148154Srueli_is_attached(const char *prov)
276162147Sru{
277162147Sru	char name[MAXPATHLEN];
278162147Sru	unsigned secsize;
279162147Sru
280131876Sphk	/*
281162147Sru	 * Not the best way to do it, but the easiest.
282111131Sru	 * We try to open provider and check if it is a GEOM provider
283162147Sru	 * by asking about its sectorsize.
284162147Sru	 */
285162147Sru	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
286162147Sru	secsize = g_get_sectorsize(name);
287162147Sru	if (secsize > 0)
288103985Sphk		return (1);
289148154Sru	return (0);
290148154Sru}
291162147Sru
292148154Srustatic unsigned char *
293148154Srueli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
294162147Sru    int new)
295148154Sru{
296162147Sru	struct hmac_ctx ctx;
297103985Sphk	const char *str;
298133945Sru	int error, nopassphrase;
299133945Sru
300103985Sphk	nopassphrase =
301118531Sru	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
302118531Sru
303103985Sphk	g_eli_crypto_hmac_init(&ctx, NULL, 0);
304133945Sru
305	str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
306	if (str[0] != '\0') {
307		char buf[MAXPHYS];
308		ssize_t done;
309		int fd;
310
311		if (strcmp(str, "-") == 0)
312			fd = STDIN_FILENO;
313		else {
314			fd = open(str, O_RDONLY);
315			if (fd == -1) {
316				gctl_error(req, "Cannot open keyfile %s: %s.",
317				    str, strerror(errno));
318				return (NULL);
319			}
320		}
321		while ((done = read(fd, buf, sizeof(buf))) > 0)
322			g_eli_crypto_hmac_update(&ctx, buf, done);
323		error = errno;
324		if (strcmp(str, "-") != 0)
325			close(fd);
326		bzero(buf, sizeof(buf));
327		if (done == -1) {
328			gctl_error(req, "Cannot read keyfile %s: %s.", str,
329			    strerror(error));
330			return (NULL);
331		}
332	}
333
334	if (!nopassphrase) {
335		char buf1[BUFSIZ], buf2[BUFSIZ], *p;
336
337		if (!new && md->md_iterations == -1) {
338			gctl_error(req, "Missing -p flag.");
339			return (NULL);
340		}
341		for (;;) {
342			p = readpassphrase(
343			    new ? "Enter new passphrase:" : "Enter passphrase:",
344			    buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
345			if (p == NULL) {
346				bzero(buf1, sizeof(buf1));
347				gctl_error(req, "Cannot read passphrase: %s.",
348				    strerror(errno));
349				return (NULL);
350			}
351
352			if (new) {
353				p = readpassphrase("Reenter new passphrase: ",
354				    buf2, sizeof(buf2),
355				    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
356				if (p == NULL) {
357					bzero(buf1, sizeof(buf1));
358					gctl_error(req,
359					    "Cannot read passphrase: %s.",
360					    strerror(errno));
361					return (NULL);
362				}
363
364				if (strcmp(buf1, buf2) != 0) {
365					bzero(buf2, sizeof(buf2));
366					fprintf(stderr, "They didn't match.\n");
367					continue;
368				}
369				bzero(buf2, sizeof(buf2));
370			}
371			break;
372		}
373		/*
374		 * Field md_iterations equal to -1 means "choose some sane
375		 * value for me".
376		 */
377		if (md->md_iterations == -1) {
378			assert(new);
379			if (verbose)
380				printf("Calculating number of iterations...\n");
381			md->md_iterations = pkcs5v2_calculate(2000000);
382			assert(md->md_iterations > 0);
383			if (verbose) {
384				printf("Done, using %d iterations.\n",
385				    md->md_iterations);
386			}
387		}
388		/*
389		 * If md_iterations is equal to 0, user don't want PKCS5v2.
390		 */
391		if (md->md_iterations == 0) {
392			g_eli_crypto_hmac_update(&ctx, md->md_salt,
393			    sizeof(md->md_salt));
394			g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
395		} else /* if (md->md_iterations > 0) */ {
396			unsigned char dkey[G_ELI_USERKEYLEN];
397
398			pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
399			    sizeof(md->md_salt), buf1, md->md_iterations);
400			g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
401			bzero(dkey, sizeof(dkey));
402		}
403		bzero(buf1, sizeof(buf1));
404	}
405	g_eli_crypto_hmac_final(&ctx, key, 0);
406	return (key);
407}
408
409static int
410eli_metadata_read(struct gctl_req *req, const char *prov,
411    struct g_eli_metadata *md)
412{
413	unsigned char sector[sizeof(struct g_eli_metadata)];
414	int error;
415
416	if (g_get_sectorsize(prov) == 0) {
417		int fd;
418
419		/* This is a file probably. */
420		fd = open(prov, O_RDONLY);
421		if (fd == -1) {
422			gctl_error(req, "Cannot open %s: %s.", prov,
423			    strerror(errno));
424			return (-1);
425		}
426		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
427			gctl_error(req, "Cannot read metadata from %s: %s.",
428			    prov, strerror(errno));
429			close(fd);
430			return (-1);
431		}
432		close(fd);
433	} else {
434		/* This is a GEOM provider. */
435		error = g_metadata_read(prov, sector, sizeof(sector),
436		    G_ELI_MAGIC);
437		if (error != 0) {
438			gctl_error(req, "Cannot read metadata from %s: %s.",
439			    prov, strerror(error));
440			return (-1);
441		}
442	}
443	if (eli_metadata_decode(sector, md) != 0) {
444		gctl_error(req, "MD5 hash mismatch for %s.", prov);
445		return (-1);
446	}
447	return (0);
448}
449
450static int
451eli_metadata_store(struct gctl_req *req, const char *prov,
452    struct g_eli_metadata *md)
453{
454	unsigned char sector[sizeof(struct g_eli_metadata)];
455	int error;
456
457	eli_metadata_encode(md, sector);
458	if (g_get_sectorsize(prov) == 0) {
459		int fd;
460
461		/* This is a file probably. */
462		fd = open(prov, O_WRONLY | O_TRUNC);
463		if (fd == -1) {
464			gctl_error(req, "Cannot open %s: %s.", prov,
465			    strerror(errno));
466			bzero(sector, sizeof(sector));
467			return (-1);
468		}
469		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
470			gctl_error(req, "Cannot write metadata to %s: %s.",
471			    prov, strerror(errno));
472			bzero(sector, sizeof(sector));
473			close(fd);
474			return (-1);
475		}
476		close(fd);
477	} else {
478		/* This is a GEOM provider. */
479		error = g_metadata_store(prov, sector, sizeof(sector));
480		if (error != 0) {
481			gctl_error(req, "Cannot write metadata to %s: %s.",
482			    prov, strerror(errno));
483			bzero(sector, sizeof(sector));
484			return (-1);
485		}
486	}
487	bzero(sector, sizeof(sector));
488	return (0);
489}
490
491static void
492eli_init(struct gctl_req *req)
493{
494	struct g_eli_metadata md;
495	unsigned char sector[sizeof(struct g_eli_metadata)];
496	unsigned char key[G_ELI_USERKEYLEN];
497	const char *str, *prov;
498	unsigned secsize;
499	off_t mediasize;
500	intmax_t val;
501	int error, nargs, boot;
502
503	nargs = gctl_get_int(req, "nargs");
504	if (nargs != 1) {
505		gctl_error(req, "Too few arguments.");
506		return;
507	}
508	prov = gctl_get_ascii(req, "arg0");
509	mediasize = g_get_mediasize(prov);
510	secsize = g_get_sectorsize(prov);
511	if (mediasize == 0 || secsize == 0) {
512		gctl_error(req, "Cannot get informations about %s: %s.", prov,
513		    strerror(errno));
514		return;
515	}
516
517	bzero(&md, sizeof(md));
518	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
519	md.md_version = G_ELI_VERSION;
520	md.md_flags = 0;
521	boot = gctl_get_int(req, "boot");
522	if (boot) {
523		int nonewpassphrase;
524
525		/* Part of key cannot be read on boot from a file. */
526		str = gctl_get_ascii(req, "newkeyfile");
527		if (str[0] != '\0') {
528			gctl_error(req,
529			    "Options -b and -K are mutually exclusive.");
530			return;
531		}
532		/* Key has to be given as a passphrase on boot. */
533		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
534		if (nonewpassphrase) {
535			gctl_error(req,
536			    "Options -b and -P are mutually exclusive.");
537			return;
538		}
539		md.md_flags |= G_ELI_FLAG_BOOT;
540	}
541	str = gctl_get_ascii(req, "algo");
542	md.md_algo = g_eli_str2algo(str);
543	if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
544	    md.md_algo > CRYPTO_ALGORITHM_MAX) {
545		gctl_error(req, "Invalid encryption algorithm.");
546		return;
547	}
548	val = gctl_get_intmax(req, "keylen");
549	md.md_keylen = val;
550	md.md_keylen = g_eli_keylen(md.md_algo, md.md_keylen);
551	if (md.md_keylen == 0) {
552		gctl_error(req, "Invalid key length.");
553		return;
554	}
555	md.md_provsize = mediasize;
556
557	val = gctl_get_intmax(req, "iterations");
558	md.md_iterations = val;
559
560	val = gctl_get_intmax(req, "sectorsize");
561	if (val == 0)
562		md.md_sectorsize = secsize;
563	else {
564		if (val < 0 || (val % secsize) != 0) {
565			gctl_error(req, "Invalid sector size.");
566			return;
567		}
568		md.md_sectorsize = val;
569	}
570
571	md.md_keys = 0x01;
572	arc4rand(md.md_salt, sizeof(md.md_salt));
573	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
574
575	/* Generate user key. */
576	if (eli_genkey(req, &md, key, 1) == NULL) {
577		bzero(key, sizeof(key));
578		bzero(&md, sizeof(md));
579		return;
580	}
581
582	/* Encrypt the first and the only Master Key. */
583	error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, md.md_mkeys);
584	bzero(key, sizeof(key));
585	if (error != 0) {
586		bzero(&md, sizeof(md));
587		gctl_error(req, "Cannot encrypt Master Key: %s.",
588		    strerror(error));
589		return;
590	}
591
592	eli_metadata_encode(&md, sector);
593	bzero(&md, sizeof(md));
594	error = g_metadata_store(prov, sector, sizeof(sector));
595	bzero(sector, sizeof(sector));
596	if (error != 0) {
597		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
598		    strerror(error));
599		return;
600	}
601	if (verbose)
602		printf("Metadata value stored on %s.\n", prov);
603}
604
605static void
606eli_attach(struct gctl_req *req)
607{
608	struct g_eli_metadata md;
609	unsigned char key[G_ELI_USERKEYLEN];
610	const char *prov;
611	int nargs;
612
613	nargs = gctl_get_int(req, "nargs");
614	if (nargs != 1) {
615		gctl_error(req, "Too few arguments.");
616		return;
617	}
618	prov = gctl_get_ascii(req, "arg0");
619
620	if (eli_metadata_read(req, prov, &md) == -1)
621		return;
622
623	if (eli_genkey(req, &md, key, 0) == NULL) {
624		bzero(key, sizeof(key));
625		return;
626	}
627
628	gctl_ro_param(req, "key", sizeof(key), key);
629	if (gctl_issue(req) == NULL) {
630		if (verbose)
631			printf("Attched to %s.\n", prov);
632	}
633	bzero(key, sizeof(key));
634}
635
636static void
637eli_setkey_attached(struct gctl_req *req, const char *prov,
638 struct g_eli_metadata *md)
639{
640	unsigned char key[G_ELI_USERKEYLEN];
641	intmax_t val;
642
643	val = gctl_get_intmax(req, "iterations");
644	/* Check if iterations number should be changed. */
645	if (val != -1)
646		md->md_iterations = val;
647
648	/* Generate key for Master Key encryption. */
649	if (eli_genkey(req, md, key, 1) == NULL) {
650		bzero(key, sizeof(key));
651		return;
652	}
653
654	gctl_ro_param(req, "key", sizeof(key), key);
655	gctl_issue(req);
656	bzero(key, sizeof(key));
657}
658
659static void
660eli_setkey_detached(struct gctl_req *req, const char *prov,
661 struct g_eli_metadata *md)
662{
663	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
664	unsigned char *mkeydst;
665	intmax_t val;
666	unsigned nkey;
667	int error;
668
669	if (md->md_keys == 0) {
670		gctl_error(req, "No valid keys on %s.", prov);
671		return;
672	}
673
674	/* Generate key for Master Key decryption. */
675	if (eli_genkey(req, md, key, 0) == NULL) {
676		bzero(key, sizeof(key));
677		return;
678	}
679
680	/* Decrypt Master Key. */
681	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
682	bzero(key, sizeof(key));
683	if (error != 0) {
684		bzero(md, sizeof(*md));
685		if (error == -1)
686			gctl_error(req, "Wrong key for %s.", prov);
687		else /* if (error > 0) */ {
688			gctl_error(req, "Cannot decrypt Master Key: %s.",
689			    strerror(error));
690		}
691		return;
692	}
693	if (verbose)
694		printf("Decrypted Master Key %u.\n", nkey);
695
696	val = gctl_get_intmax(req, "keyno");
697	if (val != -1)
698		nkey = val;
699#if 0
700	else
701		; /* Use the key number which was found during decryption. */
702#endif
703	if (nkey >= G_ELI_MAXMKEYS) {
704		gctl_error(req, "Invalid '%s' argument.", "keyno");
705		return;
706	}
707
708	val = gctl_get_intmax(req, "iterations");
709	/* Check if iterations number should and can be changed. */
710	if (val != -1) {
711		if (bitcount32(md->md_keys) != 1) {
712			gctl_error(req, "To be able to use '-i' option, only "
713			    "one key can be defined.");
714			return;
715		}
716		if (md->md_keys != (1 << nkey)) {
717			gctl_error(req, "Only already defined key can be "
718			    "changed when '-i' option is used.");
719			return;
720		}
721		md->md_iterations = val;
722	}
723
724	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
725	md->md_keys |= (1 << nkey);
726
727	bcopy(mkey, mkeydst, sizeof(mkey));
728	bzero(mkey, sizeof(mkey));
729
730	/* Generate key for Master Key encryption. */
731	if (eli_genkey(req, md, key, 1) == NULL) {
732		bzero(key, sizeof(key));
733		bzero(md, sizeof(*md));
734		return;
735	}
736
737	/* Encrypt the Master-Key with the new key. */
738	error = g_eli_mkey_encrypt(md->md_algo, key, md->md_keylen, mkeydst);
739	bzero(key, sizeof(key));
740	if (error != 0) {
741		bzero(md, sizeof(*md));
742		gctl_error(req, "Cannot encrypt Master Key: %s.",
743		    strerror(error));
744		return;
745	}
746
747	/* Store metadata with fresh key. */
748	eli_metadata_store(req, prov, md);
749	bzero(md, sizeof(*md));
750}
751
752static void
753eli_setkey(struct gctl_req *req)
754{
755	struct g_eli_metadata md;
756	const char *prov;
757	int nargs;
758
759	nargs = gctl_get_int(req, "nargs");
760	if (nargs != 1) {
761		gctl_error(req, "Too few arguments.");
762		return;
763	}
764	prov = gctl_get_ascii(req, "arg0");
765
766	if (eli_metadata_read(req, prov, &md) == -1)
767		return;
768
769	if (eli_is_attached(prov))
770		eli_setkey_attached(req, prov, &md);
771	else
772		eli_setkey_detached(req, prov, &md);
773}
774
775static void
776eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
777{
778
779	gctl_issue(req);
780}
781
782static void
783eli_delkey_detached(struct gctl_req *req, const char *prov)
784{
785	struct g_eli_metadata md;
786	unsigned char *mkeydst;
787	intmax_t val;
788	unsigned nkey;
789	int all, force;
790
791	if (eli_metadata_read(req, prov, &md) == -1)
792		return;
793
794	all = gctl_get_int(req, "all");
795	if (all)
796		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
797	else {
798		force = gctl_get_int(req, "force");
799		val = gctl_get_intmax(req, "keyno");
800		if (val == -1) {
801			gctl_error(req, "Key number has to be specified.");
802			return;
803		}
804		nkey = val;
805		if (nkey >= G_ELI_MAXMKEYS) {
806			gctl_error(req, "Invalid '%s' argument.", "keyno");
807			return;
808		}
809		if (!(md.md_keys & (1 << nkey)) && !force) {
810			gctl_error(req, "Master Key %u is not set.", nkey);
811			return;
812		}
813		md.md_keys &= ~(1 << nkey);
814		if (md.md_keys == 0 && !force) {
815			gctl_error(req, "This is the last Master Key. Use '-f' "
816			    "option if you really want to remove it.");
817			return;
818		}
819		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
820		arc4rand(mkeydst, G_ELI_MKEYLEN);
821	}
822
823	eli_metadata_store(req, prov, &md);
824	bzero(&md, sizeof(md));
825}
826
827static void
828eli_delkey(struct gctl_req *req)
829{
830	const char *prov;
831	int nargs;
832
833	nargs = gctl_get_int(req, "nargs");
834	if (nargs != 1) {
835		gctl_error(req, "Too few arguments.");
836		return;
837	}
838	prov = gctl_get_ascii(req, "arg0");
839
840	if (eli_is_attached(prov))
841		eli_delkey_attached(req, prov);
842	else
843		eli_delkey_detached(req, prov);
844}
845
846static void
847eli_kill_detached(struct gctl_req *req, const char *prov)
848{
849	struct g_eli_metadata md;
850	int error;
851
852	/*
853	 * NOTE: Maybe we should verify if this is geli provider first,
854	 *       but 'kill' command is quite critical so better don't waste
855	 *       the time.
856	 */
857#if 0
858	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
859	    G_ELI_MAGIC);
860	if (error != 0) {
861		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
862		    strerror(error));
863		return;
864	}
865#endif
866
867	arc4rand((unsigned char *)&md, sizeof(md));
868	error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
869	if (error != 0) {
870		gctl_error(req, "Cannot write metadata to %s: %s.", prov,
871		    strerror(error));
872	}
873}
874
875static void
876eli_kill(struct gctl_req *req)
877{
878	const char *prov;
879	int i, nargs, all;
880
881	nargs = gctl_get_int(req, "nargs");
882	all = gctl_get_int(req, "all");
883	if (!all && nargs == 0) {
884		gctl_error(req, "Too few arguments.");
885		return;
886	}
887	/*
888	 * How '-a' option combine with a list of providers:
889	 * Delete Master Keys from all attached providers:
890	 * geli kill -a
891	 * Delete Master Keys from all attached provider and from
892	 * detached da0 and da1:
893	 * geli kill -a da0 da1
894	 * Delete Master Keys from (attached or detached) da0 and da1:
895	 * geli kill da0 da1
896	 */
897
898	/*
899	 * First attached providers.
900	 */
901	gctl_issue(req);
902	/*
903	 * Now the rest.
904	 */
905	for (i = 0; i < nargs; i++) {
906		prov = gctl_get_ascii(req, "arg%d", i);
907		if (!eli_is_attached(prov))
908			eli_kill_detached(req, prov);
909	}
910}
911
912static void
913eli_backup(struct gctl_req *req)
914{
915	struct g_eli_metadata md;
916	const char *file, *prov;
917	unsigned secsize;
918	unsigned char *sector;
919	off_t mediasize;
920	int nargs, filefd, provfd;
921
922	nargs = gctl_get_int(req, "nargs");
923	if (nargs != 2) {
924		gctl_error(req, "Invalid number of arguments.");
925		return;
926	}
927	prov = gctl_get_ascii(req, "arg0");
928	file = gctl_get_ascii(req, "arg1");
929
930	provfd = filefd = -1;
931	sector = NULL;
932	secsize = 0;
933
934	provfd = open(prov, O_RDONLY);
935	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
936		char devprov[MAXPATHLEN];
937
938		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
939		provfd = open(devprov, O_RDONLY);
940	}
941	if (provfd == -1) {
942		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
943		return;
944	}
945	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
946	if (filefd == -1) {
947		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
948		goto out;
949	}
950
951	mediasize = g_get_mediasize(prov);
952	secsize = g_get_sectorsize(prov);
953	if (mediasize == 0 || secsize == 0) {
954		gctl_error(req, "Cannot get informations about %s: %s.", prov,
955		    strerror(errno));
956		return;
957	}
958
959	sector = malloc(secsize);
960	if (sector == NULL) {
961		gctl_error(req, "Cannot allocate memory.");
962		return;
963	}
964
965	/* Read metadata from the provider. */
966	if (pread(provfd, sector, secsize, mediasize - secsize) !=
967	    (ssize_t)secsize) {
968		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
969		goto out;
970	}
971	/* Check if this is geli provider. */
972	if (eli_metadata_decode(sector, &md) != 0) {
973		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
974		goto out;
975	}
976	/* Write metadata to the destination file. */
977	if (write(filefd, sector, secsize) != (ssize_t)secsize) {
978		gctl_error(req, "Cannot write to %s: %s.", file,
979		    strerror(errno));
980		goto out;
981	}
982out:
983	if (provfd > 0)
984		close(provfd);
985	if (filefd > 0)
986		close(filefd);
987	if (sector != NULL) {
988		bzero(sector, secsize);
989		free(sector);
990	}
991}
992
993static void
994eli_restore(struct gctl_req *req)
995{
996	struct g_eli_metadata md;
997	const char *file, *prov;
998	unsigned char *sector;
999	unsigned secsize;
1000	off_t mediasize;
1001	int nargs, filefd, provfd;
1002
1003	nargs = gctl_get_int(req, "nargs");
1004	if (nargs != 2) {
1005		gctl_error(req, "Invalid number of arguments.");
1006		return;
1007	}
1008	file = gctl_get_ascii(req, "arg0");
1009	prov = gctl_get_ascii(req, "arg1");
1010
1011	provfd = filefd = -1;
1012	sector = NULL;
1013	secsize = 0;
1014
1015	filefd = open(file, O_RDONLY);
1016	if (filefd == -1) {
1017		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1018		goto out;
1019	}
1020	provfd = open(prov, O_WRONLY);
1021	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1022		char devprov[MAXPATHLEN];
1023
1024		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1025		provfd = open(devprov, O_WRONLY);
1026	}
1027	if (provfd == -1) {
1028		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1029		return;
1030	}
1031
1032	mediasize = g_get_mediasize(prov);
1033	secsize = g_get_sectorsize(prov);
1034	if (mediasize == 0 || secsize == 0) {
1035		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1036		    strerror(errno));
1037		return;
1038	}
1039
1040	sector = malloc(secsize);
1041	if (sector == NULL) {
1042		gctl_error(req, "Cannot allocate memory.");
1043		return;
1044	}
1045
1046	/* Read metadata from the backup file. */
1047	if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1048		gctl_error(req, "Cannot read from %s: %s.", file,
1049		    strerror(errno));
1050		goto out;
1051	}
1052	/* Check if this file contains geli metadata. */
1053	if (eli_metadata_decode(sector, &md) != 0) {
1054		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1055		goto out;
1056	}
1057	/* Read metadata from the provider. */
1058	if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1059	    (ssize_t)secsize) {
1060		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1061		goto out;
1062	}
1063out:
1064	if (provfd > 0)
1065		close(provfd);
1066	if (filefd > 0)
1067		close(filefd);
1068	if (sector != NULL) {
1069		bzero(sector, secsize);
1070		free(sector);
1071	}
1072}
1073
1074static void
1075eli_clear(struct gctl_req *req)
1076{
1077	const char *name;
1078	int error, i, nargs;
1079
1080	nargs = gctl_get_int(req, "nargs");
1081	if (nargs < 1) {
1082		gctl_error(req, "Too few arguments.");
1083		return;
1084	}
1085
1086	for (i = 0; i < nargs; i++) {
1087		name = gctl_get_ascii(req, "arg%d", i);
1088		error = g_metadata_clear(name, G_ELI_MAGIC);
1089		if (error != 0) {
1090			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1091			    name, strerror(error));
1092			gctl_error(req, "Not fully done.");
1093			continue;
1094		}
1095		if (verbose)
1096			printf("Metadata cleared on %s.\n", name);
1097	}
1098}
1099
1100static void
1101eli_dump(struct gctl_req *req)
1102{
1103	struct g_eli_metadata md, tmpmd;
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_read(name, (unsigned char *)&tmpmd,
1116		    sizeof(tmpmd), G_ELI_MAGIC);
1117		if (error != 0) {
1118			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1119			    name, strerror(error));
1120			gctl_error(req, "Not fully done.");
1121			continue;
1122		}
1123		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1124			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1125			    name);
1126			gctl_error(req, "Not fully done.");
1127			continue;
1128		}
1129		printf("Metadata on %s:\n", name);
1130		eli_metadata_dump(&md);
1131		printf("\n");
1132	}
1133}
1134