g_eli_ctl.c revision 162834
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
31573Srgrimes * All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes *
141573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
151573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
181573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241573Srgrimes * SUCH DAMAGE.
251573Srgrimes */
261573Srgrimes
271573Srgrimes#include <sys/cdefs.h>
281573Srgrimes__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 162834 2006-09-30 08:16:49Z pjd $");
291573Srgrimes
301573Srgrimes#include <sys/param.h>
311573Srgrimes#include <sys/systm.h>
321573Srgrimes#include <sys/kernel.h>
331573Srgrimes#include <sys/module.h>
341573Srgrimes#include <sys/lock.h>
351573Srgrimes#include <sys/mutex.h>
361573Srgrimes#include <sys/bio.h>
3786170Sobrien#include <sys/sysctl.h>
3886170Sobrien#include <sys/malloc.h>
391573Srgrimes#include <sys/kthread.h>
401573Srgrimes#include <sys/proc.h>
411573Srgrimes#include <sys/sched.h>
421573Srgrimes#include <sys/uio.h>
431573Srgrimes
441573Srgrimes#include <vm/uma.h>
451573Srgrimes
461573Srgrimes#include <geom/geom.h>
471573Srgrimes#include <geom/eli/g_eli.h>
481573Srgrimes
491573Srgrimes
501573SrgrimesMALLOC_DECLARE(M_ELI);
511573Srgrimes
521573Srgrimes
531573Srgrimesstatic void
541573Srgrimesg_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
551573Srgrimes{
561573Srgrimes	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
147static struct g_eli_softc *
148g_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
173static void
174g_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
231static void
232g_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		md.md_sectorsize = *sectorsize;
359	}
360
361	g_eli_create(req, mp, pp, &md, mkey, -1);
362	bzero(mkey, sizeof(mkey));
363	bzero(&md, sizeof(md));
364}
365
366static void
367g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
368{
369	struct g_eli_softc *sc;
370	struct g_eli_metadata md;
371	struct g_provider *pp;
372	struct g_consumer *cp;
373	char param[16];
374	const char *prov;
375	u_char *sector;
376	int *nargs, *boot, *noboot;
377	int error;
378	u_int i;
379
380	g_topology_assert();
381
382	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
383	if (nargs == NULL) {
384		gctl_error(req, "No '%s' argument.", "nargs");
385		return;
386	}
387	if (*nargs <= 0) {
388		gctl_error(req, "Missing device(s).");
389		return;
390	}
391
392	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
393	if (boot == NULL) {
394		gctl_error(req, "No '%s' argument.", "boot");
395		return;
396	}
397	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
398	if (noboot == NULL) {
399		gctl_error(req, "No '%s' argument.", "noboot");
400		return;
401	}
402	if (*boot && *noboot) {
403		gctl_error(req, "Options -b and -B are mutually exclusive.");
404		return;
405	}
406	if (!*boot && !*noboot) {
407		gctl_error(req, "No option given.");
408		return;
409	}
410
411	for (i = 0; i < *nargs; i++) {
412		snprintf(param, sizeof(param), "arg%d", i);
413		prov = gctl_get_asciiparam(req, param);
414		if (prov == NULL) {
415			gctl_error(req, "No 'arg%d' argument.", i);
416			return;
417		}
418		sc = g_eli_find_device(mp, prov);
419		if (sc == NULL) {
420			/*
421			 * We ignore not attached providers, userland part will
422			 * take care of them.
423			 */
424			G_ELI_DEBUG(1, "Skipping configuration of not attached "
425			    "provider %s.", prov);
426			continue;
427		}
428		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
429			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
430			    prov);
431			continue;
432		} else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
433			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
434			    prov);
435			continue;
436		}
437		if (sc->sc_flags & G_ELI_FLAG_RO) {
438			gctl_error(req, "Cannot change configuration of "
439			    "read-only provider %s.", prov);
440			continue;
441		}
442		cp = LIST_FIRST(&sc->sc_geom->consumer);
443		pp = cp->provider;
444		error = g_eli_read_metadata(mp, pp, &md);
445		if (error != 0) {
446			gctl_error(req,
447			    "Cannot read metadata from %s (error=%d).",
448			    prov, error);
449			continue;
450		}
451
452		if (*boot) {
453			md.md_flags |= G_ELI_FLAG_BOOT;
454			sc->sc_flags |= G_ELI_FLAG_BOOT;
455		} else {
456			md.md_flags &= ~G_ELI_FLAG_BOOT;
457			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
458		}
459
460		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
461		eli_metadata_encode(&md, sector);
462		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
463		    pp->sectorsize);
464		if (error != 0) {
465			gctl_error(req,
466			    "Cannot store metadata on %s (error=%d).",
467			    prov, error);
468		}
469		bzero(&md, sizeof(md));
470		bzero(sector, sizeof(sector));
471		free(sector, M_ELI);
472	}
473}
474
475static void
476g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
477{
478	struct g_eli_softc *sc;
479	struct g_eli_metadata md;
480	struct g_provider *pp;
481	struct g_consumer *cp;
482	const char *name;
483	u_char *key, *mkeydst, *sector;
484	intmax_t *valp;
485	int keysize, nkey, error;
486
487	g_topology_assert();
488
489	name = gctl_get_asciiparam(req, "arg0");
490	if (name == NULL) {
491		gctl_error(req, "No 'arg%u' argument.", 0);
492		return;
493	}
494	sc = g_eli_find_device(mp, name);
495	if (sc == NULL) {
496		gctl_error(req, "Provider %s is invalid.", name);
497		return;
498	}
499	if (sc->sc_flags & G_ELI_FLAG_RO) {
500		gctl_error(req, "Cannot change keys for read-only provider.");
501		return;
502	}
503	cp = LIST_FIRST(&sc->sc_geom->consumer);
504	pp = cp->provider;
505
506	error = g_eli_read_metadata(mp, pp, &md);
507	if (error != 0) {
508		gctl_error(req, "Cannot read metadata from %s (error=%d).",
509		    name, error);
510		return;
511	}
512
513	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
514	if (valp == NULL) {
515		gctl_error(req, "No '%s' argument.", "keyno");
516		return;
517	}
518	if (*valp != -1)
519		nkey = *valp;
520	else
521		nkey = sc->sc_nkey;
522	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
523		gctl_error(req, "Invalid '%s' argument.", "keyno");
524		return;
525	}
526
527	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
528	if (valp == NULL) {
529		gctl_error(req, "No '%s' argument.", "iterations");
530		return;
531	}
532	/* Check if iterations number should and can be changed. */
533	if (*valp != -1) {
534		if (bitcount32(md.md_keys) != 1) {
535			gctl_error(req, "To be able to use '-i' option, only "
536			    "one key can be defined.");
537			return;
538		}
539		if (md.md_keys != (1 << nkey)) {
540			gctl_error(req, "Only already defined key can be "
541			    "changed when '-i' option is used.");
542			return;
543		}
544		md.md_iterations = *valp;
545	}
546
547	key = gctl_get_param(req, "key", &keysize);
548	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
549		bzero(&md, sizeof(md));
550		gctl_error(req, "No '%s' argument.", "key");
551		return;
552	}
553
554	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
555	md.md_keys |= (1 << nkey);
556
557	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
558
559	/* Encrypt Master Key with the new key. */
560	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
561	bzero(key, sizeof(key));
562	if (error != 0) {
563		bzero(&md, sizeof(md));
564		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
565		return;
566	}
567
568	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
569	/* Store metadata with fresh key. */
570	eli_metadata_encode(&md, sector);
571	bzero(&md, sizeof(md));
572	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
573	    pp->sectorsize);
574	bzero(sector, sizeof(sector));
575	free(sector, M_ELI);
576	if (error != 0) {
577		gctl_error(req, "Cannot store metadata on %s (error=%d).",
578		    pp->name, error);
579		return;
580	}
581	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
582}
583
584static void
585g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
586{
587	struct g_eli_softc *sc;
588	struct g_eli_metadata md;
589	struct g_provider *pp;
590	struct g_consumer *cp;
591	const char *name;
592	u_char *mkeydst, *sector;
593	intmax_t *valp;
594	size_t keysize;
595	int error, nkey, *all, *force;
596	u_int i;
597
598	g_topology_assert();
599
600	nkey = 0;	/* fixes causeless gcc warning */
601
602	name = gctl_get_asciiparam(req, "arg0");
603	if (name == NULL) {
604		gctl_error(req, "No 'arg%u' argument.", 0);
605		return;
606	}
607	sc = g_eli_find_device(mp, name);
608	if (sc == NULL) {
609		gctl_error(req, "Provider %s is invalid.", name);
610		return;
611	}
612	if (sc->sc_flags & G_ELI_FLAG_RO) {
613		gctl_error(req, "Cannot delete keys for read-only provider.");
614		return;
615	}
616	cp = LIST_FIRST(&sc->sc_geom->consumer);
617	pp = cp->provider;
618
619	error = g_eli_read_metadata(mp, pp, &md);
620	if (error != 0) {
621		gctl_error(req, "Cannot read metadata from %s (error=%d).",
622		    name, error);
623		return;
624	}
625
626	all = gctl_get_paraml(req, "all", sizeof(*all));
627	if (all == NULL) {
628		gctl_error(req, "No '%s' argument.", "all");
629		return;
630	}
631
632	if (*all) {
633		mkeydst = md.md_mkeys;
634		keysize = sizeof(md.md_mkeys);
635	} else {
636		force = gctl_get_paraml(req, "force", sizeof(*force));
637		if (force == NULL) {
638			gctl_error(req, "No '%s' argument.", "force");
639			return;
640		}
641
642		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
643		if (valp == NULL) {
644			gctl_error(req, "No '%s' argument.", "keyno");
645			return;
646		}
647		if (*valp != -1)
648			nkey = *valp;
649		else
650			nkey = sc->sc_nkey;
651		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
652			gctl_error(req, "Invalid '%s' argument.", "keyno");
653			return;
654		}
655		if (!(md.md_keys & (1 << nkey)) && !*force) {
656			gctl_error(req, "Master Key %u is not set.", nkey);
657			return;
658		}
659		md.md_keys &= ~(1 << nkey);
660		if (md.md_keys == 0 && !*force) {
661			gctl_error(req, "This is the last Master Key. Use '-f' "
662			    "flag if you really want to remove it.");
663			return;
664		}
665		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
666		keysize = G_ELI_MKEYLEN;
667	}
668
669	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
670	for (i = 0; i <= g_eli_overwrites; i++) {
671		if (i == g_eli_overwrites)
672			bzero(mkeydst, keysize);
673		else
674			arc4rand(mkeydst, keysize, 0);
675		/* Store metadata with destroyed key. */
676		eli_metadata_encode(&md, sector);
677		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
678		    pp->sectorsize);
679		if (error != 0) {
680			G_ELI_DEBUG(0, "Cannot store metadata on %s "
681			    "(error=%d).", pp->name, error);
682		}
683	}
684	bzero(&md, sizeof(md));
685	bzero(sector, sizeof(sector));
686	free(sector, M_ELI);
687	if (*all)
688		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
689	else
690		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
691}
692
693static int
694g_eli_kill_one(struct g_eli_softc *sc)
695{
696	struct g_provider *pp;
697	struct g_consumer *cp;
698	int error = 0;
699
700	g_topology_assert();
701
702	if (sc == NULL)
703		return (ENOENT);
704
705	pp = LIST_FIRST(&sc->sc_geom->provider);
706	g_error_provider(pp, ENXIO);
707
708	cp = LIST_FIRST(&sc->sc_geom->consumer);
709	pp = cp->provider;
710
711	if (sc->sc_flags & G_ELI_FLAG_RO) {
712		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
713		    "provider: %s.", pp->name);
714	} else {
715		u_char *sector;
716		u_int i;
717		int err;
718
719		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
720		for (i = 0; i <= g_eli_overwrites; i++) {
721			if (i == g_eli_overwrites)
722				bzero(sector, pp->sectorsize);
723			else
724				arc4rand(sector, pp->sectorsize, 0);
725			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
726			    sector, pp->sectorsize);
727			if (err != 0) {
728				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
729				    "(error=%d).", pp->name, err);
730				if (error == 0)
731					error = err;
732			}
733		}
734		free(sector, M_ELI);
735	}
736	if (error == 0)
737		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
738	g_eli_destroy(sc, 1);
739	return (error);
740}
741
742static void
743g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
744{
745	int *all, *nargs;
746	int error;
747
748	g_topology_assert();
749
750	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
751	if (nargs == NULL) {
752		gctl_error(req, "No '%s' argument.", "nargs");
753		return;
754	}
755	all = gctl_get_paraml(req, "all", sizeof(*all));
756	if (all == NULL) {
757		gctl_error(req, "No '%s' argument.", "all");
758		return;
759	}
760	if (!*all && *nargs == 0) {
761		gctl_error(req, "Too few arguments.");
762		return;
763	}
764
765	if (*all) {
766		struct g_geom *gp, *gp2;
767
768		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
769			error = g_eli_kill_one(gp->softc);
770			if (error != 0)
771				gctl_error(req, "Not fully done.");
772		}
773	} else {
774		struct g_eli_softc *sc;
775		const char *prov;
776		char param[16];
777		int i;
778
779		for (i = 0; i < *nargs; i++) {
780			snprintf(param, sizeof(param), "arg%d", i);
781			prov = gctl_get_asciiparam(req, param);
782			if (prov == NULL) {
783				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
784				continue;
785			}
786
787			sc = g_eli_find_device(mp, prov);
788			if (sc == NULL) {
789				G_ELI_DEBUG(0, "No such provider: %s.", prov);
790				continue;
791			}
792			error = g_eli_kill_one(sc);
793			if (error != 0)
794				gctl_error(req, "Not fully done.");
795		}
796	}
797}
798
799void
800g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
801{
802	uint32_t *version;
803
804	g_topology_assert();
805
806	version = gctl_get_paraml(req, "version", sizeof(*version));
807	if (version == NULL) {
808		gctl_error(req, "No '%s' argument.", "version");
809		return;
810	}
811	if (*version != G_ELI_VERSION) {
812		gctl_error(req, "Userland and kernel parts are out of sync.");
813		return;
814	}
815
816	if (strcmp(verb, "attach") == 0)
817		g_eli_ctl_attach(req, mp);
818	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
819		g_eli_ctl_detach(req, mp);
820	else if (strcmp(verb, "onetime") == 0)
821		g_eli_ctl_onetime(req, mp);
822	else if (strcmp(verb, "configure") == 0)
823		g_eli_ctl_configure(req, mp);
824	else if (strcmp(verb, "setkey") == 0)
825		g_eli_ctl_setkey(req, mp);
826	else if (strcmp(verb, "delkey") == 0)
827		g_eli_ctl_delkey(req, mp);
828	else if (strcmp(verb, "kill") == 0)
829		g_eli_ctl_kill(req, mp);
830	else
831		gctl_error(req, "Unknown verb.");
832}
833