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