g_eli_ctl.c revision 154462
1131377Stjr/*-
2131377Stjr * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3131377Stjr * All rights reserved.
4131377Stjr *
5131377Stjr * Redistribution and use in source and binary forms, with or without
6131377Stjr * modification, are permitted provided that the following conditions
7131377Stjr * are met:
8131377Stjr * 1. Redistributions of source code must retain the above copyright
9131377Stjr *    notice, this list of conditions and the following disclaimer.
10131377Stjr * 2. Redistributions in binary form must reproduce the above copyright
11131377Stjr *    notice, this list of conditions and the following disclaimer in the
12131377Stjr *    documentation and/or other materials provided with the distribution.
13131377Stjr *
14131377Stjr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15131377Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16131377Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17131377Stjr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18131377Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19131377Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20131377Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21131377Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22131377Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23131377Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24131377Stjr * SUCH DAMAGE.
25131377Stjr */
26131377Stjr
27131377Stjr#include <sys/cdefs.h>
28131377Stjr__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 154462 2006-01-17 07:30:34Z pjd $");
29131377Stjr
30131377Stjr#include <sys/param.h>
31131377Stjr#include <sys/systm.h>
32131377Stjr#include <sys/kernel.h>
33131377Stjr#include <sys/module.h>
34131377Stjr#include <sys/lock.h>
35131377Stjr#include <sys/mutex.h>
36131377Stjr#include <sys/bio.h>
37131377Stjr#include <sys/sysctl.h>
38131377Stjr#include <sys/malloc.h>
39131377Stjr#include <sys/kthread.h>
40131377Stjr#include <sys/proc.h>
41131377Stjr#include <sys/sched.h>
42131377Stjr#include <sys/uio.h>
43131377Stjr
44131377Stjr#include <vm/uma.h>
45131377Stjr
46131377Stjr#include <geom/geom.h>
47131377Stjr#include <geom/eli/g_eli.h>
48131377Stjr
49131377Stjr
50131377StjrMALLOC_DECLARE(M_ELI);
51131377Stjr
52131377Stjr
53131377Stjrstatic void
54131377Stjrg_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
55131377Stjr{
56131377Stjr	struct g_eli_metadata md;
57131377Stjr	struct g_provider *pp;
58131377Stjr	const char *name;
59131377Stjr	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
60131377Stjr	int *nargs, *detach;
61131377Stjr	int keysize, error;
62131377Stjr	u_int nkey;
63131377Stjr
64131377Stjr	g_topology_assert();
65131377Stjr
66131377Stjr	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
67131377Stjr	if (nargs == NULL) {
68131377Stjr		gctl_error(req, "No '%s' argument.", "nargs");
69131377Stjr		return;
70131377Stjr	}
71131377Stjr	if (*nargs != 1) {
72131377Stjr		gctl_error(req, "Invalid number of arguments.");
73131377Stjr		return;
74131377Stjr	}
75131377Stjr
76131377Stjr	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
77131377Stjr	if (detach == NULL) {
78131377Stjr		gctl_error(req, "No '%s' argument.", "detach");
79131377Stjr		return;
80131377Stjr	}
81131377Stjr
82131377Stjr	name = gctl_get_asciiparam(req, "arg0");
83131377Stjr	if (name == NULL) {
84131377Stjr		gctl_error(req, "No 'arg%u' argument.", 0);
85131377Stjr		return;
86131377Stjr	}
87131377Stjr	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
88131377Stjr		name += strlen("/dev/");
89131377Stjr	pp = g_provider_by_name(name);
90131377Stjr	if (pp == NULL) {
91131377Stjr		gctl_error(req, "Provider %s is invalid.", name);
92131377Stjr		return;
93131377Stjr	}
94131377Stjr	error = g_eli_read_metadata(mp, pp, &md);
95131377Stjr	if (error != 0) {
96131377Stjr		gctl_error(req, "Cannot read metadata from %s (error=%d).",
97131377Stjr		    name, error);
98131377Stjr		return;
99131377Stjr	}
100131377Stjr	if (md.md_keys == 0x00) {
101131377Stjr		bzero(&md, sizeof(md));
102131377Stjr		gctl_error(req, "No valid keys on %s.", pp->name);
103131377Stjr		return;
104131377Stjr	}
105131377Stjr
106131377Stjr	key = gctl_get_param(req, "key", &keysize);
107131377Stjr	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
108131377Stjr		bzero(&md, sizeof(md));
109131377Stjr		gctl_error(req, "No '%s' argument.", "key");
110131377Stjr		return;
111131377Stjr	}
112131377Stjr
113131377Stjr	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
114131377Stjr	bzero(key, keysize);
115131377Stjr	if (error == -1) {
116131377Stjr		bzero(&md, sizeof(md));
117131377Stjr		gctl_error(req, "Wrong key for %s.", pp->name);
118131377Stjr		return;
119131377Stjr	} else if (error > 0) {
120131377Stjr		bzero(&md, sizeof(md));
121131377Stjr		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
122131377Stjr		    pp->name, error);
123131377Stjr		return;
124131377Stjr	}
125131377Stjr	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
126131377Stjr
127131377Stjr	if (*detach)
128131377Stjr		md.md_flags |= G_ELI_FLAG_WO_DETACH;
129131377Stjr	g_eli_create(req, mp, pp, &md, mkey, nkey);
130131377Stjr	bzero(mkey, sizeof(mkey));
131131377Stjr	bzero(&md, sizeof(md));
132131377Stjr}
133131377Stjr
134131377Stjrstatic struct g_eli_softc *
135131377Stjrg_eli_find_device(struct g_class *mp, const char *prov)
136131377Stjr{
137131377Stjr	struct g_eli_softc *sc;
138131377Stjr	struct g_geom *gp;
139131377Stjr	struct g_provider *pp;
140131377Stjr	struct g_consumer *cp;
141131377Stjr
142131377Stjr	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
143131377Stjr		prov += strlen("/dev/");
144131377Stjr	LIST_FOREACH(gp, &mp->geom, geom) {
145131377Stjr		sc = gp->softc;
146131377Stjr		if (sc == NULL)
147131377Stjr			continue;
148131377Stjr		pp = LIST_FIRST(&gp->provider);
149131377Stjr		if (pp != NULL && strcmp(pp->name, prov) == 0)
150131377Stjr			return (sc);
151131377Stjr		cp = LIST_FIRST(&gp->consumer);
152131377Stjr		if (cp != NULL && cp->provider != NULL &&
153131377Stjr		    strcmp(cp->provider->name, prov) == 0) {
154131377Stjr			return (sc);
155131377Stjr		}
156131377Stjr	}
157131377Stjr	return (NULL);
158131377Stjr}
159131377Stjr
160131377Stjrstatic void
161131377Stjrg_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
162131377Stjr{
163131377Stjr	struct g_eli_softc *sc;
164131377Stjr	int *force, *last, *nargs, error;
165131377Stjr	const char *prov;
166131377Stjr	char param[16];
167131377Stjr	u_int i;
168131377Stjr
169131377Stjr	g_topology_assert();
170131377Stjr
171131377Stjr	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
172131377Stjr	if (nargs == NULL) {
173131377Stjr		gctl_error(req, "No '%s' argument.", "nargs");
174131377Stjr		return;
175131377Stjr	}
176131377Stjr	if (*nargs <= 0) {
177131377Stjr		gctl_error(req, "Missing device(s).");
178131377Stjr		return;
179131377Stjr	}
180131377Stjr	force = gctl_get_paraml(req, "force", sizeof(*force));
181131377Stjr	if (force == NULL) {
182131377Stjr		gctl_error(req, "No '%s' argument.", "force");
183131377Stjr		return;
184131377Stjr	}
185131377Stjr	last = gctl_get_paraml(req, "last", sizeof(*last));
186131377Stjr	if (last == NULL) {
187131377Stjr		gctl_error(req, "No '%s' argument.", "last");
188131377Stjr		return;
189131377Stjr	}
190131377Stjr
191131377Stjr	for (i = 0; i < (u_int)*nargs; i++) {
192131377Stjr		snprintf(param, sizeof(param), "arg%u", i);
193131377Stjr		prov = gctl_get_asciiparam(req, param);
194131377Stjr		if (prov == NULL) {
195131377Stjr			gctl_error(req, "No 'arg%u' argument.", i);
196131377Stjr			return;
197131377Stjr		}
198131377Stjr		sc = g_eli_find_device(mp, prov);
199131377Stjr		if (sc == NULL) {
200131377Stjr			gctl_error(req, "No such device: %s.", prov);
201131377Stjr			return;
202131377Stjr		}
203131377Stjr		if (*last) {
204131377Stjr			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
205131377Stjr			sc->sc_geom->access = g_eli_access;
206131377Stjr		} else {
207131377Stjr			error = g_eli_destroy(sc, *force);
208131377Stjr			if (error != 0) {
209131377Stjr				gctl_error(req,
210131377Stjr				    "Cannot destroy device %s (error=%d).",
211131377Stjr				    sc->sc_name, error);
212131377Stjr				return;
213131377Stjr			}
214131377Stjr		}
215131377Stjr	}
216131377Stjr}
217131377Stjr
218131377Stjrstatic void
219131377Stjrg_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
220131377Stjr{
221131377Stjr	struct g_eli_metadata md;
222131377Stjr	struct g_provider *pp;
223131377Stjr	const char *name;
224131377Stjr	intmax_t *keylen, *sectorsize;
225131377Stjr	u_char mkey[G_ELI_DATAIVKEYLEN];
226131377Stjr	int *nargs, *detach;
227131377Stjr
228131377Stjr	g_topology_assert();
229131377Stjr	bzero(&md, sizeof(md));
230131377Stjr
231131377Stjr	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
232131377Stjr	if (nargs == NULL) {
233131377Stjr		gctl_error(req, "No '%s' argument.", "nargs");
234131377Stjr		return;
235131377Stjr	}
236131377Stjr	if (*nargs != 1) {
237131377Stjr		gctl_error(req, "Invalid number of arguments.");
238131377Stjr		return;
239131377Stjr	}
240131377Stjr
241131377Stjr	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
242131377Stjr	if (detach == NULL) {
243131377Stjr		gctl_error(req, "No '%s' argument.", "detach");
244131377Stjr		return;
245131377Stjr	}
246131377Stjr
247131377Stjr	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
248131377Stjr	md.md_version = G_ELI_VERSION;
249131377Stjr	md.md_flags |= G_ELI_FLAG_ONETIME;
250131377Stjr	if (*detach)
251131377Stjr		md.md_flags |= G_ELI_FLAG_WO_DETACH;
252131377Stjr
253131377Stjr	name = gctl_get_asciiparam(req, "algo");
254131377Stjr	if (name == NULL) {
255131377Stjr		gctl_error(req, "No '%s' argument.", "algo");
256131377Stjr		return;
257131377Stjr	}
258131377Stjr	md.md_algo = g_eli_str2algo(name);
259131377Stjr	if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
260131377Stjr	    md.md_algo > CRYPTO_ALGORITHM_MAX) {
261131377Stjr		gctl_error(req, "Invalid '%s' argument.", "algo");
262131377Stjr		return;
263131377Stjr	}
264131377Stjr
265131377Stjr	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
266131377Stjr	if (keylen == NULL) {
267131377Stjr		gctl_error(req, "No '%s' argument.", "keylen");
268131377Stjr		return;
269131377Stjr	}
270131377Stjr	md.md_keylen = g_eli_keylen(md.md_algo, *keylen);
271131377Stjr	if (md.md_keylen == 0) {
272131377Stjr		gctl_error(req, "Invalid '%s' argument.", "keylen");
273131377Stjr		return;
274131377Stjr	}
275131377Stjr
276131377Stjr	/* Not important here. */
277131377Stjr	md.md_provsize = 0;
278131377Stjr	/* Not important here. */
279131377Stjr	bzero(md.md_salt, sizeof(md.md_salt));
280131377Stjr
281131377Stjr	md.md_keys = 0x01;
282131377Stjr	arc4rand(mkey, sizeof(mkey), 0);
283131377Stjr
284131377Stjr	/* Not important here. */
285131377Stjr	bzero(md.md_hash, sizeof(md.md_hash));
286131377Stjr
287131377Stjr	name = gctl_get_asciiparam(req, "arg0");
288131377Stjr	if (name == NULL) {
289131377Stjr		gctl_error(req, "No 'arg%u' argument.", 0);
290131377Stjr		return;
291131377Stjr	}
292131377Stjr	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
293131377Stjr		name += strlen("/dev/");
294131377Stjr	pp = g_provider_by_name(name);
295131377Stjr	if (pp == NULL) {
296131377Stjr		gctl_error(req, "Provider %s is invalid.", name);
297131377Stjr		return;
298131377Stjr	}
299131377Stjr
300131377Stjr	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
301131377Stjr	if (sectorsize == NULL) {
302131377Stjr		gctl_error(req, "No '%s' argument.", "sectorsize");
303131377Stjr		return;
304131377Stjr	}
305131377Stjr	if (*sectorsize == 0)
306131377Stjr		md.md_sectorsize = pp->sectorsize;
307131377Stjr	else {
308131377Stjr		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
309131377Stjr			gctl_error(req, "Invalid sector size.");
310131377Stjr			return;
311131377Stjr		}
312131377Stjr		md.md_sectorsize = *sectorsize;
313131377Stjr	}
314131377Stjr
315131377Stjr	g_eli_create(req, mp, pp, &md, mkey, -1);
316131377Stjr	bzero(mkey, sizeof(mkey));
317131377Stjr	bzero(&md, sizeof(md));
318131377Stjr}
319131377Stjr
320131377Stjrstatic void
321131377Stjrg_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
322131377Stjr{
323131377Stjr	struct g_eli_softc *sc;
324131377Stjr	struct g_eli_metadata md;
325131377Stjr	struct g_provider *pp;
326131377Stjr	struct g_consumer *cp;
327131377Stjr	const char *name;
328131377Stjr	u_char *key, *mkeydst, *sector;
329131377Stjr	intmax_t *valp;
330131377Stjr	int keysize, nkey, error;
331131377Stjr
332131377Stjr	g_topology_assert();
333131377Stjr
334131377Stjr	name = gctl_get_asciiparam(req, "arg0");
335131377Stjr	if (name == NULL) {
336131377Stjr		gctl_error(req, "No 'arg%u' argument.", 0);
337131377Stjr		return;
338131377Stjr	}
339131377Stjr	sc = g_eli_find_device(mp, name);
340131377Stjr	if (sc == NULL) {
341131377Stjr		gctl_error(req, "Provider %s is invalid.", name);
342131377Stjr		return;
343131377Stjr	}
344131377Stjr	cp = LIST_FIRST(&sc->sc_geom->consumer);
345131377Stjr	pp = cp->provider;
346131377Stjr
347131377Stjr	error = g_eli_read_metadata(mp, pp, &md);
348131377Stjr	if (error != 0) {
349131377Stjr		gctl_error(req, "Cannot read metadata from %s (error=%d).",
350131377Stjr		    name, error);
351131377Stjr		return;
352131377Stjr	}
353131377Stjr
354131377Stjr	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
355131377Stjr	if (valp == NULL) {
356131377Stjr		gctl_error(req, "No '%s' argument.", "keyno");
357131377Stjr		return;
358131377Stjr	}
359131377Stjr	if (*valp != -1)
360131377Stjr		nkey = *valp;
361131377Stjr	else
362131377Stjr		nkey = sc->sc_nkey;
363131377Stjr	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
364131377Stjr		gctl_error(req, "Invalid '%s' argument.", "keyno");
365131377Stjr		return;
366131377Stjr	}
367131377Stjr
368131377Stjr	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
369131377Stjr	if (valp == NULL) {
370131377Stjr		gctl_error(req, "No '%s' argument.", "iterations");
371131377Stjr		return;
372131377Stjr	}
373131377Stjr	/* Check if iterations number should and can be changed. */
374131377Stjr	if (*valp != -1) {
375131377Stjr		if (bitcount32(md.md_keys) != 1) {
376131377Stjr			gctl_error(req, "To be able to use '-i' option, only "
377131377Stjr			    "one key can be defined.");
378131377Stjr			return;
379131377Stjr		}
380131377Stjr		if (md.md_keys != (1 << nkey)) {
381131377Stjr			gctl_error(req, "Only already defined key can be "
382131377Stjr			    "changed when '-i' option is used.");
383131377Stjr			return;
384131377Stjr		}
385131377Stjr		md.md_iterations = *valp;
386131377Stjr	}
387131377Stjr
388131377Stjr	key = gctl_get_param(req, "key", &keysize);
389131377Stjr	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
390131377Stjr		bzero(&md, sizeof(md));
391131377Stjr		gctl_error(req, "No '%s' argument.", "key");
392131377Stjr		return;
393131377Stjr	}
394131377Stjr
395131377Stjr	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
396131377Stjr	md.md_keys |= (1 << nkey);
397131377Stjr
398131377Stjr	bcopy(sc->sc_ivkey, mkeydst, sizeof(sc->sc_ivkey));
399131377Stjr	bcopy(sc->sc_datakey, mkeydst + sizeof(sc->sc_ivkey),
400131377Stjr	    sizeof(sc->sc_datakey));
401131377Stjr
402131377Stjr	/* Encrypt Master Key with the new key. */
403131377Stjr	error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst);
404131377Stjr	bzero(key, sizeof(key));
405131377Stjr	if (error != 0) {
406131377Stjr		bzero(&md, sizeof(md));
407131377Stjr		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
408131377Stjr		return;
409131377Stjr	}
410131377Stjr
411131377Stjr	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
412131377Stjr	/* Store metadata with fresh key. */
413131377Stjr	eli_metadata_encode(&md, sector);
414131377Stjr	bzero(&md, sizeof(md));
415131377Stjr	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
416131377Stjr	    pp->sectorsize);
417131377Stjr	bzero(sector, sizeof(sector));
418131377Stjr	free(sector, M_ELI);
419131377Stjr	if (error != 0) {
420131377Stjr		gctl_error(req, "Cannot store metadata on %s (error=%d).",
421131377Stjr		    pp->name, error);
422131377Stjr		return;
423131377Stjr	}
424131377Stjr	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
425131377Stjr}
426131377Stjr
427131377Stjrstatic void
428131377Stjrg_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
429131377Stjr{
430131377Stjr	struct g_eli_softc *sc;
431131377Stjr	struct g_eli_metadata md;
432131377Stjr	struct g_provider *pp;
433131377Stjr	struct g_consumer *cp;
434131377Stjr	const char *name;
435131377Stjr	u_char *mkeydst, *sector;
436131377Stjr	intmax_t *valp;
437131377Stjr	size_t keysize;
438131377Stjr	int error, nkey, *all, *force;
439131377Stjr	u_int i;
440131377Stjr
441131377Stjr	g_topology_assert();
442
443	nkey = 0;	/* fixes causeless gcc warning */
444
445	name = gctl_get_asciiparam(req, "arg0");
446	if (name == NULL) {
447		gctl_error(req, "No 'arg%u' argument.", 0);
448		return;
449	}
450	sc = g_eli_find_device(mp, name);
451	if (sc == NULL) {
452		gctl_error(req, "Provider %s is invalid.", name);
453		return;
454	}
455	cp = LIST_FIRST(&sc->sc_geom->consumer);
456	pp = cp->provider;
457
458	error = g_eli_read_metadata(mp, pp, &md);
459	if (error != 0) {
460		gctl_error(req, "Cannot read metadata from %s (error=%d).",
461		    name, error);
462		return;
463	}
464
465	all = gctl_get_paraml(req, "all", sizeof(*all));
466	if (all == NULL) {
467		gctl_error(req, "No '%s' argument.", "all");
468		return;
469	}
470
471	if (*all) {
472		mkeydst = md.md_mkeys;
473		keysize = sizeof(md.md_mkeys);
474	} else {
475		force = gctl_get_paraml(req, "force", sizeof(*force));
476		if (force == NULL) {
477			gctl_error(req, "No '%s' argument.", "force");
478			return;
479		}
480
481		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
482		if (valp == NULL) {
483			gctl_error(req, "No '%s' argument.", "keyno");
484			return;
485		}
486		if (*valp != -1)
487			nkey = *valp;
488		else
489			nkey = sc->sc_nkey;
490		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
491			gctl_error(req, "Invalid '%s' argument.", "keyno");
492			return;
493		}
494		if (!(md.md_keys & (1 << nkey)) && !*force) {
495			gctl_error(req, "Master Key %u is not set.", nkey);
496			return;
497		}
498		md.md_keys &= ~(1 << nkey);
499		if (md.md_keys == 0 && !*force) {
500			gctl_error(req, "This is the last Master Key. Use '-f' "
501			    "flag if you really want to remove it.");
502			return;
503		}
504		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
505		keysize = G_ELI_MKEYLEN;
506	}
507
508	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
509	for (i = 0; i <= g_eli_overwrites; i++) {
510		if (i == g_eli_overwrites)
511			bzero(mkeydst, keysize);
512		else
513			arc4rand(mkeydst, keysize, 0);
514		/* Store metadata with destroyed key. */
515		eli_metadata_encode(&md, sector);
516		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
517		    pp->sectorsize);
518		if (error != 0) {
519			G_ELI_DEBUG(0, "Cannot store metadata on %s "
520			    "(error=%d).", pp->name, error);
521		}
522	}
523	bzero(&md, sizeof(md));
524	bzero(sector, sizeof(sector));
525	free(sector, M_ELI);
526	if (*all)
527		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
528	else
529		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
530}
531
532static int
533g_eli_kill_one(struct g_eli_softc *sc)
534{
535	struct g_provider *pp;
536	struct g_consumer *cp;
537	u_char *sector;
538	int err, error = 0;
539	u_int i;
540
541	g_topology_assert();
542
543	if (sc == NULL)
544		return (ENOENT);
545
546	pp = LIST_FIRST(&sc->sc_geom->provider);
547	g_error_provider(pp, ENXIO);
548
549	cp = LIST_FIRST(&sc->sc_geom->consumer);
550	pp = cp->provider;
551
552	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
553	for (i = 0; i <= g_eli_overwrites; i++) {
554		if (i == g_eli_overwrites)
555			bzero(sector, pp->sectorsize);
556		else
557			arc4rand(sector, pp->sectorsize, 0);
558		err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
559		    pp->sectorsize);
560		if (err != 0) {
561			G_ELI_DEBUG(0, "Cannot erase metadata on %s "
562			    "(error=%d).", pp->name, err);
563			if (error == 0)
564				error = err;
565		}
566	}
567	free(sector, M_ELI);
568	if (error == 0)
569		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
570	g_eli_destroy(sc, 1);
571	return (error);
572}
573
574static void
575g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
576{
577	int *all, *nargs;
578	int error;
579
580	g_topology_assert();
581
582	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
583	if (nargs == NULL) {
584		gctl_error(req, "No '%s' argument.", "nargs");
585		return;
586	}
587	all = gctl_get_paraml(req, "all", sizeof(*all));
588	if (all == NULL) {
589		gctl_error(req, "No '%s' argument.", "all");
590		return;
591	}
592	if (!*all && *nargs == 0) {
593		gctl_error(req, "Too few arguments.");
594		return;
595	}
596
597	if (*all) {
598		struct g_geom *gp, *gp2;
599
600		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
601			error = g_eli_kill_one(gp->softc);
602			if (error != 0)
603				gctl_error(req, "Not fully done.");
604		}
605	} else {
606		struct g_eli_softc *sc;
607		const char *prov;
608		char param[16];
609		int i;
610
611		for (i = 0; i < *nargs; i++) {
612			snprintf(param, sizeof(param), "arg%u", i);
613			prov = gctl_get_asciiparam(req, param);
614			if (prov == NULL) {
615				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
616				continue;
617			}
618
619			sc = g_eli_find_device(mp, prov);
620			if (sc == NULL) {
621				G_ELI_DEBUG(1, "No such provider: %s.", prov);
622				continue;
623			}
624			error = g_eli_kill_one(sc);
625			if (error != 0)
626				gctl_error(req, "Not fully done.");
627		}
628	}
629}
630
631void
632g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
633{
634	uint32_t *version;
635
636	g_topology_assert();
637
638	version = gctl_get_paraml(req, "version", sizeof(*version));
639	if (version == NULL) {
640		gctl_error(req, "No '%s' argument.", "version");
641		return;
642	}
643	if (*version != G_ELI_VERSION) {
644		gctl_error(req, "Userland and kernel parts are out of sync.");
645		return;
646	}
647
648	if (strcmp(verb, "attach") == 0)
649		g_eli_ctl_attach(req, mp);
650	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
651		g_eli_ctl_detach(req, mp);
652	else if (strcmp(verb, "onetime") == 0)
653		g_eli_ctl_onetime(req, mp);
654	else if (strcmp(verb, "setkey") == 0)
655		g_eli_ctl_setkey(req, mp);
656	else if (strcmp(verb, "delkey") == 0)
657		g_eli_ctl_delkey(req, mp);
658	else if (strcmp(verb, "kill") == 0)
659		g_eli_ctl_kill(req, mp);
660	else
661		gctl_error(req, "Unknown verb.");
662}
663