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