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