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