g_eli_ctl.c revision 159307
1139825Simp/*-
290643Sbenno * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
390643Sbenno * All rights reserved.
490643Sbenno *
590643Sbenno * Redistribution and use in source and binary forms, with or without
690643Sbenno * modification, are permitted provided that the following conditions
790643Sbenno * are met:
890643Sbenno * 1. Redistributions of source code must retain the above copyright
990643Sbenno *    notice, this list of conditions and the following disclaimer.
1090643Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1190643Sbenno *    notice, this list of conditions and the following disclaimer in the
1290643Sbenno *    documentation and/or other materials provided with the distribution.
1390643Sbenno *
1490643Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1590643Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1690643Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1790643Sbenno * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1890643Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1990643Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2090643Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2190643Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2290643Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2390643Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2490643Sbenno * SUCH DAMAGE.
2590643Sbenno */
2690643Sbenno
2790643Sbenno#include <sys/cdefs.h>
2890643Sbenno__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 159307 2006-06-05 21:38:54Z pjd $");
29139825Simp
3077957Sbenno#include <sys/param.h>
3177957Sbenno#include <sys/systm.h>
3277957Sbenno#include <sys/kernel.h>
3377957Sbenno#include <sys/module.h>
3477957Sbenno#include <sys/lock.h>
3577957Sbenno#include <sys/mutex.h>
3677957Sbenno#include <sys/bio.h>
3777957Sbenno#include <sys/sysctl.h>
3877957Sbenno#include <sys/malloc.h>
3977957Sbenno#include <sys/kthread.h>
4077957Sbenno#include <sys/proc.h>
4177957Sbenno#include <sys/sched.h>
4277957Sbenno#include <sys/uio.h>
4377957Sbenno
4477957Sbenno#include <vm/uma.h>
4577957Sbenno
4677957Sbenno#include <geom/geom.h>
4777957Sbenno#include <geom/eli/g_eli.h>
4877957Sbenno
4977957Sbenno
5077957SbennoMALLOC_DECLARE(M_ELI);
5177957Sbenno
5277957Sbenno
5377957Sbennostatic void
5477957Sbennog_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
5577957Sbenno{
5677957Sbenno	struct g_eli_metadata md;
5777957Sbenno	struct g_provider *pp;
5877957Sbenno	const char *name;
5978880Sbenno	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
6077957Sbenno	int *nargs, *detach;
61139825Simp	int keysize, error;
6277957Sbenno	u_int nkey;
6377957Sbenno
6477957Sbenno	g_topology_assert();
6577957Sbenno
6677957Sbenno	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
6777957Sbenno	if (nargs == NULL) {
6877957Sbenno		gctl_error(req, "No '%s' argument.", "nargs");
6977957Sbenno		return;
7077957Sbenno	}
7177957Sbenno	if (*nargs != 1) {
7277957Sbenno		gctl_error(req, "Invalid number of arguments.");
7377957Sbenno		return;
7477957Sbenno	}
7577957Sbenno
7677957Sbenno	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
7777957Sbenno	if (detach == NULL) {
7877957Sbenno		gctl_error(req, "No '%s' argument.", "detach");
7977957Sbenno		return;
8077957Sbenno	}
8177957Sbenno
8277957Sbenno	name = gctl_get_asciiparam(req, "arg0");
8377957Sbenno	if (name == NULL) {
8477957Sbenno		gctl_error(req, "No 'arg%u' argument.", 0);
8577957Sbenno		return;
86113038Sobrien	}
87113038Sobrien	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
8877957Sbenno		name += strlen("/dev/");
8990643Sbenno	pp = g_provider_by_name(name);
9090643Sbenno	if (pp == NULL) {
9190643Sbenno		gctl_error(req, "Provider %s is invalid.", name);
9290643Sbenno		return;
9390643Sbenno	}
9490643Sbenno	error = g_eli_read_metadata(mp, pp, &md);
9590643Sbenno	if (error != 0) {
9690643Sbenno		gctl_error(req, "Cannot read metadata from %s (error=%d).",
9790643Sbenno		    name, error);
9890643Sbenno		return;
9990643Sbenno	}
10090643Sbenno	if (md.md_keys == 0x00) {
10190643Sbenno		bzero(&md, sizeof(md));
10290643Sbenno		gctl_error(req, "No valid keys on %s.", pp->name);
10390643Sbenno		return;
10490643Sbenno	}
105118239Speter
106118239Speter	key = gctl_get_param(req, "key", &keysize);
10777957Sbenno	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
10880431Speter		bzero(&md, sizeof(md));
109222813Sattilio		gctl_error(req, "No '%s' argument.", "key");
110222813Sattilio		return;
11190643Sbenno	}
11290643Sbenno
11390643Sbenno	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
11490643Sbenno	bzero(key, keysize);
11577957Sbenno	if (error == -1) {
116238159Salc		bzero(&md, sizeof(md));
117222813Sattilio		gctl_error(req, "Wrong key for %s.", pp->name);
11890643Sbenno		return;
11990643Sbenno	} else if (error > 0) {
12077957Sbenno		bzero(&md, sizeof(md));
12177957Sbenno		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
12290643Sbenno		    pp->name, error);
12390643Sbenno		return;
124152180Sgrehan	}
12577957Sbenno	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
12677957Sbenno
12777957Sbenno	if (*detach)
12877957Sbenno		md.md_flags |= G_ELI_FLAG_WO_DETACH;
12977957Sbenno	g_eli_create(req, mp, pp, &md, mkey, nkey);
13077957Sbenno	bzero(mkey, sizeof(mkey));
13177957Sbenno	bzero(&md, sizeof(md));
13292847Sjeff}
13377957Sbenno
134125687Sgrehanstatic struct g_eli_softc *
135192067Snwhitehorng_eli_find_device(struct g_class *mp, const char *prov)
13683730Smp{
13790643Sbenno	struct g_eli_softc *sc;
13890643Sbenno	struct g_geom *gp;
13990643Sbenno	struct g_provider *pp;
14077957Sbenno	struct g_consumer *cp;
141178628Smarcel
14290643Sbenno	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
143152180Sgrehan		prov += strlen("/dev/");
144265974Sian	LIST_FOREACH(gp, &mp->geom, geom) {
14577957Sbenno		sc = gp->softc;
146152180Sgrehan		if (sc == NULL)
14777957Sbenno			continue;
148152180Sgrehan		pp = LIST_FIRST(&gp->provider);
149152180Sgrehan		if (pp != NULL && strcmp(pp->name, prov) == 0)
15090643Sbenno			return (sc);
15177957Sbenno		cp = LIST_FIRST(&gp->consumer);
15290643Sbenno		if (cp != NULL && cp->provider != NULL &&
15390643Sbenno		    strcmp(cp->provider->name, prov) == 0) {
15490643Sbenno			return (sc);
15590643Sbenno		}
15690643Sbenno	}
15790643Sbenno	return (NULL);
15890643Sbenno}
15990643Sbenno
16090643Sbennostatic void
16190643Sbennog_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
16277957Sbenno{
163249864Sjhibbits	struct g_eli_softc *sc;
164249864Sjhibbits	int *force, *last, *nargs, error;
165249864Sjhibbits	const char *prov;
166249864Sjhibbits	char param[16];
167249864Sjhibbits	int i;
16890643Sbenno
16990643Sbenno	g_topology_assert();
17090643Sbenno
17197346Sbenno	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
17297346Sbenno	if (nargs == NULL) {
173209975Snwhitehorn		gctl_error(req, "No '%s' argument.", "nargs");
174209975Snwhitehorn		return;
175100319Sbenno	}
17677957Sbenno	if (*nargs <= 0) {
17790643Sbenno		gctl_error(req, "Missing device(s).");
178134535Salc		return;
179134535Salc	}
180152180Sgrehan	force = gctl_get_paraml(req, "force", sizeof(*force));
181212278Snwhitehorn	if (force == NULL) {
182134535Salc		gctl_error(req, "No '%s' argument.", "force");
183183094Smarcel		return;
184183094Smarcel	}
185183094Smarcel	last = gctl_get_paraml(req, "last", sizeof(*last));
186134535Salc	if (last == NULL) {
18790643Sbenno		gctl_error(req, "No '%s' argument.", "last");
18890643Sbenno		return;
189152180Sgrehan	}
190152180Sgrehan
191152180Sgrehan	for (i = 0; i < *nargs; i++) {
19277957Sbenno		snprintf(param, sizeof(param), "arg%d", i);
19390643Sbenno		prov = gctl_get_asciiparam(req, param);
19490643Sbenno		if (prov == NULL) {
19590643Sbenno			gctl_error(req, "No 'arg%d' argument.", i);
196152180Sgrehan			return;
197152180Sgrehan		}
198152180Sgrehan		sc = g_eli_find_device(mp, prov);
19977957Sbenno		if (sc == NULL) {
200242534Sattilio			gctl_error(req, "No such device: %s.", prov);
201238159Salc			return;
202152180Sgrehan		}
203152180Sgrehan		if (*last) {
20477957Sbenno			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
20599037Sbenno			sc->sc_geom->access = g_eli_access;
206152180Sgrehan		} else {
207152180Sgrehan			error = g_eli_destroy(sc, *force);
20877957Sbenno			if (error != 0) {
20990643Sbenno				gctl_error(req,
210152180Sgrehan				    "Cannot destroy device %s (error=%d).",
21177957Sbenno				    sc->sc_name, error);
212152180Sgrehan				return;
21377957Sbenno			}
21490643Sbenno		}
21590643Sbenno	}
21690643Sbenno}
217152180Sgrehan
218152180Sgrehanstatic void
219152180Sgrehang_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
220152180Sgrehan{
221152180Sgrehan	struct g_eli_metadata md;
222152180Sgrehan	struct g_provider *pp;
223152180Sgrehan	const char *name;
224152180Sgrehan	intmax_t *keylen, *sectorsize;
22590643Sbenno	u_char mkey[G_ELI_DATAIVKEYLEN];
226152180Sgrehan	int *nargs, *detach;
227152180Sgrehan
228152180Sgrehan	g_topology_assert();
229152180Sgrehan	bzero(&md, sizeof(md));
230152180Sgrehan
23190643Sbenno	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
232152180Sgrehan	if (nargs == NULL) {
233152180Sgrehan		gctl_error(req, "No '%s' argument.", "nargs");
234152180Sgrehan		return;
235152180Sgrehan	}
236152180Sgrehan	if (*nargs != 1) {
237152180Sgrehan		gctl_error(req, "Invalid number of arguments.");
23877957Sbenno		return;
23990643Sbenno	}
240152180Sgrehan
24190643Sbenno	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
242152180Sgrehan	if (detach == NULL) {
24377957Sbenno		gctl_error(req, "No '%s' argument.", "detach");
24490643Sbenno		return;
24590643Sbenno	}
24690643Sbenno
247152180Sgrehan	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
24877957Sbenno	md.md_version = G_ELI_VERSION;
24977957Sbenno	md.md_flags |= G_ELI_FLAG_ONETIME;
25090643Sbenno	if (*detach)
25177957Sbenno		md.md_flags |= G_ELI_FLAG_WO_DETACH;
252152180Sgrehan
25390643Sbenno	name = gctl_get_asciiparam(req, "aalgo");
254152180Sgrehan	if (name == NULL) {
255152180Sgrehan		gctl_error(req, "No '%s' argument.", "aalgo");
256152180Sgrehan		return;
25790643Sbenno	}
25890643Sbenno	if (strcmp(name, "none") != 0) {
25990643Sbenno		md.md_aalgo = g_eli_str2aalgo(name);
26090643Sbenno		if (md.md_aalgo < CRYPTO_ALGORITHM_MIN ||
261270439Skib		    md.md_aalgo > CRYPTO_ALGORITHM_MAX) {
262270439Skib			gctl_error(req, "Invalid authentication algorithm.");
263152180Sgrehan			return;
264152180Sgrehan		}
265208990Salc		md.md_flags |= G_ELI_FLAG_AUTH;
266152180Sgrehan	}
267152180Sgrehan
26890643Sbenno	name = gctl_get_asciiparam(req, "ealgo");
269152180Sgrehan	if (name == NULL) {
270152180Sgrehan		gctl_error(req, "No '%s' argument.", "ealgo");
271152180Sgrehan		return;
272152180Sgrehan	}
273152180Sgrehan	md.md_ealgo = g_eli_str2ealgo(name);
274248280Skib	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
275248280Skib	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
276270439Skib		gctl_error(req, "Invalid encryption algorithm.");
277270439Skib		return;
278159303Salc	}
279159303Salc
280159627Sups	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
281152180Sgrehan	if (keylen == NULL) {
282152180Sgrehan		gctl_error(req, "No '%s' argument.", "keylen");
283152180Sgrehan		return;
284152180Sgrehan	}
285214617Salc	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
286207155Salc	if (md.md_keylen == 0) {
287238357Salc		gctl_error(req, "Invalid '%s' argument.", "keylen");
288235936Sraj		return;
289152180Sgrehan	}
290173708Salc
291152180Sgrehan	/* Not important here. */
292152180Sgrehan	md.md_provsize = 0;
293152180Sgrehan	/* Not important here. */
294152180Sgrehan	bzero(md.md_salt, sizeof(md.md_salt));
295152180Sgrehan
296152180Sgrehan	md.md_keys = 0x01;
297152180Sgrehan	arc4rand(mkey, sizeof(mkey), 0);
298152180Sgrehan
299160889Salc	/* Not important here. */
300270920Skib	bzero(md.md_hash, sizeof(md.md_hash));
301152180Sgrehan
302152180Sgrehan	name = gctl_get_asciiparam(req, "arg0");
303152180Sgrehan	if (name == NULL) {
304152180Sgrehan		gctl_error(req, "No 'arg%u' argument.", 0);
305152180Sgrehan		return;
306190681Snwhitehorn	}
307152180Sgrehan	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
308235936Sraj		name += strlen("/dev/");
309213307Snwhitehorn	pp = g_provider_by_name(name);
310152180Sgrehan	if (pp == NULL) {
311235936Sraj		gctl_error(req, "Provider %s is invalid.", name);
312213307Snwhitehorn		return;
313235936Sraj	}
314213307Snwhitehorn
315235936Sraj	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
316198341Smarcel	if (sectorsize == NULL) {
317249864Sjhibbits		gctl_error(req, "No '%s' argument.", "sectorsize");
318249864Sjhibbits		return;
319249864Sjhibbits	}
320152180Sgrehan	if (*sectorsize == 0)
321152180Sgrehan		md.md_sectorsize = pp->sectorsize;
322152180Sgrehan	else {
323152180Sgrehan		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
324248280Skib			gctl_error(req, "Invalid sector size.");
325152180Sgrehan			return;
326159303Salc		}
327152180Sgrehan		md.md_sectorsize = *sectorsize;
328152180Sgrehan	}
329152180Sgrehan
330152180Sgrehan	g_eli_create(req, mp, pp, &md, mkey, -1);
331152180Sgrehan	bzero(mkey, sizeof(mkey));
332214617Salc	bzero(&md, sizeof(md));
333207155Salc}
334152180Sgrehan
335152180Sgrehanstatic void
336152180Sgrehang_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
337173708Salc{
338152180Sgrehan	struct g_eli_softc *sc;
339152180Sgrehan	struct g_eli_metadata md;
340152180Sgrehan	struct g_provider *pp;
341152180Sgrehan	struct g_consumer *cp;
342152180Sgrehan	const char *name;
343152180Sgrehan	u_char *key, *mkeydst, *sector;
344152180Sgrehan	intmax_t *valp;
345152180Sgrehan	int keysize, nkey, error;
346160889Salc
347198341Smarcel	g_topology_assert();
348270920Skib
349152180Sgrehan	name = gctl_get_asciiparam(req, "arg0");
350152180Sgrehan	if (name == NULL) {
351152180Sgrehan		gctl_error(req, "No 'arg%u' argument.", 0);
352152180Sgrehan		return;
353152180Sgrehan	}
354213307Snwhitehorn	sc = g_eli_find_device(mp, name);
355152180Sgrehan	if (sc == NULL) {
356152180Sgrehan		gctl_error(req, "Provider %s is invalid.", name);
357152180Sgrehan		return;
358190681Snwhitehorn	}
359213307Snwhitehorn	cp = LIST_FIRST(&sc->sc_geom->consumer);
360152180Sgrehan	pp = cp->provider;
361152180Sgrehan
362152180Sgrehan	error = g_eli_read_metadata(mp, pp, &md);
363152180Sgrehan	if (error != 0) {
364213307Snwhitehorn		gctl_error(req, "Cannot read metadata from %s (error=%d).",
365152180Sgrehan		    name, error);
366249864Sjhibbits		return;
367249864Sjhibbits	}
368152180Sgrehan
369152180Sgrehan	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
370152180Sgrehan	if (valp == NULL) {
371152180Sgrehan		gctl_error(req, "No '%s' argument.", "keyno");
372212627Sgrehan		return;
373152180Sgrehan	}
374213307Snwhitehorn	if (*valp != -1)
375213307Snwhitehorn		nkey = *valp;
376213307Snwhitehorn	else
377213307Snwhitehorn		nkey = sc->sc_nkey;
378213307Snwhitehorn	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
379212627Sgrehan		gctl_error(req, "Invalid '%s' argument.", "keyno");
380213307Snwhitehorn		return;
381213307Snwhitehorn	}
382213307Snwhitehorn
383213307Snwhitehorn	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
384213307Snwhitehorn	if (valp == NULL) {
385213307Snwhitehorn		gctl_error(req, "No '%s' argument.", "iterations");
386213307Snwhitehorn		return;
387213307Snwhitehorn	}
388213307Snwhitehorn	/* Check if iterations number should and can be changed. */
389213307Snwhitehorn	if (*valp != -1) {
390213307Snwhitehorn		if (bitcount32(md.md_keys) != 1) {
391213307Snwhitehorn			gctl_error(req, "To be able to use '-i' option, only "
392213307Snwhitehorn			    "one key can be defined.");
393213307Snwhitehorn			return;
394213307Snwhitehorn		}
395213307Snwhitehorn		if (md.md_keys != (1 << nkey)) {
396213307Snwhitehorn			gctl_error(req, "Only already defined key can be "
397213307Snwhitehorn			    "changed when '-i' option is used.");
398213307Snwhitehorn			return;
399213307Snwhitehorn		}
400213307Snwhitehorn		md.md_iterations = *valp;
401213307Snwhitehorn	}
402213307Snwhitehorn
403213307Snwhitehorn	key = gctl_get_param(req, "key", &keysize);
404213307Snwhitehorn	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
405213307Snwhitehorn		bzero(&md, sizeof(md));
406213307Snwhitehorn		gctl_error(req, "No '%s' argument.", "key");
407213307Snwhitehorn		return;
408213307Snwhitehorn	}
409183094Smarcel
410183094Smarcel	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
411183094Smarcel	md.md_keys |= (1 << nkey);
412152180Sgrehan
413183094Smarcel	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
414213407Snwhitehorn
415183094Smarcel	/* Encrypt Master Key with the new key. */
416213407Snwhitehorn	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
417183094Smarcel	bzero(key, sizeof(key));
418183094Smarcel	if (error != 0) {
419183094Smarcel		bzero(&md, sizeof(md));
420183094Smarcel		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
421183094Smarcel		return;
422183094Smarcel	}
423183094Smarcel
424183094Smarcel	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
425183094Smarcel	/* Store metadata with fresh key. */
426183094Smarcel	eli_metadata_encode(&md, sector);
427183094Smarcel	bzero(&md, sizeof(md));
428183094Smarcel	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
429183094Smarcel	    pp->sectorsize);
430183094Smarcel	bzero(sector, sizeof(sector));
431183094Smarcel	free(sector, M_ELI);
432183094Smarcel	if (error != 0) {
43390643Sbenno		gctl_error(req, "Cannot store metadata on %s (error=%d).",
43490643Sbenno		    pp->name, error);
43577957Sbenno		return;
43690643Sbenno	}
43790643Sbenno	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
43877957Sbenno}
43990643Sbenno
44090643Sbennostatic void
44190643Sbennog_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
44290643Sbenno{
44390643Sbenno	struct g_eli_softc *sc;
44490643Sbenno	struct g_eli_metadata md;
44590643Sbenno	struct g_provider *pp;
446152180Sgrehan	struct g_consumer *cp;
44777957Sbenno	const char *name;
44877957Sbenno	u_char *mkeydst, *sector;
44990643Sbenno	intmax_t *valp;
45090643Sbenno	size_t keysize;
45190643Sbenno	int error, nkey, *all, *force;
45290643Sbenno	u_int i;
45390643Sbenno
45490643Sbenno	g_topology_assert();
45590643Sbenno
45677957Sbenno	nkey = 0;	/* fixes causeless gcc warning */
457152180Sgrehan
45877957Sbenno	name = gctl_get_asciiparam(req, "arg0");
45990643Sbenno	if (name == NULL) {
460238159Salc		gctl_error(req, "No 'arg%u' argument.", 0);
46190643Sbenno		return;
46277957Sbenno	}
46377957Sbenno	sc = g_eli_find_device(mp, name);
46477957Sbenno	if (sc == NULL) {
465152180Sgrehan		gctl_error(req, "Provider %s is invalid.", name);
46677957Sbenno		return;
46777957Sbenno	}
46890643Sbenno	cp = LIST_FIRST(&sc->sc_geom->consumer);
46977957Sbenno	pp = cp->provider;
47077957Sbenno
47190643Sbenno	error = g_eli_read_metadata(mp, pp, &md);
472152180Sgrehan	if (error != 0) {
47390643Sbenno		gctl_error(req, "Cannot read metadata from %s (error=%d).",
47490643Sbenno		    name, error);
475238159Salc		return;
47690643Sbenno	}
47790643Sbenno
47890643Sbenno	all = gctl_get_paraml(req, "all", sizeof(*all));
47977957Sbenno	if (all == NULL) {
480152180Sgrehan		gctl_error(req, "No '%s' argument.", "all");
48177957Sbenno		return;
48290643Sbenno	}
48390643Sbenno
48490643Sbenno	if (*all) {
48590643Sbenno		mkeydst = md.md_mkeys;
48677957Sbenno		keysize = sizeof(md.md_mkeys);
48777957Sbenno	} else {
48877957Sbenno		force = gctl_get_paraml(req, "force", sizeof(*force));
489152180Sgrehan		if (force == NULL) {
49077957Sbenno			gctl_error(req, "No '%s' argument.", "force");
49190643Sbenno			return;
49290643Sbenno		}
49390643Sbenno
49490643Sbenno		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
49577957Sbenno		if (valp == NULL) {
49690643Sbenno			gctl_error(req, "No '%s' argument.", "keyno");
497152180Sgrehan			return;
49890643Sbenno		}
499159928Salc		if (*valp != -1)
500159928Salc			nkey = *valp;
501159928Salc		else
50290643Sbenno			nkey = sc->sc_nkey;
50390643Sbenno		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
50490643Sbenno			gctl_error(req, "Invalid '%s' argument.", "keyno");
50590643Sbenno			return;
50690643Sbenno		}
50790643Sbenno		if (!(md.md_keys & (1 << nkey)) && !*force) {
50890643Sbenno			gctl_error(req, "Master Key %u is not set.", nkey);
50990643Sbenno			return;
51090643Sbenno		}
51177957Sbenno		md.md_keys &= ~(1 << nkey);
51277957Sbenno		if (md.md_keys == 0 && !*force) {
51390643Sbenno			gctl_error(req, "This is the last Master Key. Use '-f' "
514152180Sgrehan			    "flag if you really want to remove it.");
51577957Sbenno			return;
51677957Sbenno		}
517159928Salc		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
51890643Sbenno		keysize = G_ELI_MKEYLEN;
51977957Sbenno	}
52077957Sbenno
52190643Sbenno	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
522152180Sgrehan	for (i = 0; i <= g_eli_overwrites; i++) {
52377957Sbenno		if (i == g_eli_overwrites)
52477957Sbenno			bzero(mkeydst, keysize);
525159928Salc		else
526159928Salc			arc4rand(mkeydst, keysize, 0);
52790643Sbenno		/* Store metadata with destroyed key. */
52890643Sbenno		eli_metadata_encode(&md, sector);
52990643Sbenno		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
53090643Sbenno		    pp->sectorsize);
531183094Smarcel		if (error != 0) {
53277957Sbenno			G_ELI_DEBUG(0, "Cannot store metadata on %s "
53377957Sbenno			    "(error=%d).", pp->name, error);
53490643Sbenno		}
535152180Sgrehan	}
53677957Sbenno	bzero(&md, sizeof(md));
53777957Sbenno	bzero(sector, sizeof(sector));
538159928Salc	free(sector, M_ELI);
53990643Sbenno	if (*all)
54090643Sbenno		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
54177957Sbenno	else
54290643Sbenno		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
543253976Sjhibbits}
54490643Sbenno
54577957Sbennostatic int
54690643Sbennog_eli_kill_one(struct g_eli_softc *sc)
547183094Smarcel{
54890643Sbenno	struct g_provider *pp;
549183094Smarcel	struct g_consumer *cp;
550152180Sgrehan	u_char *sector;
55190643Sbenno	int err, error = 0;
55277957Sbenno	u_int i;
55390643Sbenno
554152180Sgrehan	g_topology_assert();
55590643Sbenno
55690643Sbenno	if (sc == NULL)
557159928Salc		return (ENOENT);
55890643Sbenno
55990643Sbenno	pp = LIST_FIRST(&sc->sc_geom->provider);
56077957Sbenno	g_error_provider(pp, ENXIO);
56190643Sbenno
56277957Sbenno	cp = LIST_FIRST(&sc->sc_geom->consumer);
563183094Smarcel	pp = cp->provider;
56477957Sbenno
56590643Sbenno	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
56690643Sbenno	for (i = 0; i <= g_eli_overwrites; i++) {
56790643Sbenno		if (i == g_eli_overwrites)
56890643Sbenno			bzero(sector, pp->sectorsize);
56977957Sbenno		else
570183094Smarcel			arc4rand(sector, pp->sectorsize, 0);
57177957Sbenno		err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
57290643Sbenno		    pp->sectorsize);
57390643Sbenno		if (err != 0) {
57490643Sbenno			G_ELI_DEBUG(0, "Cannot erase metadata on %s "
575152180Sgrehan			    "(error=%d).", pp->name, err);
576152180Sgrehan			if (error == 0)
57777957Sbenno				error = err;
57877957Sbenno		}
57990643Sbenno	}
580152180Sgrehan	free(sector, M_ELI);
58190643Sbenno	if (error == 0)
58290643Sbenno		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
58390643Sbenno	g_eli_destroy(sc, 1);
58490643Sbenno	return (error);
58590643Sbenno}
586152180Sgrehan
587152180Sgrehanstatic void
58890643Sbennog_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
58990643Sbenno{
59077957Sbenno	int *all, *nargs;
59190643Sbenno	int error;
59277957Sbenno
59390643Sbenno	g_topology_assert();
59490643Sbenno
59590643Sbenno	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
59690643Sbenno	if (nargs == NULL) {
59790643Sbenno		gctl_error(req, "No '%s' argument.", "nargs");
59890643Sbenno		return;
59990643Sbenno	}
60090643Sbenno	all = gctl_get_paraml(req, "all", sizeof(*all));
60190643Sbenno	if (all == NULL) {
60290643Sbenno		gctl_error(req, "No '%s' argument.", "all");
60390643Sbenno		return;
60490643Sbenno	}
60590643Sbenno	if (!*all && *nargs == 0) {
60690643Sbenno		gctl_error(req, "Too few arguments.");
60790643Sbenno		return;
60890643Sbenno	}
60977957Sbenno
61077957Sbenno	if (*all) {
61177957Sbenno		struct g_geom *gp, *gp2;
612190681Snwhitehorn
613178628Smarcel		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
614178628Smarcel			error = g_eli_kill_one(gp->softc);
615178628Smarcel			if (error != 0)
616178628Smarcel				gctl_error(req, "Not fully done.");
617178628Smarcel		}
618183094Smarcel	} else {
619178628Smarcel		struct g_eli_softc *sc;
620178628Smarcel		const char *prov;
621178628Smarcel		char param[16];
622178628Smarcel		int i;
623178628Smarcel
624178628Smarcel		for (i = 0; i < *nargs; i++) {
625178628Smarcel			snprintf(param, sizeof(param), "arg%d", i);
626178628Smarcel			prov = gctl_get_asciiparam(req, param);
627243370Sadrian			if (prov == NULL) {
628243370Sadrian				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
629243370Sadrian				continue;
630243370Sadrian			}
631243370Sadrian
632243370Sadrian			sc = g_eli_find_device(mp, prov);
633243370Sadrian			if (sc == NULL) {
634243370Sadrian				G_ELI_DEBUG(0, "No such provider: %s.", prov);
635243370Sadrian				continue;
636243370Sadrian			}
637243370Sadrian			error = g_eli_kill_one(sc);
638178629Smarcel			if (error != 0)
639178628Smarcel				gctl_error(req, "Not fully done.");
640178629Smarcel		}
641178629Smarcel	}
642178629Smarcel}
643178629Smarcel
644178629Smarcelvoid
645178628Smarcelg_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
646178628Smarcel{
647178628Smarcel	uint32_t *version;
648215163Snwhitehorn
649183094Smarcel	g_topology_assert();
650178628Smarcel
651178628Smarcel	version = gctl_get_paraml(req, "version", sizeof(*version));
652178628Smarcel	if (version == NULL) {
653178628Smarcel		gctl_error(req, "No '%s' argument.", "version");
654178628Smarcel		return;
655179254Smarcel	}
656178628Smarcel	if (*version != G_ELI_VERSION) {
657178628Smarcel		gctl_error(req, "Userland and kernel parts are out of sync.");
658178628Smarcel		return;
659152180Sgrehan	}
66077957Sbenno
66197346Sbenno	if (strcmp(verb, "attach") == 0)
66290643Sbenno		g_eli_ctl_attach(req, mp);
66390643Sbenno	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
66490643Sbenno		g_eli_ctl_detach(req, mp);
665143200Sgrehan	else if (strcmp(verb, "onetime") == 0)
66690643Sbenno		g_eli_ctl_onetime(req, mp);
667194784Sjeff	else if (strcmp(verb, "setkey") == 0)
668209369Snwhitehorn		g_eli_ctl_setkey(req, mp);
66977957Sbenno	else if (strcmp(verb, "delkey") == 0)
67099037Sbenno		g_eli_ctl_delkey(req, mp);
671103604Sgrehan	else if (strcmp(verb, "kill") == 0)
67299037Sbenno		g_eli_ctl_kill(req, mp);
67399037Sbenno	else
67499037Sbenno		gctl_error(req, "Unknown verb.");
67599037Sbenno}
676243370Sadrian