1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sbin/geom/class/eli/geom_eli.c 348588 2019-06-03 21:04:23Z jhb $");
31
32#include <sys/param.h>
33#include <sys/mman.h>
34#include <sys/sysctl.h>
35#include <sys/resource.h>
36#include <opencrypto/cryptodev.h>
37
38#include <assert.h>
39#include <err.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <libgeom.h>
43#include <paths.h>
44#include <readpassphrase.h>
45#include <stdbool.h>
46#include <stdint.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <strings.h>
51#include <unistd.h>
52
53#include <geom/eli/g_eli.h>
54#include <geom/eli/pkcs5v2.h>
55
56#include "core/geom.h"
57#include "misc/subr.h"
58
59
60uint32_t lib_version = G_LIB_VERSION;
61uint32_t version = G_ELI_VERSION;
62
63#define	GELI_BACKUP_DIR	"/var/backups/"
64#define	GELI_ENC_ALGO	"aes"
65
66static void eli_main(struct gctl_req *req, unsigned flags);
67static void eli_init(struct gctl_req *req);
68static void eli_attach(struct gctl_req *req);
69static void eli_configure(struct gctl_req *req);
70static void eli_setkey(struct gctl_req *req);
71static void eli_delkey(struct gctl_req *req);
72static void eli_resume(struct gctl_req *req);
73static void eli_kill(struct gctl_req *req);
74static void eli_backup(struct gctl_req *req);
75static void eli_restore(struct gctl_req *req);
76static void eli_resize(struct gctl_req *req);
77static void eli_version(struct gctl_req *req);
78static void eli_clear(struct gctl_req *req);
79static void eli_dump(struct gctl_req *req);
80
81static int eli_backup_create(struct gctl_req *req, const char *prov,
82    const char *file);
83
84/*
85 * Available commands:
86 *
87 * init [-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov
88 * label - alias for 'init'
89 * attach [-Cdprv] [-n keyno] [-j passfile] [-k keyfile] prov
90 * detach [-fl] prov ...
91 * stop - alias for 'detach'
92 * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov
93 * configure [-bBgGtT] prov ...
94 * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
95 * delkey [-afv] [-n keyno] prov
96 * suspend [-v] -a | prov ...
97 * resume [-pv] [-j passfile] [-k keyfile] prov
98 * kill [-av] [prov ...]
99 * backup [-v] prov file
100 * restore [-fv] file prov
101 * resize [-v] -s oldsize prov
102 * version [prov ...]
103 * clear [-v] prov ...
104 * dump [-v] prov ...
105 */
106struct g_command class_commands[] = {
107	{ "init", G_FLAG_VERBOSE, eli_main,
108	    {
109		{ 'a', "aalgo", "", G_TYPE_STRING },
110		{ 'b', "boot", NULL, G_TYPE_BOOL },
111		{ 'B', "backupfile", "", G_TYPE_STRING },
112		{ 'd', "displaypass", NULL, G_TYPE_BOOL },
113		{ 'e', "ealgo", "", G_TYPE_STRING },
114		{ 'g', "geliboot", NULL, G_TYPE_BOOL },
115		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
116		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
117		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
118		{ 'l', "keylen", "0", G_TYPE_NUMBER },
119		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
120		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
121		{ 'T', "notrim", NULL, G_TYPE_BOOL },
122		{ 'V', "mdversion", "-1", G_TYPE_NUMBER },
123		G_OPT_SENTINEL
124	    },
125	    "[-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov"
126	},
127	{ "label", G_FLAG_VERBOSE, eli_main,
128	    {
129		{ 'a', "aalgo", "", G_TYPE_STRING },
130		{ 'b', "boot", NULL, G_TYPE_BOOL },
131		{ 'B', "backupfile", "", G_TYPE_STRING },
132		{ 'd', "displaypass", NULL, G_TYPE_BOOL },
133		{ 'e', "ealgo", "", G_TYPE_STRING },
134		{ 'g', "geliboot", NULL, G_TYPE_BOOL },
135		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
136		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
137		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
138		{ 'l', "keylen", "0", G_TYPE_NUMBER },
139		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
140		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
141		{ 'V', "mdversion", "-1", G_TYPE_NUMBER },
142		G_OPT_SENTINEL
143	    },
144	    "- an alias for 'init'"
145	},
146	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
147	    {
148		{ 'C', "dryrun", NULL, G_TYPE_BOOL },
149		{ 'd', "detach", NULL, G_TYPE_BOOL },
150		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
151		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
152		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
153		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
154		{ 'r', "readonly", NULL, G_TYPE_BOOL },
155		G_OPT_SENTINEL
156	    },
157	    "[-Cdprv] [-n keyno] [-j passfile] [-k keyfile] prov"
158	},
159	{ "detach", 0, NULL,
160	    {
161		{ 'f', "force", NULL, G_TYPE_BOOL },
162		{ 'l', "last", NULL, G_TYPE_BOOL },
163		G_OPT_SENTINEL
164	    },
165	    "[-fl] prov ..."
166	},
167	{ "stop", 0, NULL,
168	    {
169		{ 'f', "force", NULL, G_TYPE_BOOL },
170		{ 'l', "last", NULL, G_TYPE_BOOL },
171		G_OPT_SENTINEL
172	    },
173	    "- an alias for 'detach'"
174	},
175	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
176	    {
177		{ 'a', "aalgo", "", G_TYPE_STRING },
178		{ 'd', "detach", NULL, G_TYPE_BOOL },
179		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
180		{ 'l', "keylen", "0", G_TYPE_NUMBER },
181		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
182		{ 'T', "notrim", NULL, G_TYPE_BOOL },
183		G_OPT_SENTINEL
184	    },
185	    "[-dT] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov"
186	},
187	{ "configure", G_FLAG_VERBOSE, eli_main,
188	    {
189		{ 'b', "boot", NULL, G_TYPE_BOOL },
190		{ 'B', "noboot", NULL, G_TYPE_BOOL },
191		{ 'd', "displaypass", NULL, G_TYPE_BOOL },
192		{ 'D', "nodisplaypass", NULL, G_TYPE_BOOL },
193		{ 'g', "geliboot", NULL, G_TYPE_BOOL },
194		{ 'G', "nogeliboot", NULL, G_TYPE_BOOL },
195		{ 't', "trim", NULL, G_TYPE_BOOL },
196		{ 'T', "notrim", NULL, G_TYPE_BOOL },
197		G_OPT_SENTINEL
198	    },
199	    "[-bBdDgGtT] prov ..."
200	},
201	{ "setkey", G_FLAG_VERBOSE, eli_main,
202	    {
203		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
204		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
205		{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
206		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
207		{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
208		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
209		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
210		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
211		G_OPT_SENTINEL
212	    },
213	    "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
214	},
215	{ "delkey", G_FLAG_VERBOSE, eli_main,
216	    {
217		{ 'a', "all", NULL, G_TYPE_BOOL },
218		{ 'f', "force", NULL, G_TYPE_BOOL },
219		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
220		G_OPT_SENTINEL
221	    },
222	    "[-afv] [-n keyno] prov"
223	},
224	{ "suspend", G_FLAG_VERBOSE, NULL,
225	    {
226		{ 'a', "all", NULL, G_TYPE_BOOL },
227		G_OPT_SENTINEL
228	    },
229	    "[-v] -a | prov ..."
230	},
231	{ "resume", G_FLAG_VERBOSE, eli_main,
232	    {
233		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
234		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
235		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
236		G_OPT_SENTINEL
237	    },
238	    "[-pv] [-j passfile] [-k keyfile] prov"
239	},
240	{ "kill", G_FLAG_VERBOSE, eli_main,
241	    {
242		{ 'a', "all", NULL, G_TYPE_BOOL },
243		G_OPT_SENTINEL
244	    },
245	    "[-av] [prov ...]"
246	},
247	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
248	    "[-v] prov file"
249	},
250	{ "restore", G_FLAG_VERBOSE, eli_main,
251	    {
252		{ 'f', "force", NULL, G_TYPE_BOOL },
253		G_OPT_SENTINEL
254	    },
255	    "[-fv] file prov"
256	},
257	{ "resize", G_FLAG_VERBOSE, eli_main,
258	    {
259		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
260		G_OPT_SENTINEL
261	    },
262	    "[-v] -s oldsize prov"
263	},
264	{ "version", G_FLAG_LOADKLD, eli_main, G_NULL_OPTS,
265	    "[prov ...]"
266	},
267	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
268	    "[-v] prov ..."
269	},
270	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
271	    "[-v] prov ..."
272	},
273	G_CMD_SENTINEL
274};
275
276static int verbose = 0;
277
278#define	BUFSIZE	1024
279
280static int
281eli_protect(struct gctl_req *req)
282{
283	struct rlimit rl;
284
285	/* Disable core dumps. */
286	rl.rlim_cur = 0;
287	rl.rlim_max = 0;
288	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
289		gctl_error(req, "Cannot disable core dumps: %s.",
290		    strerror(errno));
291		return (-1);
292	}
293	/* Disable swapping. */
294	if (mlockall(MCL_FUTURE) == -1) {
295		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
296		return (-1);
297	}
298	return (0);
299}
300
301static void
302eli_main(struct gctl_req *req, unsigned int flags)
303{
304	const char *name;
305
306	if (eli_protect(req) == -1)
307		return;
308
309	if ((flags & G_FLAG_VERBOSE) != 0)
310		verbose = 1;
311
312	name = gctl_get_ascii(req, "verb");
313	if (name == NULL) {
314		gctl_error(req, "No '%s' argument.", "verb");
315		return;
316	}
317	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
318		eli_init(req);
319	else if (strcmp(name, "attach") == 0)
320		eli_attach(req);
321	else if (strcmp(name, "configure") == 0)
322		eli_configure(req);
323	else if (strcmp(name, "setkey") == 0)
324		eli_setkey(req);
325	else if (strcmp(name, "delkey") == 0)
326		eli_delkey(req);
327	else if (strcmp(name, "resume") == 0)
328		eli_resume(req);
329	else if (strcmp(name, "kill") == 0)
330		eli_kill(req);
331	else if (strcmp(name, "backup") == 0)
332		eli_backup(req);
333	else if (strcmp(name, "restore") == 0)
334		eli_restore(req);
335	else if (strcmp(name, "resize") == 0)
336		eli_resize(req);
337	else if (strcmp(name, "version") == 0)
338		eli_version(req);
339	else if (strcmp(name, "dump") == 0)
340		eli_dump(req);
341	else if (strcmp(name, "clear") == 0)
342		eli_clear(req);
343	else
344		gctl_error(req, "Unknown command: %s.", name);
345}
346
347static bool
348eli_is_attached(const char *prov)
349{
350	char name[MAXPATHLEN];
351
352	/*
353	 * Not the best way to do it, but the easiest.
354	 * We try to open provider and check if it is a GEOM provider
355	 * by asking about its sectorsize.
356	 */
357	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
358	return (g_get_sectorsize(name) > 0);
359}
360
361static int
362eli_genkey_files(struct gctl_req *req, bool new, const char *type,
363    struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize)
364{
365	char *p, buf[BUFSIZE], argname[16];
366	const char *file;
367	int error, fd, i;
368	ssize_t done;
369
370	assert((strcmp(type, "keyfile") == 0 && ctxp != NULL &&
371	    passbuf == NULL && passbufsize == 0) ||
372	    (strcmp(type, "passfile") == 0 && ctxp == NULL &&
373	    passbuf != NULL && passbufsize > 0));
374	assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0');
375
376	for (i = 0; ; i++) {
377		snprintf(argname, sizeof(argname), "%s%s%d",
378		    new ? "new" : "", type, i);
379
380		/* No more {key,pass}files? */
381		if (!gctl_has_param(req, argname))
382			return (i);
383
384		file = gctl_get_ascii(req, "%s", argname);
385		assert(file != NULL);
386
387		if (strcmp(file, "-") == 0)
388			fd = STDIN_FILENO;
389		else {
390			fd = open(file, O_RDONLY);
391			if (fd == -1) {
392				gctl_error(req, "Cannot open %s %s: %s.",
393				    type, file, strerror(errno));
394				return (-1);
395			}
396		}
397		if (strcmp(type, "keyfile") == 0) {
398			while ((done = read(fd, buf, sizeof(buf))) > 0)
399				g_eli_crypto_hmac_update(ctxp, buf, done);
400		} else /* if (strcmp(type, "passfile") == 0) */ {
401			assert(strcmp(type, "passfile") == 0);
402
403			while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) {
404				buf[done] = '\0';
405				p = strchr(buf, '\n');
406				if (p != NULL) {
407					*p = '\0';
408					done = p - buf;
409				}
410				if (strlcat(passbuf, buf, passbufsize) >=
411				    passbufsize) {
412					gctl_error(req,
413					    "Passphrase in %s too long.", file);
414					bzero(buf, sizeof(buf));
415					return (-1);
416				}
417				if (p != NULL)
418					break;
419			}
420		}
421		error = errno;
422		if (strcmp(file, "-") != 0)
423			close(fd);
424		bzero(buf, sizeof(buf));
425		if (done == -1) {
426			gctl_error(req, "Cannot read %s %s: %s.",
427			    type, file, strerror(error));
428			return (-1);
429		}
430	}
431	/* NOTREACHED */
432}
433
434static int
435eli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf,
436    size_t passbufsize)
437{
438	char *p;
439
440	for (;;) {
441		p = readpassphrase(
442		    new ? "Enter new passphrase: " : "Enter passphrase: ",
443		    passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY);
444		if (p == NULL) {
445			bzero(passbuf, passbufsize);
446			gctl_error(req, "Cannot read passphrase: %s.",
447			    strerror(errno));
448			return (-1);
449		}
450
451		if (new) {
452			char tmpbuf[BUFSIZE];
453
454			p = readpassphrase("Reenter new passphrase: ",
455			    tmpbuf, sizeof(tmpbuf),
456			    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
457			if (p == NULL) {
458				bzero(passbuf, passbufsize);
459				gctl_error(req,
460				    "Cannot read passphrase: %s.",
461				    strerror(errno));
462				return (-1);
463			}
464
465			if (strcmp(passbuf, tmpbuf) != 0) {
466				bzero(passbuf, passbufsize);
467				fprintf(stderr, "They didn't match.\n");
468				continue;
469			}
470			bzero(tmpbuf, sizeof(tmpbuf));
471		}
472		return (0);
473	}
474	/* NOTREACHED */
475}
476
477static int
478eli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new,
479    struct hmac_ctx *ctxp)
480{
481	char passbuf[BUFSIZE];
482	bool nopassphrase;
483	int nfiles;
484
485	nopassphrase =
486	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
487	if (nopassphrase) {
488		if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) {
489			gctl_error(req,
490			    "Options -%c and -%c are mutually exclusive.",
491			    new ? 'J' : 'j', new ? 'P' : 'p');
492			return (-1);
493		}
494		return (0);
495	}
496
497	if (!new && md->md_iterations == -1) {
498		gctl_error(req, "Missing -p flag.");
499		return (-1);
500	}
501	passbuf[0] = '\0';
502	nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf,
503	    sizeof(passbuf));
504	if (nfiles == -1)
505		return (-1);
506	else if (nfiles == 0) {
507		if (eli_genkey_passphrase_prompt(req, new, passbuf,
508		    sizeof(passbuf)) == -1) {
509			return (-1);
510		}
511	}
512	/*
513	 * Field md_iterations equal to -1 means "choose some sane
514	 * value for me".
515	 */
516	if (md->md_iterations == -1) {
517		assert(new);
518		if (verbose)
519			printf("Calculating number of iterations...\n");
520		md->md_iterations = pkcs5v2_calculate(2000000);
521		assert(md->md_iterations > 0);
522		if (verbose) {
523			printf("Done, using %d iterations.\n",
524			    md->md_iterations);
525		}
526	}
527	/*
528	 * If md_iterations is equal to 0, user doesn't want PKCS#5v2.
529	 */
530	if (md->md_iterations == 0) {
531		g_eli_crypto_hmac_update(ctxp, md->md_salt,
532		    sizeof(md->md_salt));
533		g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf));
534	} else /* if (md->md_iterations > 0) */ {
535		unsigned char dkey[G_ELI_USERKEYLEN];
536
537		pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
538		    sizeof(md->md_salt), passbuf, md->md_iterations);
539		g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey));
540		bzero(dkey, sizeof(dkey));
541	}
542	bzero(passbuf, sizeof(passbuf));
543
544	return (0);
545}
546
547static unsigned char *
548eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
549    bool new)
550{
551	struct hmac_ctx ctx;
552	bool nopassphrase;
553	int nfiles;
554
555	nopassphrase =
556	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
557
558	g_eli_crypto_hmac_init(&ctx, NULL, 0);
559
560	nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0);
561	if (nfiles == -1)
562		return (NULL);
563	else if (nfiles == 0 && nopassphrase) {
564		gctl_error(req, "No key components given.");
565		return (NULL);
566	}
567
568	if (eli_genkey_passphrase(req, md, new, &ctx) == -1)
569		return (NULL);
570
571	g_eli_crypto_hmac_final(&ctx, key, 0);
572
573	return (key);
574}
575
576static int
577eli_metadata_read(struct gctl_req *req, const char *prov,
578    struct g_eli_metadata *md)
579{
580	unsigned char sector[sizeof(struct g_eli_metadata)];
581	int error;
582
583	if (g_get_sectorsize(prov) == 0) {
584		int fd;
585
586		/* This is a file probably. */
587		fd = open(prov, O_RDONLY);
588		if (fd == -1) {
589			gctl_error(req, "Cannot open %s: %s.", prov,
590			    strerror(errno));
591			return (-1);
592		}
593		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
594			gctl_error(req, "Cannot read metadata from %s: %s.",
595			    prov, strerror(errno));
596			close(fd);
597			return (-1);
598		}
599		close(fd);
600	} else {
601		/* This is a GEOM provider. */
602		error = g_metadata_read(prov, sector, sizeof(sector),
603		    G_ELI_MAGIC);
604		if (error != 0) {
605			gctl_error(req, "Cannot read metadata from %s: %s.",
606			    prov, strerror(error));
607			return (-1);
608		}
609	}
610	error = eli_metadata_decode(sector, md);
611	switch (error) {
612	case 0:
613		break;
614	case EOPNOTSUPP:
615		gctl_error(req,
616		    "Provider's %s metadata version %u is too new.\n"
617		    "geli: The highest supported version is %u.",
618		    prov, (unsigned int)md->md_version, G_ELI_VERSION);
619		return (-1);
620	case EINVAL:
621		gctl_error(req, "Inconsistent provider's %s metadata.", prov);
622		return (-1);
623	default:
624		gctl_error(req,
625		    "Unexpected error while decoding provider's %s metadata: %s.",
626		    prov, strerror(error));
627		return (-1);
628	}
629	return (0);
630}
631
632static int
633eli_metadata_store(struct gctl_req *req, const char *prov,
634    struct g_eli_metadata *md)
635{
636	unsigned char sector[sizeof(struct g_eli_metadata)];
637	int error;
638
639	eli_metadata_encode(md, sector);
640	if (g_get_sectorsize(prov) == 0) {
641		int fd;
642
643		/* This is a file probably. */
644		fd = open(prov, O_WRONLY | O_TRUNC);
645		if (fd == -1) {
646			gctl_error(req, "Cannot open %s: %s.", prov,
647			    strerror(errno));
648			bzero(sector, sizeof(sector));
649			return (-1);
650		}
651		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
652			gctl_error(req, "Cannot write metadata to %s: %s.",
653			    prov, strerror(errno));
654			bzero(sector, sizeof(sector));
655			close(fd);
656			return (-1);
657		}
658		close(fd);
659	} else {
660		/* This is a GEOM provider. */
661		error = g_metadata_store(prov, sector, sizeof(sector));
662		if (error != 0) {
663			gctl_error(req, "Cannot write metadata to %s: %s.",
664			    prov, strerror(errno));
665			bzero(sector, sizeof(sector));
666			return (-1);
667		}
668	}
669	bzero(sector, sizeof(sector));
670	return (0);
671}
672
673static void
674eli_init(struct gctl_req *req)
675{
676	struct g_eli_metadata md;
677	unsigned char sector[sizeof(struct g_eli_metadata)] __aligned(4);
678	unsigned char key[G_ELI_USERKEYLEN];
679	char backfile[MAXPATHLEN];
680	const char *str, *prov;
681	unsigned int secsize, version;
682	off_t mediasize;
683	intmax_t val;
684	int error, nargs;
685
686	nargs = gctl_get_int(req, "nargs");
687	if (nargs != 1) {
688		gctl_error(req, "Invalid number of arguments.");
689		return;
690	}
691	prov = gctl_get_ascii(req, "arg0");
692	mediasize = g_get_mediasize(prov);
693	secsize = g_get_sectorsize(prov);
694	if (mediasize == 0 || secsize == 0) {
695		gctl_error(req, "Cannot get informations about %s: %s.", prov,
696		    strerror(errno));
697		return;
698	}
699
700	bzero(&md, sizeof(md));
701	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
702	val = gctl_get_intmax(req, "mdversion");
703	if (val == -1) {
704		version = G_ELI_VERSION;
705	} else if (val < 0 || val > G_ELI_VERSION) {
706		gctl_error(req,
707		    "Invalid version specified should be between %u and %u.",
708		    G_ELI_VERSION_00, G_ELI_VERSION);
709		return;
710	} else {
711		version = val;
712	}
713	md.md_version = version;
714	md.md_flags = 0;
715	if (gctl_get_int(req, "boot"))
716		md.md_flags |= G_ELI_FLAG_BOOT;
717	if (gctl_get_int(req, "geliboot"))
718		md.md_flags |= G_ELI_FLAG_GELIBOOT;
719	if (gctl_get_int(req, "displaypass"))
720		md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
721	if (gctl_get_int(req, "notrim"))
722		md.md_flags |= G_ELI_FLAG_NODELETE;
723	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
724	str = gctl_get_ascii(req, "aalgo");
725	if (*str != '\0') {
726		if (version < G_ELI_VERSION_01) {
727			gctl_error(req,
728			    "Data authentication is supported starting from version %u.",
729			    G_ELI_VERSION_01);
730			return;
731		}
732		md.md_aalgo = g_eli_str2aalgo(str);
733		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
734		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
735			md.md_flags |= G_ELI_FLAG_AUTH;
736		} else {
737			/*
738			 * For backward compatibility, check if the -a option
739			 * was used to provide encryption algorithm.
740			 */
741			md.md_ealgo = g_eli_str2ealgo(str);
742			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
743			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
744				gctl_error(req,
745				    "Invalid authentication algorithm.");
746				return;
747			} else {
748				fprintf(stderr, "warning: The -e option, not "
749				    "the -a option is now used to specify "
750				    "encryption algorithm to use.\n");
751			}
752		}
753	}
754	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
755	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
756		str = gctl_get_ascii(req, "ealgo");
757		if (*str == '\0') {
758			if (version < G_ELI_VERSION_05)
759				str = "aes-cbc";
760			else
761				str = GELI_ENC_ALGO;
762		}
763		md.md_ealgo = g_eli_str2ealgo(str);
764		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
765		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
766			gctl_error(req, "Invalid encryption algorithm.");
767			return;
768		}
769		if (md.md_ealgo == CRYPTO_CAMELLIA_CBC &&
770		    version < G_ELI_VERSION_04) {
771			gctl_error(req,
772			    "Camellia-CBC algorithm is supported starting from version %u.",
773			    G_ELI_VERSION_04);
774			return;
775		}
776		if (md.md_ealgo == CRYPTO_AES_XTS &&
777		    version < G_ELI_VERSION_05) {
778			gctl_error(req,
779			    "AES-XTS algorithm is supported starting from version %u.",
780			    G_ELI_VERSION_05);
781			return;
782		}
783	}
784	if (md.md_flags & G_ELI_FLAG_AUTH) {
785		switch (md.md_aalgo) {
786		case CRYPTO_MD5_HMAC:
787			gctl_error(req,
788			    "The %s authentication algorithm is deprecated.",
789			    g_eli_algo2str(md.md_aalgo));
790			return;
791		}
792	}
793	switch (md.md_ealgo) {
794	case CRYPTO_3DES_CBC:
795	case CRYPTO_BLF_CBC:
796		gctl_error(req, "The %s encryption algorithm is deprecated.",
797		    g_eli_algo2str(md.md_ealgo));
798		return;
799	}
800	val = gctl_get_intmax(req, "keylen");
801	md.md_keylen = val;
802	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
803	if (md.md_keylen == 0) {
804		gctl_error(req, "Invalid key length.");
805		return;
806	}
807	md.md_provsize = mediasize;
808
809	val = gctl_get_intmax(req, "iterations");
810	if (val != -1) {
811		int nonewpassphrase;
812
813		/*
814		 * Don't allow to set iterations when there will be no
815		 * passphrase.
816		 */
817		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
818		if (nonewpassphrase) {
819			gctl_error(req,
820			    "Options -i and -P are mutually exclusive.");
821			return;
822		}
823	}
824	md.md_iterations = val;
825
826	val = gctl_get_intmax(req, "sectorsize");
827	if (val == 0)
828		md.md_sectorsize = secsize;
829	else {
830		if (val < 0 || (val % secsize) != 0 || !powerof2(val)) {
831			gctl_error(req, "Invalid sector size.");
832			return;
833		}
834		if (val > sysconf(_SC_PAGE_SIZE)) {
835			fprintf(stderr,
836			    "warning: Using sectorsize bigger than the page size!\n");
837		}
838		md.md_sectorsize = val;
839	}
840
841	md.md_keys = 0x01;
842	arc4random_buf(md.md_salt, sizeof(md.md_salt));
843	arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
844
845	/* Generate user key. */
846	if (eli_genkey(req, &md, key, true) == NULL) {
847		bzero(key, sizeof(key));
848		bzero(&md, sizeof(md));
849		return;
850	}
851
852	/* Encrypt the first and the only Master Key. */
853	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
854	bzero(key, sizeof(key));
855	if (error != 0) {
856		bzero(&md, sizeof(md));
857		gctl_error(req, "Cannot encrypt Master Key: %s.",
858		    strerror(error));
859		return;
860	}
861
862	eli_metadata_encode(&md, sector);
863	bzero(&md, sizeof(md));
864	error = g_metadata_store(prov, sector, sizeof(sector));
865	bzero(sector, sizeof(sector));
866	if (error != 0) {
867		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
868		    strerror(error));
869		return;
870	}
871	if (verbose)
872		printf("Metadata value stored on %s.\n", prov);
873	/* Backup metadata to a file. */
874	str = gctl_get_ascii(req, "backupfile");
875	if (str[0] != '\0') {
876		/* Backupfile given be the user, just copy it. */
877		strlcpy(backfile, str, sizeof(backfile));
878	} else {
879		/* Generate file name automatically. */
880		const char *p = prov;
881		unsigned int i;
882
883		if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
884			p += sizeof(_PATH_DEV) - 1;
885		snprintf(backfile, sizeof(backfile), "%s%s.eli",
886		    GELI_BACKUP_DIR, p);
887		/* Replace all / with _. */
888		for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
889			if (backfile[i] == '/')
890				backfile[i] = '_';
891		}
892	}
893	if (strcmp(backfile, "none") != 0 &&
894	    eli_backup_create(req, prov, backfile) == 0) {
895		printf("\nMetadata backup can be found in %s and\n", backfile);
896		printf("can be restored with the following command:\n");
897		printf("\n\t# geli restore %s %s\n\n", backfile, prov);
898	}
899}
900
901static void
902eli_attach(struct gctl_req *req)
903{
904	struct g_eli_metadata md;
905	unsigned char key[G_ELI_USERKEYLEN];
906	const char *prov;
907	off_t mediasize;
908	int nargs;
909
910	nargs = gctl_get_int(req, "nargs");
911	if (nargs != 1) {
912		gctl_error(req, "Invalid number of arguments.");
913		return;
914	}
915	prov = gctl_get_ascii(req, "arg0");
916
917	if (eli_metadata_read(req, prov, &md) == -1)
918		return;
919
920	mediasize = g_get_mediasize(prov);
921	if (md.md_provsize != (uint64_t)mediasize) {
922		gctl_error(req, "Provider size mismatch.");
923		return;
924	}
925
926	if (eli_genkey(req, &md, key, false) == NULL) {
927		bzero(key, sizeof(key));
928		return;
929	}
930
931	gctl_ro_param(req, "key", sizeof(key), key);
932	if (gctl_issue(req) == NULL) {
933		if (verbose)
934			printf("Attached to %s.\n", prov);
935	}
936	bzero(key, sizeof(key));
937}
938
939static void
940eli_configure_detached(struct gctl_req *req, const char *prov, int boot,
941    int geliboot, int displaypass, int trim)
942{
943	struct g_eli_metadata md;
944	bool changed = 0;
945
946	if (eli_metadata_read(req, prov, &md) == -1)
947		return;
948
949	if (boot == 1 && (md.md_flags & G_ELI_FLAG_BOOT)) {
950		if (verbose)
951			printf("BOOT flag already configured for %s.\n", prov);
952	} else if (boot == 0 && !(md.md_flags & G_ELI_FLAG_BOOT)) {
953		if (verbose)
954			printf("BOOT flag not configured for %s.\n", prov);
955	} else if (boot >= 0) {
956		if (boot)
957			md.md_flags |= G_ELI_FLAG_BOOT;
958		else
959			md.md_flags &= ~G_ELI_FLAG_BOOT;
960		changed = 1;
961	}
962
963	if (geliboot == 1 && (md.md_flags & G_ELI_FLAG_GELIBOOT)) {
964		if (verbose)
965			printf("GELIBOOT flag already configured for %s.\n", prov);
966	} else if (geliboot == 0 && !(md.md_flags & G_ELI_FLAG_GELIBOOT)) {
967		if (verbose)
968			printf("GELIBOOT flag not configured for %s.\n", prov);
969	} else if (geliboot >= 0) {
970		if (geliboot)
971			md.md_flags |= G_ELI_FLAG_GELIBOOT;
972		else
973			md.md_flags &= ~G_ELI_FLAG_GELIBOOT;
974		changed = 1;
975	}
976
977	if (displaypass == 1 && (md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
978		if (verbose)
979			printf("GELIDISPLAYPASS flag already configured for %s.\n", prov);
980	} else if (displaypass == 0 &&
981	    !(md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
982		if (verbose)
983			printf("GELIDISPLAYPASS flag not configured for %s.\n", prov);
984	} else if (displaypass >= 0) {
985		if (displaypass)
986			md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
987		else
988			md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
989		changed = 1;
990	}
991
992	if (trim == 0 && (md.md_flags & G_ELI_FLAG_NODELETE)) {
993		if (verbose)
994			printf("TRIM disable flag already configured for %s.\n", prov);
995	} else if (trim == 1 && !(md.md_flags & G_ELI_FLAG_NODELETE)) {
996		if (verbose)
997			printf("TRIM disable flag not configured for %s.\n", prov);
998	} else if (trim >= 0) {
999		if (trim)
1000			md.md_flags &= ~G_ELI_FLAG_NODELETE;
1001		else
1002			md.md_flags |= G_ELI_FLAG_NODELETE;
1003		changed = 1;
1004	}
1005
1006	if (changed)
1007		eli_metadata_store(req, prov, &md);
1008	bzero(&md, sizeof(md));
1009}
1010
1011static void
1012eli_configure(struct gctl_req *req)
1013{
1014	const char *prov;
1015	bool boot, noboot, geliboot, nogeliboot, displaypass, nodisplaypass;
1016	bool trim, notrim;
1017	int doboot, dogeliboot, dodisplaypass, dotrim;
1018	int i, nargs;
1019
1020	nargs = gctl_get_int(req, "nargs");
1021	if (nargs == 0) {
1022		gctl_error(req, "Too few arguments.");
1023		return;
1024	}
1025
1026	boot = gctl_get_int(req, "boot");
1027	noboot = gctl_get_int(req, "noboot");
1028	geliboot = gctl_get_int(req, "geliboot");
1029	nogeliboot = gctl_get_int(req, "nogeliboot");
1030	displaypass = gctl_get_int(req, "displaypass");
1031	nodisplaypass = gctl_get_int(req, "nodisplaypass");
1032	trim = gctl_get_int(req, "trim");
1033	notrim = gctl_get_int(req, "notrim");
1034
1035	doboot = -1;
1036	if (boot && noboot) {
1037		gctl_error(req, "Options -b and -B are mutually exclusive.");
1038		return;
1039	}
1040	if (boot)
1041		doboot = 1;
1042	else if (noboot)
1043		doboot = 0;
1044
1045	dogeliboot = -1;
1046	if (geliboot && nogeliboot) {
1047		gctl_error(req, "Options -g and -G are mutually exclusive.");
1048		return;
1049	}
1050	if (geliboot)
1051		dogeliboot = 1;
1052	else if (nogeliboot)
1053		dogeliboot = 0;
1054
1055	dodisplaypass = -1;
1056	if (displaypass && nodisplaypass) {
1057		gctl_error(req, "Options -d and -D are mutually exclusive.");
1058		return;
1059	}
1060	if (displaypass)
1061		dodisplaypass = 1;
1062	else if (nodisplaypass)
1063		dodisplaypass = 0;
1064
1065	dotrim = -1;
1066	if (trim && notrim) {
1067		gctl_error(req, "Options -t and -T are mutually exclusive.");
1068		return;
1069	}
1070	if (trim)
1071		dotrim = 1;
1072	else if (notrim)
1073		dotrim = 0;
1074
1075	if (doboot == -1 && dogeliboot == -1 && dodisplaypass == -1 &&
1076	    dotrim == -1) {
1077		gctl_error(req, "No option given.");
1078		return;
1079	}
1080
1081	/* First attached providers. */
1082	gctl_issue(req);
1083	/* Now the rest. */
1084	for (i = 0; i < nargs; i++) {
1085		prov = gctl_get_ascii(req, "arg%d", i);
1086		if (!eli_is_attached(prov)) {
1087			eli_configure_detached(req, prov, doboot, dogeliboot,
1088			    dodisplaypass, dotrim);
1089		}
1090	}
1091}
1092
1093static void
1094eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
1095{
1096	unsigned char key[G_ELI_USERKEYLEN];
1097	intmax_t val, old = 0;
1098	int error;
1099
1100	val = gctl_get_intmax(req, "iterations");
1101	/* Check if iterations number should be changed. */
1102	if (val != -1)
1103		md->md_iterations = val;
1104	else
1105		old = md->md_iterations;
1106
1107	/* Generate key for Master Key encryption. */
1108	if (eli_genkey(req, md, key, true) == NULL) {
1109		bzero(key, sizeof(key));
1110		return;
1111	}
1112	/*
1113	 * If number of iterations has changed, but wasn't given as a
1114	 * command-line argument, update the request.
1115	 */
1116	if (val == -1 && md->md_iterations != old) {
1117		error = gctl_change_param(req, "iterations", sizeof(intmax_t),
1118		    &md->md_iterations);
1119		assert(error == 0);
1120	}
1121
1122	gctl_ro_param(req, "key", sizeof(key), key);
1123	gctl_issue(req);
1124	bzero(key, sizeof(key));
1125}
1126
1127static void
1128eli_setkey_detached(struct gctl_req *req, const char *prov,
1129 struct g_eli_metadata *md)
1130{
1131	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
1132	unsigned char *mkeydst;
1133	unsigned int nkey;
1134	intmax_t val;
1135	int error;
1136
1137	if (md->md_keys == 0) {
1138		gctl_error(req, "No valid keys on %s.", prov);
1139		return;
1140	}
1141
1142	/* Generate key for Master Key decryption. */
1143	if (eli_genkey(req, md, key, false) == NULL) {
1144		bzero(key, sizeof(key));
1145		return;
1146	}
1147
1148	/* Decrypt Master Key. */
1149	error = g_eli_mkey_decrypt_any(md, key, mkey, &nkey);
1150	bzero(key, sizeof(key));
1151	if (error != 0) {
1152		bzero(md, sizeof(*md));
1153		if (error == -1)
1154			gctl_error(req, "Wrong key for %s.", prov);
1155		else /* if (error > 0) */ {
1156			gctl_error(req, "Cannot decrypt Master Key: %s.",
1157			    strerror(error));
1158		}
1159		return;
1160	}
1161	if (verbose)
1162		printf("Decrypted Master Key %u.\n", nkey);
1163
1164	val = gctl_get_intmax(req, "keyno");
1165	if (val != -1)
1166		nkey = val;
1167#if 0
1168	else
1169		; /* Use the key number which was found during decryption. */
1170#endif
1171	if (nkey >= G_ELI_MAXMKEYS) {
1172		gctl_error(req, "Invalid '%s' argument.", "keyno");
1173		return;
1174	}
1175
1176	val = gctl_get_intmax(req, "iterations");
1177	/* Check if iterations number should and can be changed. */
1178	if (val != -1 && md->md_iterations == -1) {
1179		md->md_iterations = val;
1180	} else if (val != -1 && val != md->md_iterations) {
1181		if (bitcount32(md->md_keys) != 1) {
1182			gctl_error(req, "To be able to use '-i' option, only "
1183			    "one key can be defined.");
1184			return;
1185		}
1186		if (md->md_keys != (1 << nkey)) {
1187			gctl_error(req, "Only already defined key can be "
1188			    "changed when '-i' option is used.");
1189			return;
1190		}
1191		md->md_iterations = val;
1192	}
1193
1194	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
1195	md->md_keys |= (1 << nkey);
1196
1197	bcopy(mkey, mkeydst, sizeof(mkey));
1198	bzero(mkey, sizeof(mkey));
1199
1200	/* Generate key for Master Key encryption. */
1201	if (eli_genkey(req, md, key, true) == NULL) {
1202		bzero(key, sizeof(key));
1203		bzero(md, sizeof(*md));
1204		return;
1205	}
1206
1207	/* Encrypt the Master-Key with the new key. */
1208	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
1209	bzero(key, sizeof(key));
1210	if (error != 0) {
1211		bzero(md, sizeof(*md));
1212		gctl_error(req, "Cannot encrypt Master Key: %s.",
1213		    strerror(error));
1214		return;
1215	}
1216
1217	/* Store metadata with fresh key. */
1218	eli_metadata_store(req, prov, md);
1219	bzero(md, sizeof(*md));
1220}
1221
1222static void
1223eli_setkey(struct gctl_req *req)
1224{
1225	struct g_eli_metadata md;
1226	const char *prov;
1227	int nargs;
1228
1229	nargs = gctl_get_int(req, "nargs");
1230	if (nargs != 1) {
1231		gctl_error(req, "Invalid number of arguments.");
1232		return;
1233	}
1234	prov = gctl_get_ascii(req, "arg0");
1235
1236	if (eli_metadata_read(req, prov, &md) == -1)
1237		return;
1238
1239	if (eli_is_attached(prov))
1240		eli_setkey_attached(req, &md);
1241	else
1242		eli_setkey_detached(req, prov, &md);
1243
1244	if (req->error == NULL || req->error[0] == '\0') {
1245		printf("Note, that the master key encrypted with old keys "
1246		    "and/or passphrase may still exists in a metadata backup "
1247		    "file.\n");
1248	}
1249}
1250
1251static void
1252eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
1253{
1254
1255	gctl_issue(req);
1256}
1257
1258static void
1259eli_delkey_detached(struct gctl_req *req, const char *prov)
1260{
1261	struct g_eli_metadata md;
1262	unsigned char *mkeydst;
1263	unsigned int nkey;
1264	intmax_t val;
1265	bool all, force;
1266
1267	if (eli_metadata_read(req, prov, &md) == -1)
1268		return;
1269
1270	all = gctl_get_int(req, "all");
1271	if (all)
1272		arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
1273	else {
1274		force = gctl_get_int(req, "force");
1275		val = gctl_get_intmax(req, "keyno");
1276		if (val == -1) {
1277			gctl_error(req, "Key number has to be specified.");
1278			return;
1279		}
1280		nkey = val;
1281		if (nkey >= G_ELI_MAXMKEYS) {
1282			gctl_error(req, "Invalid '%s' argument.", "keyno");
1283			return;
1284		}
1285		if (!(md.md_keys & (1 << nkey)) && !force) {
1286			gctl_error(req, "Master Key %u is not set.", nkey);
1287			return;
1288		}
1289		md.md_keys &= ~(1 << nkey);
1290		if (md.md_keys == 0 && !force) {
1291			gctl_error(req, "This is the last Master Key. Use '-f' "
1292			    "option if you really want to remove it.");
1293			return;
1294		}
1295		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
1296		arc4random_buf(mkeydst, G_ELI_MKEYLEN);
1297	}
1298
1299	eli_metadata_store(req, prov, &md);
1300	bzero(&md, sizeof(md));
1301}
1302
1303static void
1304eli_delkey(struct gctl_req *req)
1305{
1306	const char *prov;
1307	int nargs;
1308
1309	nargs = gctl_get_int(req, "nargs");
1310	if (nargs != 1) {
1311		gctl_error(req, "Invalid number of arguments.");
1312		return;
1313	}
1314	prov = gctl_get_ascii(req, "arg0");
1315
1316	if (eli_is_attached(prov))
1317		eli_delkey_attached(req, prov);
1318	else
1319		eli_delkey_detached(req, prov);
1320}
1321
1322static void
1323eli_resume(struct gctl_req *req)
1324{
1325	struct g_eli_metadata md;
1326	unsigned char key[G_ELI_USERKEYLEN];
1327	const char *prov;
1328	off_t mediasize;
1329	int nargs;
1330
1331	nargs = gctl_get_int(req, "nargs");
1332	if (nargs != 1) {
1333		gctl_error(req, "Invalid number of arguments.");
1334		return;
1335	}
1336	prov = gctl_get_ascii(req, "arg0");
1337
1338	if (eli_metadata_read(req, prov, &md) == -1)
1339		return;
1340
1341	mediasize = g_get_mediasize(prov);
1342	if (md.md_provsize != (uint64_t)mediasize) {
1343		gctl_error(req, "Provider size mismatch.");
1344		return;
1345	}
1346
1347	if (eli_genkey(req, &md, key, false) == NULL) {
1348		bzero(key, sizeof(key));
1349		return;
1350	}
1351
1352	gctl_ro_param(req, "key", sizeof(key), key);
1353	if (gctl_issue(req) == NULL) {
1354		if (verbose)
1355			printf("Resumed %s.\n", prov);
1356	}
1357	bzero(key, sizeof(key));
1358}
1359
1360static int
1361eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset)
1362{
1363	unsigned int overwrites;
1364	unsigned char *sector;
1365	ssize_t size;
1366	int error;
1367
1368	size = sizeof(overwrites);
1369	if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size,
1370	    NULL, 0) == -1 || overwrites == 0) {
1371		overwrites = G_ELI_OVERWRITES;
1372	}
1373
1374	size = g_sectorsize(fd);
1375	if (size <= 0) {
1376		gctl_error(req, "Cannot obtain provider sector size %s: %s.",
1377		    prov, strerror(errno));
1378		return (-1);
1379	}
1380	sector = malloc(size);
1381	if (sector == NULL) {
1382		gctl_error(req, "Cannot allocate %zd bytes of memory.", size);
1383		return (-1);
1384	}
1385
1386	error = 0;
1387	do {
1388		arc4random_buf(sector, size);
1389		if (pwrite(fd, sector, size, offset) != size) {
1390			if (error == 0)
1391				error = errno;
1392		}
1393		(void)g_flush(fd);
1394	} while (--overwrites > 0);
1395	free(sector);
1396	if (error != 0) {
1397		gctl_error(req, "Cannot trash metadata on provider %s: %s.",
1398		    prov, strerror(error));
1399		return (-1);
1400	}
1401	return (0);
1402}
1403
1404static void
1405eli_kill_detached(struct gctl_req *req, const char *prov)
1406{
1407	off_t offset;
1408	int fd;
1409
1410	/*
1411	 * NOTE: Maybe we should verify if this is geli provider first,
1412	 *       but 'kill' command is quite critical so better don't waste
1413	 *       the time.
1414	 */
1415#if 0
1416	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
1417	    G_ELI_MAGIC);
1418	if (error != 0) {
1419		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
1420		    strerror(error));
1421		return;
1422	}
1423#endif
1424
1425	fd = g_open(prov, 1);
1426	if (fd == -1) {
1427		gctl_error(req, "Cannot open provider %s: %s.", prov,
1428		    strerror(errno));
1429		return;
1430	}
1431	offset = g_mediasize(fd) - g_sectorsize(fd);
1432	if (offset <= 0) {
1433		gctl_error(req,
1434		    "Cannot obtain media size or sector size for provider %s: %s.",
1435		    prov, strerror(errno));
1436		(void)g_close(fd);
1437		return;
1438	}
1439	(void)eli_trash_metadata(req, prov, fd, offset);
1440	(void)g_close(fd);
1441}
1442
1443static void
1444eli_kill(struct gctl_req *req)
1445{
1446	const char *prov;
1447	int i, nargs, all;
1448
1449	nargs = gctl_get_int(req, "nargs");
1450	all = gctl_get_int(req, "all");
1451	if (!all && nargs == 0) {
1452		gctl_error(req, "Too few arguments.");
1453		return;
1454	}
1455	/*
1456	 * How '-a' option combine with a list of providers:
1457	 * Delete Master Keys from all attached providers:
1458	 * geli kill -a
1459	 * Delete Master Keys from all attached providers and from
1460	 * detached da0 and da1:
1461	 * geli kill -a da0 da1
1462	 * Delete Master Keys from (attached or detached) da0 and da1:
1463	 * geli kill da0 da1
1464	 */
1465
1466	/* First detached providers. */
1467	for (i = 0; i < nargs; i++) {
1468		prov = gctl_get_ascii(req, "arg%d", i);
1469		if (!eli_is_attached(prov))
1470			eli_kill_detached(req, prov);
1471	}
1472	/* Now attached providers. */
1473	gctl_issue(req);
1474}
1475
1476static int
1477eli_backup_create(struct gctl_req *req, const char *prov, const char *file)
1478{
1479	unsigned char *sector;
1480	ssize_t secsize;
1481	int error, filefd, ret;
1482
1483	ret = -1;
1484	filefd = -1;
1485	sector = NULL;
1486	secsize = 0;
1487
1488	secsize = g_get_sectorsize(prov);
1489	if (secsize == 0) {
1490		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1491		    strerror(errno));
1492		goto out;
1493	}
1494	sector = malloc(secsize);
1495	if (sector == NULL) {
1496		gctl_error(req, "Cannot allocate memory.");
1497		goto out;
1498	}
1499	/* Read metadata from the provider. */
1500	error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC);
1501	if (error != 0) {
1502		gctl_error(req, "Unable to read metadata from %s: %s.", prov,
1503		    strerror(error));
1504		goto out;
1505	}
1506
1507	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1508	if (filefd == -1) {
1509		gctl_error(req, "Unable to open %s: %s.", file,
1510		    strerror(errno));
1511		goto out;
1512	}
1513	/* Write metadata to the destination file. */
1514	if (write(filefd, sector, secsize) != secsize) {
1515		gctl_error(req, "Unable to write to %s: %s.", file,
1516		    strerror(errno));
1517		(void)close(filefd);
1518		(void)unlink(file);
1519		goto out;
1520	}
1521	(void)fsync(filefd);
1522	(void)close(filefd);
1523	/* Success. */
1524	ret = 0;
1525out:
1526	if (sector != NULL) {
1527		bzero(sector, secsize);
1528		free(sector);
1529	}
1530	return (ret);
1531}
1532
1533static void
1534eli_backup(struct gctl_req *req)
1535{
1536	const char *file, *prov;
1537	int nargs;
1538
1539	nargs = gctl_get_int(req, "nargs");
1540	if (nargs != 2) {
1541		gctl_error(req, "Invalid number of arguments.");
1542		return;
1543	}
1544	prov = gctl_get_ascii(req, "arg0");
1545	file = gctl_get_ascii(req, "arg1");
1546
1547	eli_backup_create(req, prov, file);
1548}
1549
1550static void
1551eli_restore(struct gctl_req *req)
1552{
1553	struct g_eli_metadata md;
1554	const char *file, *prov;
1555	off_t mediasize;
1556	int nargs;
1557
1558	nargs = gctl_get_int(req, "nargs");
1559	if (nargs != 2) {
1560		gctl_error(req, "Invalid number of arguments.");
1561		return;
1562	}
1563	file = gctl_get_ascii(req, "arg0");
1564	prov = gctl_get_ascii(req, "arg1");
1565
1566	/* Read metadata from the backup file. */
1567	if (eli_metadata_read(req, file, &md) == -1)
1568		return;
1569	/* Obtain provider's mediasize. */
1570	mediasize = g_get_mediasize(prov);
1571	if (mediasize == 0) {
1572		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1573		    strerror(errno));
1574		return;
1575	}
1576	/* Check if the provider size has changed since we did the backup. */
1577	if (md.md_provsize != (uint64_t)mediasize) {
1578		if (gctl_get_int(req, "force")) {
1579			md.md_provsize = mediasize;
1580		} else {
1581			gctl_error(req, "Provider size mismatch: "
1582			    "wrong backup file?");
1583			return;
1584		}
1585	}
1586	/* Write metadata to the provider. */
1587	(void)eli_metadata_store(req, prov, &md);
1588}
1589
1590static void
1591eli_resize(struct gctl_req *req)
1592{
1593	struct g_eli_metadata md;
1594	const char *prov;
1595	unsigned char *sector;
1596	ssize_t secsize;
1597	off_t mediasize, oldsize;
1598	int error, nargs, provfd;
1599
1600	nargs = gctl_get_int(req, "nargs");
1601	if (nargs != 1) {
1602		gctl_error(req, "Invalid number of arguments.");
1603		return;
1604	}
1605	prov = gctl_get_ascii(req, "arg0");
1606
1607	provfd = -1;
1608	sector = NULL;
1609	secsize = 0;
1610
1611	provfd = g_open(prov, 1);
1612	if (provfd == -1) {
1613		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1614		goto out;
1615	}
1616
1617	mediasize = g_mediasize(provfd);
1618	secsize = g_sectorsize(provfd);
1619	if (mediasize == -1 || secsize == -1) {
1620		gctl_error(req, "Cannot get information about %s: %s.", prov,
1621		    strerror(errno));
1622		goto out;
1623	}
1624
1625	sector = malloc(secsize);
1626	if (sector == NULL) {
1627		gctl_error(req, "Cannot allocate memory.");
1628		goto out;
1629	}
1630
1631	oldsize = gctl_get_intmax(req, "oldsize");
1632	if (oldsize < 0 || oldsize > mediasize) {
1633		gctl_error(req, "Invalid oldsize: Out of range.");
1634		goto out;
1635	}
1636	if (oldsize == mediasize) {
1637		gctl_error(req, "Size hasn't changed.");
1638		goto out;
1639	}
1640
1641	/* Read metadata from the 'oldsize' offset. */
1642	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
1643		gctl_error(req, "Cannot read old metadata: %s.",
1644		    strerror(errno));
1645		goto out;
1646	}
1647
1648	/* Check if this sector contains geli metadata. */
1649	error = eli_metadata_decode(sector, &md);
1650	switch (error) {
1651	case 0:
1652		break;
1653	case EOPNOTSUPP:
1654		gctl_error(req,
1655		    "Provider's %s metadata version %u is too new.\n"
1656		    "geli: The highest supported version is %u.",
1657		    prov, (unsigned int)md.md_version, G_ELI_VERSION);
1658		goto out;
1659	case EINVAL:
1660		gctl_error(req, "Inconsistent provider's %s metadata.", prov);
1661		goto out;
1662	default:
1663		gctl_error(req,
1664		    "Unexpected error while decoding provider's %s metadata: %s.",
1665		    prov, strerror(error));
1666		goto out;
1667	}
1668
1669	/*
1670	 * If the old metadata doesn't have a correct provider size, refuse
1671	 * to resize.
1672	 */
1673	if (md.md_provsize != (uint64_t)oldsize) {
1674		gctl_error(req, "Provider size mismatch at oldsize.");
1675		goto out;
1676	}
1677
1678	/*
1679	 * Update the old metadata with the current provider size and write
1680	 * it back to the correct place on the provider.
1681	 */
1682	md.md_provsize = mediasize;
1683	/* Write metadata to the provider. */
1684	(void)eli_metadata_store(req, prov, &md);
1685	/* Now trash the old metadata. */
1686	(void)eli_trash_metadata(req, prov, provfd, oldsize - secsize);
1687out:
1688	if (provfd != -1)
1689		(void)g_close(provfd);
1690	if (sector != NULL) {
1691		bzero(sector, secsize);
1692		free(sector);
1693	}
1694}
1695
1696static void
1697eli_version(struct gctl_req *req)
1698{
1699	struct g_eli_metadata md;
1700	const char *name;
1701	unsigned int version;
1702	int error, i, nargs;
1703
1704	nargs = gctl_get_int(req, "nargs");
1705
1706	if (nargs == 0) {
1707		unsigned int kernver;
1708		ssize_t size;
1709
1710		size = sizeof(kernver);
1711		if (sysctlbyname("kern.geom.eli.version", &kernver, &size,
1712		    NULL, 0) == -1) {
1713			warn("Unable to obtain GELI kernel version");
1714		} else {
1715			printf("kernel: %u\n", kernver);
1716		}
1717		printf("userland: %u\n", G_ELI_VERSION);
1718		return;
1719	}
1720
1721	for (i = 0; i < nargs; i++) {
1722		name = gctl_get_ascii(req, "arg%d", i);
1723		error = g_metadata_read(name, (unsigned char *)&md,
1724		    sizeof(md), G_ELI_MAGIC);
1725		if (error != 0) {
1726			warn("%s: Unable to read metadata: %s.", name,
1727			    strerror(error));
1728			gctl_error(req, "Not fully done.");
1729			continue;
1730		}
1731		version = le32dec(&md.md_version);
1732		printf("%s: %u\n", name, version);
1733	}
1734}
1735
1736static void
1737eli_clear(struct gctl_req *req)
1738{
1739	const char *name;
1740	int error, i, nargs;
1741
1742	nargs = gctl_get_int(req, "nargs");
1743	if (nargs < 1) {
1744		gctl_error(req, "Too few arguments.");
1745		return;
1746	}
1747
1748	for (i = 0; i < nargs; i++) {
1749		name = gctl_get_ascii(req, "arg%d", i);
1750		error = g_metadata_clear(name, G_ELI_MAGIC);
1751		if (error != 0) {
1752			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1753			    name, strerror(error));
1754			gctl_error(req, "Not fully done.");
1755			continue;
1756		}
1757		if (verbose)
1758			printf("Metadata cleared on %s.\n", name);
1759	}
1760}
1761
1762static void
1763eli_dump(struct gctl_req *req)
1764{
1765	struct g_eli_metadata md;
1766	const char *name;
1767	int i, nargs;
1768
1769	nargs = gctl_get_int(req, "nargs");
1770	if (nargs < 1) {
1771		gctl_error(req, "Too few arguments.");
1772		return;
1773	}
1774
1775	for (i = 0; i < nargs; i++) {
1776		name = gctl_get_ascii(req, "arg%d", i);
1777		if (eli_metadata_read(NULL, name, &md) == -1) {
1778			gctl_error(req, "Not fully done.");
1779			continue;
1780		}
1781		printf("Metadata on %s:\n", name);
1782		eli_metadata_dump(&md);
1783		printf("\n");
1784	}
1785}
1786