g_eli_ctl.c revision 257718
1/*-
2 * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
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: stable/10/sys/geom/eli/g_eli_ctl.c 257718 2013-11-05 19:58:40Z delphij $");
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
50MALLOC_DECLARE(M_ELI);
51
52
53static void
54g_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
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 ? TRUE : FALSE);
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 (*name != '\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
370static void
371g_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, pp->sectorsize);
475		free(sector, M_ELI);
476	}
477}
478
479static void
480g_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, keysize);
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, pp->sectorsize);
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
588static void
589g_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		(void)g_io_flush(cp);
692	}
693	bzero(&md, sizeof(md));
694	bzero(sector, pp->sectorsize);
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
702static void
703g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
704{
705	struct g_eli_worker *wr;
706
707	g_topology_assert();
708
709	KASSERT(sc != NULL, ("NULL sc"));
710
711	if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
712		gctl_error(req,
713		    "Device %s is using one-time key, suspend not supported.",
714		    sc->sc_name);
715		return;
716	}
717
718	mtx_lock(&sc->sc_queue_mtx);
719	if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
720		mtx_unlock(&sc->sc_queue_mtx);
721		gctl_error(req, "Device %s already suspended.",
722		    sc->sc_name);
723		return;
724	}
725	sc->sc_flags |= G_ELI_FLAG_SUSPEND;
726	wakeup(sc);
727	for (;;) {
728		LIST_FOREACH(wr, &sc->sc_workers, w_next) {
729			if (wr->w_active)
730				break;
731		}
732		if (wr == NULL)
733			break;
734		/* Not all threads suspended. */
735		msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
736		    "geli:suspend", 0);
737	}
738	/*
739	 * Clear sensitive data on suspend, they will be recovered on resume.
740	 */
741	bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
742	g_eli_key_destroy(sc);
743	bzero(sc->sc_akey, sizeof(sc->sc_akey));
744	bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
745	bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
746	bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
747	mtx_unlock(&sc->sc_queue_mtx);
748	G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
749}
750
751static void
752g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
753{
754	struct g_eli_softc *sc;
755	int *all, *nargs;
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			sc = gp->softc;
779			if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
780				G_ELI_DEBUG(0,
781				    "Device %s is using one-time key, suspend not supported, skipping.",
782				    sc->sc_name);
783				continue;
784			}
785			g_eli_suspend_one(sc, req);
786		}
787	} else {
788		const char *prov;
789		char param[16];
790		int i;
791
792		for (i = 0; i < *nargs; i++) {
793			snprintf(param, sizeof(param), "arg%d", i);
794			prov = gctl_get_asciiparam(req, param);
795			if (prov == NULL) {
796				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
797				continue;
798			}
799
800			sc = g_eli_find_device(mp, prov);
801			if (sc == NULL) {
802				G_ELI_DEBUG(0, "No such provider: %s.", prov);
803				continue;
804			}
805			g_eli_suspend_one(sc, req);
806		}
807	}
808}
809
810static void
811g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
812{
813	struct g_eli_metadata md;
814	struct g_eli_softc *sc;
815	struct g_provider *pp;
816	struct g_consumer *cp;
817	const char *name;
818	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
819	int *nargs, keysize, error;
820	u_int nkey;
821
822	g_topology_assert();
823
824	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
825	if (nargs == NULL) {
826		gctl_error(req, "No '%s' argument.", "nargs");
827		return;
828	}
829	if (*nargs != 1) {
830		gctl_error(req, "Invalid number of arguments.");
831		return;
832	}
833
834	name = gctl_get_asciiparam(req, "arg0");
835	if (name == NULL) {
836		gctl_error(req, "No 'arg%u' argument.", 0);
837		return;
838	}
839	sc = g_eli_find_device(mp, name);
840	if (sc == NULL) {
841		gctl_error(req, "Provider %s is invalid.", name);
842		return;
843	}
844	cp = LIST_FIRST(&sc->sc_geom->consumer);
845	pp = cp->provider;
846	error = g_eli_read_metadata(mp, pp, &md);
847	if (error != 0) {
848		gctl_error(req, "Cannot read metadata from %s (error=%d).",
849		    name, error);
850		return;
851	}
852	if (md.md_keys == 0x00) {
853		bzero(&md, sizeof(md));
854		gctl_error(req, "No valid keys on %s.", pp->name);
855		return;
856	}
857
858	key = gctl_get_param(req, "key", &keysize);
859	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
860		bzero(&md, sizeof(md));
861		gctl_error(req, "No '%s' argument.", "key");
862		return;
863	}
864
865	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
866	bzero(key, keysize);
867	if (error == -1) {
868		bzero(&md, sizeof(md));
869		gctl_error(req, "Wrong key for %s.", pp->name);
870		return;
871	} else if (error > 0) {
872		bzero(&md, sizeof(md));
873		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
874		    pp->name, error);
875		return;
876	}
877	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
878
879	mtx_lock(&sc->sc_queue_mtx);
880	if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
881		gctl_error(req, "Device %s is not suspended.", name);
882	else {
883		/* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
884		g_eli_mkey_propagate(sc, mkey);
885		sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
886		G_ELI_DEBUG(1, "Resumed %s.", pp->name);
887		wakeup(sc);
888	}
889	mtx_unlock(&sc->sc_queue_mtx);
890	bzero(mkey, sizeof(mkey));
891	bzero(&md, sizeof(md));
892}
893
894static int
895g_eli_kill_one(struct g_eli_softc *sc)
896{
897	struct g_provider *pp;
898	struct g_consumer *cp;
899	int error = 0;
900
901	g_topology_assert();
902
903	if (sc == NULL)
904		return (ENOENT);
905
906	pp = LIST_FIRST(&sc->sc_geom->provider);
907	g_error_provider(pp, ENXIO);
908
909	cp = LIST_FIRST(&sc->sc_geom->consumer);
910	pp = cp->provider;
911
912	if (sc->sc_flags & G_ELI_FLAG_RO) {
913		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
914		    "provider: %s.", pp->name);
915	} else {
916		u_char *sector;
917		u_int i;
918		int err;
919
920		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
921		for (i = 0; i <= g_eli_overwrites; i++) {
922			if (i == g_eli_overwrites)
923				bzero(sector, pp->sectorsize);
924			else
925				arc4rand(sector, pp->sectorsize, 0);
926			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
927			    sector, pp->sectorsize);
928			if (err != 0) {
929				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
930				    "(error=%d).", pp->name, err);
931				if (error == 0)
932					error = err;
933			}
934			/*
935			 * Flush write cache so we don't overwrite data N times
936			 * in cache and only once on disk.
937			 */
938			(void)g_io_flush(cp);
939		}
940		free(sector, M_ELI);
941	}
942	if (error == 0)
943		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
944	g_eli_destroy(sc, TRUE);
945	return (error);
946}
947
948static void
949g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
950{
951	int *all, *nargs;
952	int error;
953
954	g_topology_assert();
955
956	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
957	if (nargs == NULL) {
958		gctl_error(req, "No '%s' argument.", "nargs");
959		return;
960	}
961	all = gctl_get_paraml(req, "all", sizeof(*all));
962	if (all == NULL) {
963		gctl_error(req, "No '%s' argument.", "all");
964		return;
965	}
966	if (!*all && *nargs == 0) {
967		gctl_error(req, "Too few arguments.");
968		return;
969	}
970
971	if (*all) {
972		struct g_geom *gp, *gp2;
973
974		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
975			error = g_eli_kill_one(gp->softc);
976			if (error != 0)
977				gctl_error(req, "Not fully done.");
978		}
979	} else {
980		struct g_eli_softc *sc;
981		const char *prov;
982		char param[16];
983		int i;
984
985		for (i = 0; i < *nargs; i++) {
986			snprintf(param, sizeof(param), "arg%d", i);
987			prov = gctl_get_asciiparam(req, param);
988			if (prov == NULL) {
989				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
990				continue;
991			}
992
993			sc = g_eli_find_device(mp, prov);
994			if (sc == NULL) {
995				G_ELI_DEBUG(0, "No such provider: %s.", prov);
996				continue;
997			}
998			error = g_eli_kill_one(sc);
999			if (error != 0)
1000				gctl_error(req, "Not fully done.");
1001		}
1002	}
1003}
1004
1005void
1006g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1007{
1008	uint32_t *version;
1009
1010	g_topology_assert();
1011
1012	version = gctl_get_paraml(req, "version", sizeof(*version));
1013	if (version == NULL) {
1014		gctl_error(req, "No '%s' argument.", "version");
1015		return;
1016	}
1017	while (*version != G_ELI_VERSION) {
1018		if (G_ELI_VERSION == G_ELI_VERSION_06 &&
1019		    *version == G_ELI_VERSION_05) {
1020			/* Compatible. */
1021			break;
1022		}
1023		if (G_ELI_VERSION == G_ELI_VERSION_07 &&
1024		    (*version == G_ELI_VERSION_05 ||
1025		     *version == G_ELI_VERSION_06)) {
1026			/* Compatible. */
1027			break;
1028		}
1029		gctl_error(req, "Userland and kernel parts are out of sync.");
1030		return;
1031	}
1032
1033	if (strcmp(verb, "attach") == 0)
1034		g_eli_ctl_attach(req, mp);
1035	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
1036		g_eli_ctl_detach(req, mp);
1037	else if (strcmp(verb, "onetime") == 0)
1038		g_eli_ctl_onetime(req, mp);
1039	else if (strcmp(verb, "configure") == 0)
1040		g_eli_ctl_configure(req, mp);
1041	else if (strcmp(verb, "setkey") == 0)
1042		g_eli_ctl_setkey(req, mp);
1043	else if (strcmp(verb, "delkey") == 0)
1044		g_eli_ctl_delkey(req, mp);
1045	else if (strcmp(verb, "suspend") == 0)
1046		g_eli_ctl_suspend(req, mp);
1047	else if (strcmp(verb, "resume") == 0)
1048		g_eli_ctl_resume(req, mp);
1049	else if (strcmp(verb, "kill") == 0)
1050		g_eli_ctl_kill(req, mp);
1051	else
1052		gctl_error(req, "Unknown verb.");
1053}
1054