xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision 1669d8afc64812c8d2d1d147ae1fd42ff441e1b1)
1 /*-
2  * Copyright (c) 2005 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/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/bio.h>
37 #include <sys/sysctl.h>
38 #include <sys/malloc.h>
39 #include <sys/kthread.h>
40 #include <sys/proc.h>
41 #include <sys/sched.h>
42 #include <sys/uio.h>
43 
44 #include <vm/uma.h>
45 
46 #include <geom/geom.h>
47 #include <geom/eli/g_eli.h>
48 
49 
50 MALLOC_DECLARE(M_ELI);
51 
52 
53 static void
54 g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
55 {
56 	struct g_eli_metadata md;
57 	struct g_provider *pp;
58 	const char *name;
59 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
60 	int *nargs, *detach, *readonly;
61 	int keysize, error;
62 	u_int nkey;
63 
64 	g_topology_assert();
65 
66 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
67 	if (nargs == NULL) {
68 		gctl_error(req, "No '%s' argument.", "nargs");
69 		return;
70 	}
71 	if (*nargs != 1) {
72 		gctl_error(req, "Invalid number of arguments.");
73 		return;
74 	}
75 
76 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
77 	if (detach == NULL) {
78 		gctl_error(req, "No '%s' argument.", "detach");
79 		return;
80 	}
81 
82 	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
83 	if (readonly == NULL) {
84 		gctl_error(req, "No '%s' argument.", "readonly");
85 		return;
86 	}
87 
88 	name = gctl_get_asciiparam(req, "arg0");
89 	if (name == NULL) {
90 		gctl_error(req, "No 'arg%u' argument.", 0);
91 		return;
92 	}
93 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
94 		name += strlen("/dev/");
95 	pp = g_provider_by_name(name);
96 	if (pp == NULL) {
97 		gctl_error(req, "Provider %s is invalid.", name);
98 		return;
99 	}
100 	error = g_eli_read_metadata(mp, pp, &md);
101 	if (error != 0) {
102 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
103 		    name, error);
104 		return;
105 	}
106 	if (md.md_keys == 0x00) {
107 		bzero(&md, sizeof(md));
108 		gctl_error(req, "No valid keys on %s.", pp->name);
109 		return;
110 	}
111 
112 	key = gctl_get_param(req, "key", &keysize);
113 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
114 		bzero(&md, sizeof(md));
115 		gctl_error(req, "No '%s' argument.", "key");
116 		return;
117 	}
118 
119 	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
120 	bzero(key, keysize);
121 	if (error == -1) {
122 		bzero(&md, sizeof(md));
123 		gctl_error(req, "Wrong key for %s.", pp->name);
124 		return;
125 	} else if (error > 0) {
126 		bzero(&md, sizeof(md));
127 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
128 		    pp->name, error);
129 		return;
130 	}
131 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
132 
133 	if (*detach && *readonly) {
134 		bzero(&md, sizeof(md));
135 		gctl_error(req, "Options -d and -r are mutually exclusive.");
136 		return;
137 	}
138 	if (*detach)
139 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
140 	if (*readonly)
141 		md.md_flags |= G_ELI_FLAG_RO;
142 	g_eli_create(req, mp, pp, &md, mkey, nkey);
143 	bzero(mkey, sizeof(mkey));
144 	bzero(&md, sizeof(md));
145 }
146 
147 static struct g_eli_softc *
148 g_eli_find_device(struct g_class *mp, const char *prov)
149 {
150 	struct g_eli_softc *sc;
151 	struct g_geom *gp;
152 	struct g_provider *pp;
153 	struct g_consumer *cp;
154 
155 	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
156 		prov += strlen("/dev/");
157 	LIST_FOREACH(gp, &mp->geom, geom) {
158 		sc = gp->softc;
159 		if (sc == NULL)
160 			continue;
161 		pp = LIST_FIRST(&gp->provider);
162 		if (pp != NULL && strcmp(pp->name, prov) == 0)
163 			return (sc);
164 		cp = LIST_FIRST(&gp->consumer);
165 		if (cp != NULL && cp->provider != NULL &&
166 		    strcmp(cp->provider->name, prov) == 0) {
167 			return (sc);
168 		}
169 	}
170 	return (NULL);
171 }
172 
173 static void
174 g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
175 {
176 	struct g_eli_softc *sc;
177 	int *force, *last, *nargs, error;
178 	const char *prov;
179 	char param[16];
180 	int i;
181 
182 	g_topology_assert();
183 
184 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
185 	if (nargs == NULL) {
186 		gctl_error(req, "No '%s' argument.", "nargs");
187 		return;
188 	}
189 	if (*nargs <= 0) {
190 		gctl_error(req, "Missing device(s).");
191 		return;
192 	}
193 	force = gctl_get_paraml(req, "force", sizeof(*force));
194 	if (force == NULL) {
195 		gctl_error(req, "No '%s' argument.", "force");
196 		return;
197 	}
198 	last = gctl_get_paraml(req, "last", sizeof(*last));
199 	if (last == NULL) {
200 		gctl_error(req, "No '%s' argument.", "last");
201 		return;
202 	}
203 
204 	for (i = 0; i < *nargs; i++) {
205 		snprintf(param, sizeof(param), "arg%d", i);
206 		prov = gctl_get_asciiparam(req, param);
207 		if (prov == NULL) {
208 			gctl_error(req, "No 'arg%d' argument.", i);
209 			return;
210 		}
211 		sc = g_eli_find_device(mp, prov);
212 		if (sc == NULL) {
213 			gctl_error(req, "No such device: %s.", prov);
214 			return;
215 		}
216 		if (*last) {
217 			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
218 			sc->sc_geom->access = g_eli_access;
219 		} else {
220 			error = g_eli_destroy(sc, *force);
221 			if (error != 0) {
222 				gctl_error(req,
223 				    "Cannot destroy device %s (error=%d).",
224 				    sc->sc_name, error);
225 				return;
226 			}
227 		}
228 	}
229 }
230 
231 static void
232 g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
233 {
234 	struct g_eli_metadata md;
235 	struct g_provider *pp;
236 	const char *name;
237 	intmax_t *keylen, *sectorsize;
238 	u_char mkey[G_ELI_DATAIVKEYLEN];
239 	int *nargs, *detach;
240 
241 	g_topology_assert();
242 	bzero(&md, sizeof(md));
243 
244 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
245 	if (nargs == NULL) {
246 		gctl_error(req, "No '%s' argument.", "nargs");
247 		return;
248 	}
249 	if (*nargs != 1) {
250 		gctl_error(req, "Invalid number of arguments.");
251 		return;
252 	}
253 
254 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
255 	if (detach == NULL) {
256 		gctl_error(req, "No '%s' argument.", "detach");
257 		return;
258 	}
259 
260 	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
261 	md.md_version = G_ELI_VERSION;
262 	md.md_flags |= G_ELI_FLAG_ONETIME;
263 	if (*detach)
264 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
265 
266 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
267 	name = gctl_get_asciiparam(req, "aalgo");
268 	if (name == NULL) {
269 		gctl_error(req, "No '%s' argument.", "aalgo");
270 		return;
271 	}
272 	if (strcmp(name, "none") != 0) {
273 		md.md_aalgo = g_eli_str2aalgo(name);
274 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
275 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
276 			md.md_flags |= G_ELI_FLAG_AUTH;
277 		} else {
278 			/*
279 			 * For backward compatibility, check if the -a option
280 			 * was used to provide encryption algorithm.
281 			 */
282 			md.md_ealgo = g_eli_str2ealgo(name);
283 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
284 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
285 				gctl_error(req,
286 				    "Invalid authentication algorithm.");
287 				return;
288 			} else {
289 				gctl_error(req, "warning: The -e option, not "
290 				    "the -a option is now used to specify "
291 				    "encryption algorithm to use.");
292 			}
293 		}
294 	}
295 
296 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
297 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
298 		name = gctl_get_asciiparam(req, "ealgo");
299 		if (name == NULL) {
300 			gctl_error(req, "No '%s' argument.", "ealgo");
301 			return;
302 		}
303 		md.md_ealgo = g_eli_str2ealgo(name);
304 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
305 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
306 			gctl_error(req, "Invalid encryption algorithm.");
307 			return;
308 		}
309 	}
310 
311 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
312 	if (keylen == NULL) {
313 		gctl_error(req, "No '%s' argument.", "keylen");
314 		return;
315 	}
316 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
317 	if (md.md_keylen == 0) {
318 		gctl_error(req, "Invalid '%s' argument.", "keylen");
319 		return;
320 	}
321 
322 	/* Not important here. */
323 	md.md_provsize = 0;
324 	/* Not important here. */
325 	bzero(md.md_salt, sizeof(md.md_salt));
326 
327 	md.md_keys = 0x01;
328 	arc4rand(mkey, sizeof(mkey), 0);
329 
330 	/* Not important here. */
331 	bzero(md.md_hash, sizeof(md.md_hash));
332 
333 	name = gctl_get_asciiparam(req, "arg0");
334 	if (name == NULL) {
335 		gctl_error(req, "No 'arg%u' argument.", 0);
336 		return;
337 	}
338 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
339 		name += strlen("/dev/");
340 	pp = g_provider_by_name(name);
341 	if (pp == NULL) {
342 		gctl_error(req, "Provider %s is invalid.", name);
343 		return;
344 	}
345 
346 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
347 	if (sectorsize == NULL) {
348 		gctl_error(req, "No '%s' argument.", "sectorsize");
349 		return;
350 	}
351 	if (*sectorsize == 0)
352 		md.md_sectorsize = pp->sectorsize;
353 	else {
354 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
355 			gctl_error(req, "Invalid sector size.");
356 			return;
357 		}
358 		if (*sectorsize > PAGE_SIZE) {
359 			gctl_error(req, "warning: Using sectorsize bigger than "
360 			    "the page size!");
361 		}
362 		md.md_sectorsize = *sectorsize;
363 	}
364 
365 	g_eli_create(req, mp, pp, &md, mkey, -1);
366 	bzero(mkey, sizeof(mkey));
367 	bzero(&md, sizeof(md));
368 }
369 
370 static void
371 g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
372 {
373 	struct g_eli_softc *sc;
374 	struct g_eli_metadata md;
375 	struct g_provider *pp;
376 	struct g_consumer *cp;
377 	char param[16];
378 	const char *prov;
379 	u_char *sector;
380 	int *nargs, *boot, *noboot;
381 	int error;
382 	u_int i;
383 
384 	g_topology_assert();
385 
386 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
387 	if (nargs == NULL) {
388 		gctl_error(req, "No '%s' argument.", "nargs");
389 		return;
390 	}
391 	if (*nargs <= 0) {
392 		gctl_error(req, "Missing device(s).");
393 		return;
394 	}
395 
396 	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
397 	if (boot == NULL) {
398 		gctl_error(req, "No '%s' argument.", "boot");
399 		return;
400 	}
401 	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
402 	if (noboot == NULL) {
403 		gctl_error(req, "No '%s' argument.", "noboot");
404 		return;
405 	}
406 	if (*boot && *noboot) {
407 		gctl_error(req, "Options -b and -B are mutually exclusive.");
408 		return;
409 	}
410 	if (!*boot && !*noboot) {
411 		gctl_error(req, "No option given.");
412 		return;
413 	}
414 
415 	for (i = 0; i < *nargs; i++) {
416 		snprintf(param, sizeof(param), "arg%d", i);
417 		prov = gctl_get_asciiparam(req, param);
418 		if (prov == NULL) {
419 			gctl_error(req, "No 'arg%d' argument.", i);
420 			return;
421 		}
422 		sc = g_eli_find_device(mp, prov);
423 		if (sc == NULL) {
424 			/*
425 			 * We ignore not attached providers, userland part will
426 			 * take care of them.
427 			 */
428 			G_ELI_DEBUG(1, "Skipping configuration of not attached "
429 			    "provider %s.", prov);
430 			continue;
431 		}
432 		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
433 			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
434 			    prov);
435 			continue;
436 		} else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
437 			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
438 			    prov);
439 			continue;
440 		}
441 		if (sc->sc_flags & G_ELI_FLAG_RO) {
442 			gctl_error(req, "Cannot change configuration of "
443 			    "read-only provider %s.", prov);
444 			continue;
445 		}
446 		cp = LIST_FIRST(&sc->sc_geom->consumer);
447 		pp = cp->provider;
448 		error = g_eli_read_metadata(mp, pp, &md);
449 		if (error != 0) {
450 			gctl_error(req,
451 			    "Cannot read metadata from %s (error=%d).",
452 			    prov, error);
453 			continue;
454 		}
455 
456 		if (*boot) {
457 			md.md_flags |= G_ELI_FLAG_BOOT;
458 			sc->sc_flags |= G_ELI_FLAG_BOOT;
459 		} else {
460 			md.md_flags &= ~G_ELI_FLAG_BOOT;
461 			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
462 		}
463 
464 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
465 		eli_metadata_encode(&md, sector);
466 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
467 		    pp->sectorsize);
468 		if (error != 0) {
469 			gctl_error(req,
470 			    "Cannot store metadata on %s (error=%d).",
471 			    prov, error);
472 		}
473 		bzero(&md, sizeof(md));
474 		bzero(sector, sizeof(sector));
475 		free(sector, M_ELI);
476 	}
477 }
478 
479 static void
480 g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
481 {
482 	struct g_eli_softc *sc;
483 	struct g_eli_metadata md;
484 	struct g_provider *pp;
485 	struct g_consumer *cp;
486 	const char *name;
487 	u_char *key, *mkeydst, *sector;
488 	intmax_t *valp;
489 	int keysize, nkey, error;
490 
491 	g_topology_assert();
492 
493 	name = gctl_get_asciiparam(req, "arg0");
494 	if (name == NULL) {
495 		gctl_error(req, "No 'arg%u' argument.", 0);
496 		return;
497 	}
498 	sc = g_eli_find_device(mp, name);
499 	if (sc == NULL) {
500 		gctl_error(req, "Provider %s is invalid.", name);
501 		return;
502 	}
503 	if (sc->sc_flags & G_ELI_FLAG_RO) {
504 		gctl_error(req, "Cannot change keys for read-only provider.");
505 		return;
506 	}
507 	cp = LIST_FIRST(&sc->sc_geom->consumer);
508 	pp = cp->provider;
509 
510 	error = g_eli_read_metadata(mp, pp, &md);
511 	if (error != 0) {
512 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
513 		    name, error);
514 		return;
515 	}
516 
517 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
518 	if (valp == NULL) {
519 		gctl_error(req, "No '%s' argument.", "keyno");
520 		return;
521 	}
522 	if (*valp != -1)
523 		nkey = *valp;
524 	else
525 		nkey = sc->sc_nkey;
526 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
527 		gctl_error(req, "Invalid '%s' argument.", "keyno");
528 		return;
529 	}
530 
531 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
532 	if (valp == NULL) {
533 		gctl_error(req, "No '%s' argument.", "iterations");
534 		return;
535 	}
536 	/* Check if iterations number should and can be changed. */
537 	if (*valp != -1) {
538 		if (bitcount32(md.md_keys) != 1) {
539 			gctl_error(req, "To be able to use '-i' option, only "
540 			    "one key can be defined.");
541 			return;
542 		}
543 		if (md.md_keys != (1 << nkey)) {
544 			gctl_error(req, "Only already defined key can be "
545 			    "changed when '-i' option is used.");
546 			return;
547 		}
548 		md.md_iterations = *valp;
549 	}
550 
551 	key = gctl_get_param(req, "key", &keysize);
552 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
553 		bzero(&md, sizeof(md));
554 		gctl_error(req, "No '%s' argument.", "key");
555 		return;
556 	}
557 
558 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
559 	md.md_keys |= (1 << nkey);
560 
561 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
562 
563 	/* Encrypt Master Key with the new key. */
564 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
565 	bzero(key, sizeof(key));
566 	if (error != 0) {
567 		bzero(&md, sizeof(md));
568 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
569 		return;
570 	}
571 
572 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
573 	/* Store metadata with fresh key. */
574 	eli_metadata_encode(&md, sector);
575 	bzero(&md, sizeof(md));
576 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
577 	    pp->sectorsize);
578 	bzero(sector, sizeof(sector));
579 	free(sector, M_ELI);
580 	if (error != 0) {
581 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
582 		    pp->name, error);
583 		return;
584 	}
585 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
586 }
587 
588 static void
589 g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
590 {
591 	struct g_eli_softc *sc;
592 	struct g_eli_metadata md;
593 	struct g_provider *pp;
594 	struct g_consumer *cp;
595 	const char *name;
596 	u_char *mkeydst, *sector;
597 	intmax_t *valp;
598 	size_t keysize;
599 	int error, nkey, *all, *force;
600 	u_int i;
601 
602 	g_topology_assert();
603 
604 	nkey = 0;	/* fixes causeless gcc warning */
605 
606 	name = gctl_get_asciiparam(req, "arg0");
607 	if (name == NULL) {
608 		gctl_error(req, "No 'arg%u' argument.", 0);
609 		return;
610 	}
611 	sc = g_eli_find_device(mp, name);
612 	if (sc == NULL) {
613 		gctl_error(req, "Provider %s is invalid.", name);
614 		return;
615 	}
616 	if (sc->sc_flags & G_ELI_FLAG_RO) {
617 		gctl_error(req, "Cannot delete keys for read-only provider.");
618 		return;
619 	}
620 	cp = LIST_FIRST(&sc->sc_geom->consumer);
621 	pp = cp->provider;
622 
623 	error = g_eli_read_metadata(mp, pp, &md);
624 	if (error != 0) {
625 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
626 		    name, error);
627 		return;
628 	}
629 
630 	all = gctl_get_paraml(req, "all", sizeof(*all));
631 	if (all == NULL) {
632 		gctl_error(req, "No '%s' argument.", "all");
633 		return;
634 	}
635 
636 	if (*all) {
637 		mkeydst = md.md_mkeys;
638 		keysize = sizeof(md.md_mkeys);
639 	} else {
640 		force = gctl_get_paraml(req, "force", sizeof(*force));
641 		if (force == NULL) {
642 			gctl_error(req, "No '%s' argument.", "force");
643 			return;
644 		}
645 
646 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
647 		if (valp == NULL) {
648 			gctl_error(req, "No '%s' argument.", "keyno");
649 			return;
650 		}
651 		if (*valp != -1)
652 			nkey = *valp;
653 		else
654 			nkey = sc->sc_nkey;
655 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
656 			gctl_error(req, "Invalid '%s' argument.", "keyno");
657 			return;
658 		}
659 		if (!(md.md_keys & (1 << nkey)) && !*force) {
660 			gctl_error(req, "Master Key %u is not set.", nkey);
661 			return;
662 		}
663 		md.md_keys &= ~(1 << nkey);
664 		if (md.md_keys == 0 && !*force) {
665 			gctl_error(req, "This is the last Master Key. Use '-f' "
666 			    "flag if you really want to remove it.");
667 			return;
668 		}
669 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
670 		keysize = G_ELI_MKEYLEN;
671 	}
672 
673 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
674 	for (i = 0; i <= g_eli_overwrites; i++) {
675 		if (i == g_eli_overwrites)
676 			bzero(mkeydst, keysize);
677 		else
678 			arc4rand(mkeydst, keysize, 0);
679 		/* Store metadata with destroyed key. */
680 		eli_metadata_encode(&md, sector);
681 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
682 		    pp->sectorsize);
683 		if (error != 0) {
684 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
685 			    "(error=%d).", pp->name, error);
686 		}
687 		/*
688 		 * Flush write cache so we don't overwrite data N times in cache
689 		 * and only once on disk.
690 		 */
691 		g_io_flush(cp);
692 	}
693 	bzero(&md, sizeof(md));
694 	bzero(sector, sizeof(sector));
695 	free(sector, M_ELI);
696 	if (*all)
697 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
698 	else
699 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
700 }
701 
702 static int
703 g_eli_kill_one(struct g_eli_softc *sc)
704 {
705 	struct g_provider *pp;
706 	struct g_consumer *cp;
707 	int error = 0;
708 
709 	g_topology_assert();
710 
711 	if (sc == NULL)
712 		return (ENOENT);
713 
714 	pp = LIST_FIRST(&sc->sc_geom->provider);
715 	g_error_provider(pp, ENXIO);
716 
717 	cp = LIST_FIRST(&sc->sc_geom->consumer);
718 	pp = cp->provider;
719 
720 	if (sc->sc_flags & G_ELI_FLAG_RO) {
721 		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
722 		    "provider: %s.", pp->name);
723 	} else {
724 		u_char *sector;
725 		u_int i;
726 		int err;
727 
728 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
729 		for (i = 0; i <= g_eli_overwrites; i++) {
730 			if (i == g_eli_overwrites)
731 				bzero(sector, pp->sectorsize);
732 			else
733 				arc4rand(sector, pp->sectorsize, 0);
734 			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
735 			    sector, pp->sectorsize);
736 			if (err != 0) {
737 				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
738 				    "(error=%d).", pp->name, err);
739 				if (error == 0)
740 					error = err;
741 			}
742 		}
743 		free(sector, M_ELI);
744 	}
745 	if (error == 0)
746 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
747 	g_eli_destroy(sc, 1);
748 	return (error);
749 }
750 
751 static void
752 g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
753 {
754 	int *all, *nargs;
755 	int error;
756 
757 	g_topology_assert();
758 
759 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
760 	if (nargs == NULL) {
761 		gctl_error(req, "No '%s' argument.", "nargs");
762 		return;
763 	}
764 	all = gctl_get_paraml(req, "all", sizeof(*all));
765 	if (all == NULL) {
766 		gctl_error(req, "No '%s' argument.", "all");
767 		return;
768 	}
769 	if (!*all && *nargs == 0) {
770 		gctl_error(req, "Too few arguments.");
771 		return;
772 	}
773 
774 	if (*all) {
775 		struct g_geom *gp, *gp2;
776 
777 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
778 			error = g_eli_kill_one(gp->softc);
779 			if (error != 0)
780 				gctl_error(req, "Not fully done.");
781 		}
782 	} else {
783 		struct g_eli_softc *sc;
784 		const char *prov;
785 		char param[16];
786 		int i;
787 
788 		for (i = 0; i < *nargs; i++) {
789 			snprintf(param, sizeof(param), "arg%d", i);
790 			prov = gctl_get_asciiparam(req, param);
791 			if (prov == NULL) {
792 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
793 				continue;
794 			}
795 
796 			sc = g_eli_find_device(mp, prov);
797 			if (sc == NULL) {
798 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
799 				continue;
800 			}
801 			error = g_eli_kill_one(sc);
802 			if (error != 0)
803 				gctl_error(req, "Not fully done.");
804 		}
805 	}
806 }
807 
808 void
809 g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
810 {
811 	uint32_t *version;
812 
813 	g_topology_assert();
814 
815 	version = gctl_get_paraml(req, "version", sizeof(*version));
816 	if (version == NULL) {
817 		gctl_error(req, "No '%s' argument.", "version");
818 		return;
819 	}
820 	if (*version != G_ELI_VERSION) {
821 		gctl_error(req, "Userland and kernel parts are out of sync.");
822 		return;
823 	}
824 
825 	if (strcmp(verb, "attach") == 0)
826 		g_eli_ctl_attach(req, mp);
827 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
828 		g_eli_ctl_detach(req, mp);
829 	else if (strcmp(verb, "onetime") == 0)
830 		g_eli_ctl_onetime(req, mp);
831 	else if (strcmp(verb, "configure") == 0)
832 		g_eli_ctl_configure(req, mp);
833 	else if (strcmp(verb, "setkey") == 0)
834 		g_eli_ctl_setkey(req, mp);
835 	else if (strcmp(verb, "delkey") == 0)
836 		g_eli_ctl_delkey(req, mp);
837 	else if (strcmp(verb, "kill") == 0)
838 		g_eli_ctl_kill(req, mp);
839 	else
840 		gctl_error(req, "Unknown verb.");
841 }
842