xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision 31f7586d7359058c601154e0026ad983ef22ca98)
1c58794deSPawel Jakub Dawidek /*-
23728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
33728855aSPedro F. Giffuni  *
41e09ff3dSPawel Jakub Dawidek  * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5c58794deSPawel Jakub Dawidek  * All rights reserved.
6c58794deSPawel Jakub Dawidek  *
7c58794deSPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
8c58794deSPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
9c58794deSPawel Jakub Dawidek  * are met:
10c58794deSPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
11c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
12c58794deSPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
13c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
14c58794deSPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
15c58794deSPawel Jakub Dawidek  *
16c58794deSPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17c58794deSPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c58794deSPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c58794deSPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20c58794deSPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c58794deSPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c58794deSPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c58794deSPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c58794deSPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c58794deSPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c58794deSPawel Jakub Dawidek  * SUCH DAMAGE.
27c58794deSPawel Jakub Dawidek  */
28c58794deSPawel Jakub Dawidek 
29c58794deSPawel Jakub Dawidek #include <sys/cdefs.h>
30c58794deSPawel Jakub Dawidek __FBSDID("$FreeBSD$");
31c58794deSPawel Jakub Dawidek 
32c58794deSPawel Jakub Dawidek #include <sys/param.h>
33c58794deSPawel Jakub Dawidek #include <sys/systm.h>
34c58794deSPawel Jakub Dawidek #include <sys/kernel.h>
35c58794deSPawel Jakub Dawidek #include <sys/module.h>
36c58794deSPawel Jakub Dawidek #include <sys/lock.h>
37c58794deSPawel Jakub Dawidek #include <sys/mutex.h>
38c58794deSPawel Jakub Dawidek #include <sys/bio.h>
39c58794deSPawel Jakub Dawidek #include <sys/sysctl.h>
40c58794deSPawel Jakub Dawidek #include <sys/malloc.h>
41c58794deSPawel Jakub Dawidek #include <sys/kthread.h>
42c58794deSPawel Jakub Dawidek #include <sys/proc.h>
43c58794deSPawel Jakub Dawidek #include <sys/sched.h>
44c58794deSPawel Jakub Dawidek #include <sys/uio.h>
45c58794deSPawel Jakub Dawidek 
46c58794deSPawel Jakub Dawidek #include <vm/uma.h>
47c58794deSPawel Jakub Dawidek 
48c58794deSPawel Jakub Dawidek #include <geom/geom.h>
49c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h>
50c58794deSPawel Jakub Dawidek 
51c58794deSPawel Jakub Dawidek 
52c58794deSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI);
53c58794deSPawel Jakub Dawidek 
54c58794deSPawel Jakub Dawidek 
55c58794deSPawel Jakub Dawidek static void
56c58794deSPawel Jakub Dawidek g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
57c58794deSPawel Jakub Dawidek {
58c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
59c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
60c58794deSPawel Jakub Dawidek 	const char *name;
61c58794deSPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
628f1c45c2SMariusz Zaborski 	int *nargs, *detach, *readonly, *dryrun;
63*31f7586dSMariusz Zaborski 	int keysize, error, nkey;
64*31f7586dSMariusz Zaborski 	intmax_t *valp;
65c58794deSPawel Jakub Dawidek 
66c58794deSPawel Jakub Dawidek 	g_topology_assert();
67c58794deSPawel Jakub Dawidek 
68c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
69c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
70c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
71c58794deSPawel Jakub Dawidek 		return;
72c58794deSPawel Jakub Dawidek 	}
73c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
74c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
75c58794deSPawel Jakub Dawidek 		return;
76c58794deSPawel Jakub Dawidek 	}
77c58794deSPawel Jakub Dawidek 
78c58794deSPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
79c58794deSPawel Jakub Dawidek 	if (detach == NULL) {
80c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "detach");
81c58794deSPawel Jakub Dawidek 		return;
82c58794deSPawel Jakub Dawidek 	}
83c58794deSPawel Jakub Dawidek 
84*31f7586dSMariusz Zaborski 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
85*31f7586dSMariusz Zaborski 	if (valp == NULL) {
86*31f7586dSMariusz Zaborski 		gctl_error(req, "No '%s' argument.", "keyno");
87*31f7586dSMariusz Zaborski 		return;
88*31f7586dSMariusz Zaborski 	}
89*31f7586dSMariusz Zaborski 	nkey = *valp;
90*31f7586dSMariusz Zaborski 	if (nkey < -1 || nkey >= G_ELI_MAXMKEYS) {
91*31f7586dSMariusz Zaborski 		gctl_error(req, "Invalid '%s' argument.", "keyno");
92*31f7586dSMariusz Zaborski 		return;
93*31f7586dSMariusz Zaborski 	}
94*31f7586dSMariusz Zaborski 
9585059016SPawel Jakub Dawidek 	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
9685059016SPawel Jakub Dawidek 	if (readonly == NULL) {
9785059016SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "readonly");
9885059016SPawel Jakub Dawidek 		return;
9985059016SPawel Jakub Dawidek 	}
10085059016SPawel Jakub Dawidek 
1018f1c45c2SMariusz Zaborski 	dryrun = gctl_get_paraml(req, "dryrun", sizeof(*dryrun));
1028f1c45c2SMariusz Zaborski 	if (dryrun == NULL) {
1038f1c45c2SMariusz Zaborski 		gctl_error(req, "No '%s' argument.", "dryrun");
1048f1c45c2SMariusz Zaborski 		return;
1058f1c45c2SMariusz Zaborski 	}
1068f1c45c2SMariusz Zaborski 
10739b7ca45SAllan Jude 	if (*detach && *readonly) {
10839b7ca45SAllan Jude 		gctl_error(req, "Options -d and -r are mutually exclusive.");
10939b7ca45SAllan Jude 		return;
11039b7ca45SAllan Jude 	}
11139b7ca45SAllan Jude 
112c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
113c58794deSPawel Jakub Dawidek 	if (name == NULL) {
114c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
115c58794deSPawel Jakub Dawidek 		return;
116c58794deSPawel Jakub Dawidek 	}
117c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
118c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
119c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
120c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
121c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
122c58794deSPawel Jakub Dawidek 		return;
123c58794deSPawel Jakub Dawidek 	}
124c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
125c58794deSPawel Jakub Dawidek 	if (error != 0) {
126c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
127c58794deSPawel Jakub Dawidek 		    name, error);
128c58794deSPawel Jakub Dawidek 		return;
129c58794deSPawel Jakub Dawidek 	}
130c58794deSPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
13139b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
132c58794deSPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
133c58794deSPawel Jakub Dawidek 		return;
134c58794deSPawel Jakub Dawidek 	}
135c58794deSPawel Jakub Dawidek 
136c58794deSPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
137c58794deSPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
13839b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
139c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
140c58794deSPawel Jakub Dawidek 		return;
141c58794deSPawel Jakub Dawidek 	}
142c58794deSPawel Jakub Dawidek 
143*31f7586dSMariusz Zaborski 	if (nkey == -1)
144*31f7586dSMariusz Zaborski 		error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey);
145*31f7586dSMariusz Zaborski 	else
146*31f7586dSMariusz Zaborski 		error = g_eli_mkey_decrypt(&md, key, mkey, nkey);
14739b7ca45SAllan Jude 	explicit_bzero(key, keysize);
148c58794deSPawel Jakub Dawidek 	if (error == -1) {
14939b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
150c58794deSPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
151c58794deSPawel Jakub Dawidek 		return;
152c58794deSPawel Jakub Dawidek 	} else if (error > 0) {
15339b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
154c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
155c58794deSPawel Jakub Dawidek 		    pp->name, error);
156c58794deSPawel Jakub Dawidek 		return;
157c58794deSPawel Jakub Dawidek 	}
158c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
159c58794deSPawel Jakub Dawidek 
160c58794deSPawel Jakub Dawidek 	if (*detach)
161c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
16285059016SPawel Jakub Dawidek 	if (*readonly)
16385059016SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_RO;
1648f1c45c2SMariusz Zaborski 	if (!*dryrun)
165c58794deSPawel Jakub Dawidek 		g_eli_create(req, mp, pp, &md, mkey, nkey);
16639b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
16739b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
168c58794deSPawel Jakub Dawidek }
169c58794deSPawel Jakub Dawidek 
170c58794deSPawel Jakub Dawidek static struct g_eli_softc *
171c58794deSPawel Jakub Dawidek g_eli_find_device(struct g_class *mp, const char *prov)
172c58794deSPawel Jakub Dawidek {
173c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
174c58794deSPawel Jakub Dawidek 	struct g_geom *gp;
175c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
176c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
177c58794deSPawel Jakub Dawidek 
178c58794deSPawel Jakub Dawidek 	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
179c58794deSPawel Jakub Dawidek 		prov += strlen("/dev/");
180c58794deSPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
181c58794deSPawel Jakub Dawidek 		sc = gp->softc;
182c58794deSPawel Jakub Dawidek 		if (sc == NULL)
183c58794deSPawel Jakub Dawidek 			continue;
184c58794deSPawel Jakub Dawidek 		pp = LIST_FIRST(&gp->provider);
185c58794deSPawel Jakub Dawidek 		if (pp != NULL && strcmp(pp->name, prov) == 0)
186c58794deSPawel Jakub Dawidek 			return (sc);
187c58794deSPawel Jakub Dawidek 		cp = LIST_FIRST(&gp->consumer);
188c58794deSPawel Jakub Dawidek 		if (cp != NULL && cp->provider != NULL &&
189c58794deSPawel Jakub Dawidek 		    strcmp(cp->provider->name, prov) == 0) {
190c58794deSPawel Jakub Dawidek 			return (sc);
191c58794deSPawel Jakub Dawidek 		}
192c58794deSPawel Jakub Dawidek 	}
193c58794deSPawel Jakub Dawidek 	return (NULL);
194c58794deSPawel Jakub Dawidek }
195c58794deSPawel Jakub Dawidek 
196c58794deSPawel Jakub Dawidek static void
197c58794deSPawel Jakub Dawidek g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
198c58794deSPawel Jakub Dawidek {
199c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
200c58794deSPawel Jakub Dawidek 	int *force, *last, *nargs, error;
201c58794deSPawel Jakub Dawidek 	const char *prov;
202c58794deSPawel Jakub Dawidek 	char param[16];
2037d54b385SPawel Jakub Dawidek 	int i;
204c58794deSPawel Jakub Dawidek 
205c58794deSPawel Jakub Dawidek 	g_topology_assert();
206c58794deSPawel Jakub Dawidek 
207c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
208c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
209c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
210c58794deSPawel Jakub Dawidek 		return;
211c58794deSPawel Jakub Dawidek 	}
212c58794deSPawel Jakub Dawidek 	if (*nargs <= 0) {
213c58794deSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
214c58794deSPawel Jakub Dawidek 		return;
215c58794deSPawel Jakub Dawidek 	}
216c58794deSPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
217c58794deSPawel Jakub Dawidek 	if (force == NULL) {
218c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "force");
219c58794deSPawel Jakub Dawidek 		return;
220c58794deSPawel Jakub Dawidek 	}
221c58794deSPawel Jakub Dawidek 	last = gctl_get_paraml(req, "last", sizeof(*last));
222c58794deSPawel Jakub Dawidek 	if (last == NULL) {
223c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "last");
224c58794deSPawel Jakub Dawidek 		return;
225c58794deSPawel Jakub Dawidek 	}
226c58794deSPawel Jakub Dawidek 
2277d54b385SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
2287d54b385SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
229c58794deSPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
230c58794deSPawel Jakub Dawidek 		if (prov == NULL) {
2317d54b385SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
232c58794deSPawel Jakub Dawidek 			return;
233c58794deSPawel Jakub Dawidek 		}
234c58794deSPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
235c58794deSPawel Jakub Dawidek 		if (sc == NULL) {
236c58794deSPawel Jakub Dawidek 			gctl_error(req, "No such device: %s.", prov);
237c58794deSPawel Jakub Dawidek 			return;
238c58794deSPawel Jakub Dawidek 		}
239c58794deSPawel Jakub Dawidek 		if (*last) {
240c58794deSPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
241c58794deSPawel Jakub Dawidek 			sc->sc_geom->access = g_eli_access;
242c58794deSPawel Jakub Dawidek 		} else {
2435ad4a7c7SPawel Jakub Dawidek 			error = g_eli_destroy(sc, *force ? TRUE : FALSE);
244c58794deSPawel Jakub Dawidek 			if (error != 0) {
245c58794deSPawel Jakub Dawidek 				gctl_error(req,
246c58794deSPawel Jakub Dawidek 				    "Cannot destroy device %s (error=%d).",
247c58794deSPawel Jakub Dawidek 				    sc->sc_name, error);
248c58794deSPawel Jakub Dawidek 				return;
249c58794deSPawel Jakub Dawidek 			}
250c58794deSPawel Jakub Dawidek 		}
251c58794deSPawel Jakub Dawidek 	}
252c58794deSPawel Jakub Dawidek }
253c58794deSPawel Jakub Dawidek 
254c58794deSPawel Jakub Dawidek static void
255c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
256c58794deSPawel Jakub Dawidek {
257c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
258c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
259c58794deSPawel Jakub Dawidek 	const char *name;
260c58794deSPawel Jakub Dawidek 	intmax_t *keylen, *sectorsize;
261c58794deSPawel Jakub Dawidek 	u_char mkey[G_ELI_DATAIVKEYLEN];
26246e34470SPawel Jakub Dawidek 	int *nargs, *detach, *notrim;
263c58794deSPawel Jakub Dawidek 
264c58794deSPawel Jakub Dawidek 	g_topology_assert();
265c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
266c58794deSPawel Jakub Dawidek 
267c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
268c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
269c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
270c58794deSPawel Jakub Dawidek 		return;
271c58794deSPawel Jakub Dawidek 	}
272c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
273c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
274c58794deSPawel Jakub Dawidek 		return;
275c58794deSPawel Jakub Dawidek 	}
276c58794deSPawel Jakub Dawidek 
277c58794deSPawel Jakub Dawidek 	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
278c58794deSPawel Jakub Dawidek 	md.md_version = G_ELI_VERSION;
279c58794deSPawel Jakub Dawidek 	md.md_flags |= G_ELI_FLAG_ONETIME;
28046e34470SPawel Jakub Dawidek 
28146e34470SPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
28246e34470SPawel Jakub Dawidek 	if (detach != NULL && *detach)
283c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
28446e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
28546e34470SPawel Jakub Dawidek 	if (notrim != NULL && *notrim)
28646e34470SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_NODELETE;
287c58794deSPawel Jakub Dawidek 
288c84efdcaSPawel Jakub Dawidek 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
289eaa3b919SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "aalgo");
290c58794deSPawel Jakub Dawidek 	if (name == NULL) {
291eaa3b919SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "aalgo");
292c58794deSPawel Jakub Dawidek 		return;
293c58794deSPawel Jakub Dawidek 	}
294a478ea74SPawel Jakub Dawidek 	if (*name != '\0') {
295eaa3b919SPawel Jakub Dawidek 		md.md_aalgo = g_eli_str2aalgo(name);
296c84efdcaSPawel Jakub Dawidek 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
297c84efdcaSPawel Jakub Dawidek 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
298eaa3b919SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_AUTH;
299c84efdcaSPawel Jakub Dawidek 		} else {
300c84efdcaSPawel Jakub Dawidek 			/*
301c84efdcaSPawel Jakub Dawidek 			 * For backward compatibility, check if the -a option
302c84efdcaSPawel Jakub Dawidek 			 * was used to provide encryption algorithm.
303c84efdcaSPawel Jakub Dawidek 			 */
304c84efdcaSPawel Jakub Dawidek 			md.md_ealgo = g_eli_str2ealgo(name);
305c84efdcaSPawel Jakub Dawidek 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
306c84efdcaSPawel Jakub Dawidek 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
307c84efdcaSPawel Jakub Dawidek 				gctl_error(req,
308c84efdcaSPawel Jakub Dawidek 				    "Invalid authentication algorithm.");
309c84efdcaSPawel Jakub Dawidek 				return;
310c84efdcaSPawel Jakub Dawidek 			} else {
311c84efdcaSPawel Jakub Dawidek 				gctl_error(req, "warning: The -e option, not "
312c84efdcaSPawel Jakub Dawidek 				    "the -a option is now used to specify "
313c84efdcaSPawel Jakub Dawidek 				    "encryption algorithm to use.");
314c84efdcaSPawel Jakub Dawidek 			}
315c84efdcaSPawel Jakub Dawidek 		}
316eaa3b919SPawel Jakub Dawidek 	}
317eaa3b919SPawel Jakub Dawidek 
318c84efdcaSPawel Jakub Dawidek 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
319c84efdcaSPawel Jakub Dawidek 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
320eaa3b919SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, "ealgo");
321eaa3b919SPawel Jakub Dawidek 		if (name == NULL) {
322eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "ealgo");
323eaa3b919SPawel Jakub Dawidek 			return;
324eaa3b919SPawel Jakub Dawidek 		}
325eaa3b919SPawel Jakub Dawidek 		md.md_ealgo = g_eli_str2ealgo(name);
326eaa3b919SPawel Jakub Dawidek 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
327eaa3b919SPawel Jakub Dawidek 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
328eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "Invalid encryption algorithm.");
329c58794deSPawel Jakub Dawidek 			return;
330c58794deSPawel Jakub Dawidek 		}
331c84efdcaSPawel Jakub Dawidek 	}
332c58794deSPawel Jakub Dawidek 
333c58794deSPawel Jakub Dawidek 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
334c58794deSPawel Jakub Dawidek 	if (keylen == NULL) {
335c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keylen");
336c58794deSPawel Jakub Dawidek 		return;
337c58794deSPawel Jakub Dawidek 	}
338eaa3b919SPawel Jakub Dawidek 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
339c58794deSPawel Jakub Dawidek 	if (md.md_keylen == 0) {
340c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keylen");
341c58794deSPawel Jakub Dawidek 		return;
342c58794deSPawel Jakub Dawidek 	}
343c58794deSPawel Jakub Dawidek 
344c58794deSPawel Jakub Dawidek 	/* Not important here. */
345c58794deSPawel Jakub Dawidek 	md.md_provsize = 0;
346c58794deSPawel Jakub Dawidek 	/* Not important here. */
347c58794deSPawel Jakub Dawidek 	bzero(md.md_salt, sizeof(md.md_salt));
348c58794deSPawel Jakub Dawidek 
349c58794deSPawel Jakub Dawidek 	md.md_keys = 0x01;
350c58794deSPawel Jakub Dawidek 	arc4rand(mkey, sizeof(mkey), 0);
351c58794deSPawel Jakub Dawidek 
352c58794deSPawel Jakub Dawidek 	/* Not important here. */
353c58794deSPawel Jakub Dawidek 	bzero(md.md_hash, sizeof(md.md_hash));
354c58794deSPawel Jakub Dawidek 
355c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
356c58794deSPawel Jakub Dawidek 	if (name == NULL) {
357c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
358c58794deSPawel Jakub Dawidek 		return;
359c58794deSPawel Jakub Dawidek 	}
360c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
361c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
362c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
363c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
364c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
365c58794deSPawel Jakub Dawidek 		return;
366c58794deSPawel Jakub Dawidek 	}
367c58794deSPawel Jakub Dawidek 
368c58794deSPawel Jakub Dawidek 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
369c58794deSPawel Jakub Dawidek 	if (sectorsize == NULL) {
370c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "sectorsize");
371c58794deSPawel Jakub Dawidek 		return;
372c58794deSPawel Jakub Dawidek 	}
373c58794deSPawel Jakub Dawidek 	if (*sectorsize == 0)
374c58794deSPawel Jakub Dawidek 		md.md_sectorsize = pp->sectorsize;
375c58794deSPawel Jakub Dawidek 	else {
376c58794deSPawel Jakub Dawidek 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
377c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid sector size.");
378c58794deSPawel Jakub Dawidek 			return;
379c58794deSPawel Jakub Dawidek 		}
38097a669a3SPawel Jakub Dawidek 		if (*sectorsize > PAGE_SIZE) {
38197a669a3SPawel Jakub Dawidek 			gctl_error(req, "warning: Using sectorsize bigger than "
38297a669a3SPawel Jakub Dawidek 			    "the page size!");
38397a669a3SPawel Jakub Dawidek 		}
384c58794deSPawel Jakub Dawidek 		md.md_sectorsize = *sectorsize;
385c58794deSPawel Jakub Dawidek 	}
386c58794deSPawel Jakub Dawidek 
387c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, -1);
38839b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
38939b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
390c58794deSPawel Jakub Dawidek }
391c58794deSPawel Jakub Dawidek 
392c58794deSPawel Jakub Dawidek static void
3938abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
3948abd1ad1SPawel Jakub Dawidek {
3958abd1ad1SPawel Jakub Dawidek 	struct g_eli_softc *sc;
3968abd1ad1SPawel Jakub Dawidek 	struct g_eli_metadata md;
3978abd1ad1SPawel Jakub Dawidek 	struct g_provider *pp;
3988abd1ad1SPawel Jakub Dawidek 	struct g_consumer *cp;
3998abd1ad1SPawel Jakub Dawidek 	char param[16];
4008abd1ad1SPawel Jakub Dawidek 	const char *prov;
4018abd1ad1SPawel Jakub Dawidek 	u_char *sector;
402d8736625SAllan Jude 	int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot;
4033453dc72SMariusz Zaborski 	int *displaypass, *nodisplaypass;
40446e34470SPawel Jakub Dawidek 	int zero, error, changed;
4058abd1ad1SPawel Jakub Dawidek 	u_int i;
4068abd1ad1SPawel Jakub Dawidek 
4078abd1ad1SPawel Jakub Dawidek 	g_topology_assert();
4088abd1ad1SPawel Jakub Dawidek 
40946e34470SPawel Jakub Dawidek 	changed = 0;
41046e34470SPawel Jakub Dawidek 	zero = 0;
41146e34470SPawel Jakub Dawidek 
4128abd1ad1SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
4138abd1ad1SPawel Jakub Dawidek 	if (nargs == NULL) {
4148abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
4158abd1ad1SPawel Jakub Dawidek 		return;
4168abd1ad1SPawel Jakub Dawidek 	}
4178abd1ad1SPawel Jakub Dawidek 	if (*nargs <= 0) {
4188abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
4198abd1ad1SPawel Jakub Dawidek 		return;
4208abd1ad1SPawel Jakub Dawidek 	}
4218abd1ad1SPawel Jakub Dawidek 
4228abd1ad1SPawel Jakub Dawidek 	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
42346e34470SPawel Jakub Dawidek 	if (boot == NULL)
42446e34470SPawel Jakub Dawidek 		boot = &zero;
4258abd1ad1SPawel Jakub Dawidek 	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
42646e34470SPawel Jakub Dawidek 	if (noboot == NULL)
42746e34470SPawel Jakub Dawidek 		noboot = &zero;
4288abd1ad1SPawel Jakub Dawidek 	if (*boot && *noboot) {
4298abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Options -b and -B are mutually exclusive.");
4308abd1ad1SPawel Jakub Dawidek 		return;
4318abd1ad1SPawel Jakub Dawidek 	}
43246e34470SPawel Jakub Dawidek 	if (*boot || *noboot)
43346e34470SPawel Jakub Dawidek 		changed = 1;
43446e34470SPawel Jakub Dawidek 
43546e34470SPawel Jakub Dawidek 	trim = gctl_get_paraml(req, "trim", sizeof(*trim));
43646e34470SPawel Jakub Dawidek 	if (trim == NULL)
43746e34470SPawel Jakub Dawidek 		trim = &zero;
43846e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
43946e34470SPawel Jakub Dawidek 	if (notrim == NULL)
44046e34470SPawel Jakub Dawidek 		notrim = &zero;
44146e34470SPawel Jakub Dawidek 	if (*trim && *notrim) {
44246e34470SPawel Jakub Dawidek 		gctl_error(req, "Options -t and -T are mutually exclusive.");
44346e34470SPawel Jakub Dawidek 		return;
44446e34470SPawel Jakub Dawidek 	}
44546e34470SPawel Jakub Dawidek 	if (*trim || *notrim)
44646e34470SPawel Jakub Dawidek 		changed = 1;
44746e34470SPawel Jakub Dawidek 
448d8736625SAllan Jude 	geliboot = gctl_get_paraml(req, "geliboot", sizeof(*geliboot));
449d8736625SAllan Jude 	if (geliboot == NULL)
450d8736625SAllan Jude 		geliboot = &zero;
451d8736625SAllan Jude 	nogeliboot = gctl_get_paraml(req, "nogeliboot", sizeof(*nogeliboot));
452d8736625SAllan Jude 	if (nogeliboot == NULL)
453d8736625SAllan Jude 		nogeliboot = &zero;
454d8736625SAllan Jude 	if (*geliboot && *nogeliboot) {
455d8736625SAllan Jude 		gctl_error(req, "Options -g and -G are mutually exclusive.");
456d8736625SAllan Jude 		return;
457d8736625SAllan Jude 	}
458d8736625SAllan Jude 	if (*geliboot || *nogeliboot)
459d8736625SAllan Jude 		changed = 1;
460d8736625SAllan Jude 
4613453dc72SMariusz Zaborski 	displaypass = gctl_get_paraml(req, "displaypass", sizeof(*displaypass));
4623453dc72SMariusz Zaborski 	if (displaypass == NULL)
4633453dc72SMariusz Zaborski 		displaypass = &zero;
4643453dc72SMariusz Zaborski 	nodisplaypass = gctl_get_paraml(req, "nodisplaypass", sizeof(*nodisplaypass));
4653453dc72SMariusz Zaborski 	if (nodisplaypass == NULL)
4663453dc72SMariusz Zaborski 		nodisplaypass = &zero;
4673453dc72SMariusz Zaborski 	if (*displaypass && *nodisplaypass) {
4683453dc72SMariusz Zaborski 		gctl_error(req, "Options -d and -D are mutually exclusive.");
4693453dc72SMariusz Zaborski 		return;
4703453dc72SMariusz Zaborski 	}
4713453dc72SMariusz Zaborski 	if (*displaypass || *nodisplaypass)
4723453dc72SMariusz Zaborski 		changed = 1;
4733453dc72SMariusz Zaborski 
47446e34470SPawel Jakub Dawidek 	if (!changed) {
4758abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No option given.");
4768abd1ad1SPawel Jakub Dawidek 		return;
4778abd1ad1SPawel Jakub Dawidek 	}
4788abd1ad1SPawel Jakub Dawidek 
4798abd1ad1SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
4808abd1ad1SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
4818abd1ad1SPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
4828abd1ad1SPawel Jakub Dawidek 		if (prov == NULL) {
4838abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
4848abd1ad1SPawel Jakub Dawidek 			return;
4858abd1ad1SPawel Jakub Dawidek 		}
4868abd1ad1SPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
4878abd1ad1SPawel Jakub Dawidek 		if (sc == NULL) {
4888abd1ad1SPawel Jakub Dawidek 			/*
4898abd1ad1SPawel Jakub Dawidek 			 * We ignore not attached providers, userland part will
4908abd1ad1SPawel Jakub Dawidek 			 * take care of them.
4918abd1ad1SPawel Jakub Dawidek 			 */
4928abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "Skipping configuration of not attached "
4938abd1ad1SPawel Jakub Dawidek 			    "provider %s.", prov);
4948abd1ad1SPawel Jakub Dawidek 			continue;
4958abd1ad1SPawel Jakub Dawidek 		}
4968abd1ad1SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_RO) {
4978abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "Cannot change configuration of "
4988abd1ad1SPawel Jakub Dawidek 			    "read-only provider %s.", prov);
4998abd1ad1SPawel Jakub Dawidek 			continue;
5008abd1ad1SPawel Jakub Dawidek 		}
50146e34470SPawel Jakub Dawidek 
50246e34470SPawel Jakub Dawidek 		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
50346e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
50446e34470SPawel Jakub Dawidek 			    prov);
50546e34470SPawel Jakub Dawidek 			continue;
50646e34470SPawel Jakub Dawidek 		} else if (*noboot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
50746e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
50846e34470SPawel Jakub Dawidek 			    prov);
50946e34470SPawel Jakub Dawidek 			continue;
51046e34470SPawel Jakub Dawidek 		}
51146e34470SPawel Jakub Dawidek 
51246e34470SPawel Jakub Dawidek 		if (*notrim && (sc->sc_flags & G_ELI_FLAG_NODELETE)) {
51346e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag already configured for %s.",
51446e34470SPawel Jakub Dawidek 			    prov);
51546e34470SPawel Jakub Dawidek 			continue;
51646e34470SPawel Jakub Dawidek 		} else if (*trim && !(sc->sc_flags & G_ELI_FLAG_NODELETE)) {
51746e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag not configured for %s.",
51846e34470SPawel Jakub Dawidek 			    prov);
51946e34470SPawel Jakub Dawidek 			continue;
52046e34470SPawel Jakub Dawidek 		}
52146e34470SPawel Jakub Dawidek 
522d8736625SAllan Jude 		if (*geliboot && (sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
523d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag already configured for %s.",
524d8736625SAllan Jude 			    prov);
525d8736625SAllan Jude 			continue;
526d8736625SAllan Jude 		} else if (*nogeliboot && !(sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
527d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag not configured for %s.",
528d8736625SAllan Jude 			    prov);
529d8736625SAllan Jude 			continue;
530d8736625SAllan Jude 		}
531d8736625SAllan Jude 
5323453dc72SMariusz Zaborski 		if (*displaypass && (sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5333453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag already configured for %s.",
5343453dc72SMariusz Zaborski 			    prov);
5353453dc72SMariusz Zaborski 			continue;
5363453dc72SMariusz Zaborski 		} else if (*nodisplaypass &&
5373453dc72SMariusz Zaborski 		    !(sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5383453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag not configured for %s.",
5393453dc72SMariusz Zaborski 			    prov);
5403453dc72SMariusz Zaborski 			continue;
5413453dc72SMariusz Zaborski 		}
5423453dc72SMariusz Zaborski 
54346e34470SPawel Jakub Dawidek 		if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
54446e34470SPawel Jakub Dawidek 			/*
54546e34470SPawel Jakub Dawidek 			 * ONETIME providers don't write metadata to
54646e34470SPawel Jakub Dawidek 			 * disk, so don't try reading it.  This means
54746e34470SPawel Jakub Dawidek 			 * we're bit-flipping uninitialized memory in md
54846e34470SPawel Jakub Dawidek 			 * below, but that's OK; we don't do anything
54946e34470SPawel Jakub Dawidek 			 * with it later.
55046e34470SPawel Jakub Dawidek 			 */
5518abd1ad1SPawel Jakub Dawidek 			cp = LIST_FIRST(&sc->sc_geom->consumer);
5528abd1ad1SPawel Jakub Dawidek 			pp = cp->provider;
5538abd1ad1SPawel Jakub Dawidek 			error = g_eli_read_metadata(mp, pp, &md);
5548abd1ad1SPawel Jakub Dawidek 			if (error != 0) {
5558abd1ad1SPawel Jakub Dawidek 			    gctl_error(req,
5568abd1ad1SPawel Jakub Dawidek 				"Cannot read metadata from %s (error=%d).",
5578abd1ad1SPawel Jakub Dawidek 				prov, error);
5588abd1ad1SPawel Jakub Dawidek 			    continue;
5598abd1ad1SPawel Jakub Dawidek 			}
56046e34470SPawel Jakub Dawidek 		}
5618abd1ad1SPawel Jakub Dawidek 
5628abd1ad1SPawel Jakub Dawidek 		if (*boot) {
5638abd1ad1SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_BOOT;
5648abd1ad1SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_BOOT;
56546e34470SPawel Jakub Dawidek 		} else if (*noboot) {
5668abd1ad1SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_BOOT;
5678abd1ad1SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
5688abd1ad1SPawel Jakub Dawidek 		}
5698abd1ad1SPawel Jakub Dawidek 
57046e34470SPawel Jakub Dawidek 		if (*notrim) {
57146e34470SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_NODELETE;
57246e34470SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_NODELETE;
57346e34470SPawel Jakub Dawidek 		} else if (*trim) {
57446e34470SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_NODELETE;
57546e34470SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_NODELETE;
57646e34470SPawel Jakub Dawidek 		}
57746e34470SPawel Jakub Dawidek 
578d8736625SAllan Jude 		if (*geliboot) {
579d8736625SAllan Jude 			md.md_flags |= G_ELI_FLAG_GELIBOOT;
580d8736625SAllan Jude 			sc->sc_flags |= G_ELI_FLAG_GELIBOOT;
581d8736625SAllan Jude 		} else if (*nogeliboot) {
582d8736625SAllan Jude 			md.md_flags &= ~G_ELI_FLAG_GELIBOOT;
583d8736625SAllan Jude 			sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT;
584d8736625SAllan Jude 		}
585d8736625SAllan Jude 
5863453dc72SMariusz Zaborski 		if (*displaypass) {
5873453dc72SMariusz Zaborski 			md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5883453dc72SMariusz Zaborski 			sc->sc_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5893453dc72SMariusz Zaborski 		} else if (*nodisplaypass) {
5903453dc72SMariusz Zaborski 			md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5913453dc72SMariusz Zaborski 			sc->sc_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5923453dc72SMariusz Zaborski 		}
5933453dc72SMariusz Zaborski 
59446e34470SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
59546e34470SPawel Jakub Dawidek 			/* There's no metadata on disk so we are done here. */
59646e34470SPawel Jakub Dawidek 			continue;
59746e34470SPawel Jakub Dawidek 		}
59846e34470SPawel Jakub Dawidek 
5998abd1ad1SPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
6008abd1ad1SPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
6018abd1ad1SPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
6028abd1ad1SPawel Jakub Dawidek 		    pp->sectorsize);
6038abd1ad1SPawel Jakub Dawidek 		if (error != 0) {
6048abd1ad1SPawel Jakub Dawidek 			gctl_error(req,
6058abd1ad1SPawel Jakub Dawidek 			    "Cannot store metadata on %s (error=%d).",
6068abd1ad1SPawel Jakub Dawidek 			    prov, error);
6078abd1ad1SPawel Jakub Dawidek 		}
60839b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
60939b7ca45SAllan Jude 		explicit_bzero(sector, pp->sectorsize);
6108abd1ad1SPawel Jakub Dawidek 		free(sector, M_ELI);
6118abd1ad1SPawel Jakub Dawidek 	}
6128abd1ad1SPawel Jakub Dawidek }
6138abd1ad1SPawel Jakub Dawidek 
6148abd1ad1SPawel Jakub Dawidek static void
615c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
616c58794deSPawel Jakub Dawidek {
617c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
618c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
619c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
620c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
621c58794deSPawel Jakub Dawidek 	const char *name;
622c58794deSPawel Jakub Dawidek 	u_char *key, *mkeydst, *sector;
623c58794deSPawel Jakub Dawidek 	intmax_t *valp;
6247a5c26fcSPawel Jakub Dawidek 	int keysize, nkey, error;
625c58794deSPawel Jakub Dawidek 
626c58794deSPawel Jakub Dawidek 	g_topology_assert();
627c58794deSPawel Jakub Dawidek 
628c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
629c58794deSPawel Jakub Dawidek 	if (name == NULL) {
630c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
631c58794deSPawel Jakub Dawidek 		return;
632c58794deSPawel Jakub Dawidek 	}
63339b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
63439b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
63539b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
63639b7ca45SAllan Jude 		return;
63739b7ca45SAllan Jude 	}
638c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
639c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
640c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
641c58794deSPawel Jakub Dawidek 		return;
642c58794deSPawel Jakub Dawidek 	}
64385059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
64485059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot change keys for read-only provider.");
64585059016SPawel Jakub Dawidek 		return;
64685059016SPawel Jakub Dawidek 	}
647c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
648c58794deSPawel Jakub Dawidek 	pp = cp->provider;
649c58794deSPawel Jakub Dawidek 
650c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
651c58794deSPawel Jakub Dawidek 	if (error != 0) {
652c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
653c58794deSPawel Jakub Dawidek 		    name, error);
654c58794deSPawel Jakub Dawidek 		return;
655c58794deSPawel Jakub Dawidek 	}
656c58794deSPawel Jakub Dawidek 
657c58794deSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
658c58794deSPawel Jakub Dawidek 	if (valp == NULL) {
659c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keyno");
660c58794deSPawel Jakub Dawidek 		return;
661c58794deSPawel Jakub Dawidek 	}
662c58794deSPawel Jakub Dawidek 	if (*valp != -1)
663c58794deSPawel Jakub Dawidek 		nkey = *valp;
664c58794deSPawel Jakub Dawidek 	else
665c58794deSPawel Jakub Dawidek 		nkey = sc->sc_nkey;
666c58794deSPawel Jakub Dawidek 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
667c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keyno");
668c58794deSPawel Jakub Dawidek 		return;
669c58794deSPawel Jakub Dawidek 	}
670c58794deSPawel Jakub Dawidek 
6717a5c26fcSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
6727a5c26fcSPawel Jakub Dawidek 	if (valp == NULL) {
6737a5c26fcSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "iterations");
6747a5c26fcSPawel Jakub Dawidek 		return;
6757a5c26fcSPawel Jakub Dawidek 	}
6767a5c26fcSPawel Jakub Dawidek 	/* Check if iterations number should and can be changed. */
677d8880fd4SAlexander Motin 	if (*valp != -1 && md.md_iterations == -1) {
678d8880fd4SAlexander Motin 		md.md_iterations = *valp;
679d8880fd4SAlexander Motin 	} else if (*valp != -1 && *valp != md.md_iterations) {
6807a5c26fcSPawel Jakub Dawidek 		if (bitcount32(md.md_keys) != 1) {
6817a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "To be able to use '-i' option, only "
6827a5c26fcSPawel Jakub Dawidek 			    "one key can be defined.");
6837a5c26fcSPawel Jakub Dawidek 			return;
6847a5c26fcSPawel Jakub Dawidek 		}
6857a5c26fcSPawel Jakub Dawidek 		if (md.md_keys != (1 << nkey)) {
6867a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "Only already defined key can be "
6877a5c26fcSPawel Jakub Dawidek 			    "changed when '-i' option is used.");
6887a5c26fcSPawel Jakub Dawidek 			return;
6897a5c26fcSPawel Jakub Dawidek 		}
6907a5c26fcSPawel Jakub Dawidek 		md.md_iterations = *valp;
6917a5c26fcSPawel Jakub Dawidek 	}
6927a5c26fcSPawel Jakub Dawidek 
693c58794deSPawel Jakub Dawidek 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
694c58794deSPawel Jakub Dawidek 	md.md_keys |= (1 << nkey);
695c58794deSPawel Jakub Dawidek 
696eaa3b919SPawel Jakub Dawidek 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
697c58794deSPawel Jakub Dawidek 
698c58794deSPawel Jakub Dawidek 	/* Encrypt Master Key with the new key. */
699eaa3b919SPawel Jakub Dawidek 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
70039b7ca45SAllan Jude 	explicit_bzero(key, keysize);
701c58794deSPawel Jakub Dawidek 	if (error != 0) {
70239b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
703c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
704c58794deSPawel Jakub Dawidek 		return;
705c58794deSPawel Jakub Dawidek 	}
706c58794deSPawel Jakub Dawidek 
707c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
708c58794deSPawel Jakub Dawidek 	/* Store metadata with fresh key. */
709c58794deSPawel Jakub Dawidek 	eli_metadata_encode(&md, sector);
71039b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
711c58794deSPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
712c58794deSPawel Jakub Dawidek 	    pp->sectorsize);
71339b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
714c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
715c58794deSPawel Jakub Dawidek 	if (error != 0) {
716c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
717c58794deSPawel Jakub Dawidek 		    pp->name, error);
718c58794deSPawel Jakub Dawidek 		return;
719c58794deSPawel Jakub Dawidek 	}
720c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
721c58794deSPawel Jakub Dawidek }
722c58794deSPawel Jakub Dawidek 
723c58794deSPawel Jakub Dawidek static void
724c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
725c58794deSPawel Jakub Dawidek {
726c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
727c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
728c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
729c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
730c58794deSPawel Jakub Dawidek 	const char *name;
731c58794deSPawel Jakub Dawidek 	u_char *mkeydst, *sector;
732c58794deSPawel Jakub Dawidek 	intmax_t *valp;
733c58794deSPawel Jakub Dawidek 	size_t keysize;
734c58794deSPawel Jakub Dawidek 	int error, nkey, *all, *force;
735c58794deSPawel Jakub Dawidek 	u_int i;
736c58794deSPawel Jakub Dawidek 
737c58794deSPawel Jakub Dawidek 	g_topology_assert();
738c58794deSPawel Jakub Dawidek 
739c58794deSPawel Jakub Dawidek 	nkey = 0;	/* fixes causeless gcc warning */
740c58794deSPawel Jakub Dawidek 
741c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
742c58794deSPawel Jakub Dawidek 	if (name == NULL) {
743c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
744c58794deSPawel Jakub Dawidek 		return;
745c58794deSPawel Jakub Dawidek 	}
746c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
747c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
748c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
749c58794deSPawel Jakub Dawidek 		return;
750c58794deSPawel Jakub Dawidek 	}
75185059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
75285059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot delete keys for read-only provider.");
75385059016SPawel Jakub Dawidek 		return;
75485059016SPawel Jakub Dawidek 	}
755c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
756c58794deSPawel Jakub Dawidek 	pp = cp->provider;
757c58794deSPawel Jakub Dawidek 
758c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
759c58794deSPawel Jakub Dawidek 	if (error != 0) {
760c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
761c58794deSPawel Jakub Dawidek 		    name, error);
762c58794deSPawel Jakub Dawidek 		return;
763c58794deSPawel Jakub Dawidek 	}
764c58794deSPawel Jakub Dawidek 
765c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
766c58794deSPawel Jakub Dawidek 	if (all == NULL) {
767c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
768c58794deSPawel Jakub Dawidek 		return;
769c58794deSPawel Jakub Dawidek 	}
770c58794deSPawel Jakub Dawidek 
771c58794deSPawel Jakub Dawidek 	if (*all) {
772c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys;
773c58794deSPawel Jakub Dawidek 		keysize = sizeof(md.md_mkeys);
774c58794deSPawel Jakub Dawidek 	} else {
775c58794deSPawel Jakub Dawidek 		force = gctl_get_paraml(req, "force", sizeof(*force));
776c58794deSPawel Jakub Dawidek 		if (force == NULL) {
777c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "force");
778c58794deSPawel Jakub Dawidek 			return;
779c58794deSPawel Jakub Dawidek 		}
780c58794deSPawel Jakub Dawidek 
781c58794deSPawel Jakub Dawidek 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
782c58794deSPawel Jakub Dawidek 		if (valp == NULL) {
783c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "keyno");
784c58794deSPawel Jakub Dawidek 			return;
785c58794deSPawel Jakub Dawidek 		}
786c58794deSPawel Jakub Dawidek 		if (*valp != -1)
787c58794deSPawel Jakub Dawidek 			nkey = *valp;
788c58794deSPawel Jakub Dawidek 		else
789c58794deSPawel Jakub Dawidek 			nkey = sc->sc_nkey;
790c58794deSPawel Jakub Dawidek 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
791c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid '%s' argument.", "keyno");
792c58794deSPawel Jakub Dawidek 			return;
793c58794deSPawel Jakub Dawidek 		}
794c58794deSPawel Jakub Dawidek 		if (!(md.md_keys & (1 << nkey)) && !*force) {
795c58794deSPawel Jakub Dawidek 			gctl_error(req, "Master Key %u is not set.", nkey);
796c58794deSPawel Jakub Dawidek 			return;
797c58794deSPawel Jakub Dawidek 		}
798c58794deSPawel Jakub Dawidek 		md.md_keys &= ~(1 << nkey);
799c58794deSPawel Jakub Dawidek 		if (md.md_keys == 0 && !*force) {
800c58794deSPawel Jakub Dawidek 			gctl_error(req, "This is the last Master Key. Use '-f' "
801c58794deSPawel Jakub Dawidek 			    "flag if you really want to remove it.");
802c58794deSPawel Jakub Dawidek 			return;
803c58794deSPawel Jakub Dawidek 		}
804c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
805c58794deSPawel Jakub Dawidek 		keysize = G_ELI_MKEYLEN;
806c58794deSPawel Jakub Dawidek 	}
807c58794deSPawel Jakub Dawidek 
808c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
809c58794deSPawel Jakub Dawidek 	for (i = 0; i <= g_eli_overwrites; i++) {
810c58794deSPawel Jakub Dawidek 		if (i == g_eli_overwrites)
81139b7ca45SAllan Jude 			explicit_bzero(mkeydst, keysize);
812c58794deSPawel Jakub Dawidek 		else
813c58794deSPawel Jakub Dawidek 			arc4rand(mkeydst, keysize, 0);
814c58794deSPawel Jakub Dawidek 		/* Store metadata with destroyed key. */
815c58794deSPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
816c58794deSPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
817c58794deSPawel Jakub Dawidek 		    pp->sectorsize);
818c58794deSPawel Jakub Dawidek 		if (error != 0) {
819c58794deSPawel Jakub Dawidek 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
820c58794deSPawel Jakub Dawidek 			    "(error=%d).", pp->name, error);
821c58794deSPawel Jakub Dawidek 		}
822f0256e71SPawel Jakub Dawidek 		/*
823f0256e71SPawel Jakub Dawidek 		 * Flush write cache so we don't overwrite data N times in cache
824f0256e71SPawel Jakub Dawidek 		 * and only once on disk.
825f0256e71SPawel Jakub Dawidek 		 */
826350e8df8SPawel Jakub Dawidek 		(void)g_io_flush(cp);
827c58794deSPawel Jakub Dawidek 	}
82839b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
82939b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
830c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
831c58794deSPawel Jakub Dawidek 	if (*all)
832c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
833c58794deSPawel Jakub Dawidek 	else
834c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
835c58794deSPawel Jakub Dawidek }
836c58794deSPawel Jakub Dawidek 
8370d2f5a4eSPawel Jakub Dawidek static void
8380d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
8395ad4a7c7SPawel Jakub Dawidek {
8405ad4a7c7SPawel Jakub Dawidek 	struct g_eli_worker *wr;
8415ad4a7c7SPawel Jakub Dawidek 
8425ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8435ad4a7c7SPawel Jakub Dawidek 
8440d2f5a4eSPawel Jakub Dawidek 	KASSERT(sc != NULL, ("NULL sc"));
8450d2f5a4eSPawel Jakub Dawidek 
8460d2f5a4eSPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
8470d2f5a4eSPawel Jakub Dawidek 		gctl_error(req,
8480d2f5a4eSPawel Jakub Dawidek 		    "Device %s is using one-time key, suspend not supported.",
8490d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8500d2f5a4eSPawel Jakub Dawidek 		return;
8510d2f5a4eSPawel Jakub Dawidek 	}
8525ad4a7c7SPawel Jakub Dawidek 
8535ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
8545ad4a7c7SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
8555ad4a7c7SPawel Jakub Dawidek 		mtx_unlock(&sc->sc_queue_mtx);
8560d2f5a4eSPawel Jakub Dawidek 		gctl_error(req, "Device %s already suspended.",
8570d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8580d2f5a4eSPawel Jakub Dawidek 		return;
8595ad4a7c7SPawel Jakub Dawidek 	}
8605ad4a7c7SPawel Jakub Dawidek 	sc->sc_flags |= G_ELI_FLAG_SUSPEND;
8615ad4a7c7SPawel Jakub Dawidek 	wakeup(sc);
8625ad4a7c7SPawel Jakub Dawidek 	for (;;) {
8635ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH(wr, &sc->sc_workers, w_next) {
8645ad4a7c7SPawel Jakub Dawidek 			if (wr->w_active)
8655ad4a7c7SPawel Jakub Dawidek 				break;
8665ad4a7c7SPawel Jakub Dawidek 		}
8675ad4a7c7SPawel Jakub Dawidek 		if (wr == NULL)
8685ad4a7c7SPawel Jakub Dawidek 			break;
8695ad4a7c7SPawel Jakub Dawidek 		/* Not all threads suspended. */
8705ad4a7c7SPawel Jakub Dawidek 		msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
8715ad4a7c7SPawel Jakub Dawidek 		    "geli:suspend", 0);
8725ad4a7c7SPawel Jakub Dawidek 	}
8735ad4a7c7SPawel Jakub Dawidek 	/*
8745ad4a7c7SPawel Jakub Dawidek 	 * Clear sensitive data on suspend, they will be recovered on resume.
8755ad4a7c7SPawel Jakub Dawidek 	 */
87639b7ca45SAllan Jude 	explicit_bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
8771e09ff3dSPawel Jakub Dawidek 	g_eli_key_destroy(sc);
87839b7ca45SAllan Jude 	explicit_bzero(sc->sc_akey, sizeof(sc->sc_akey));
87939b7ca45SAllan Jude 	explicit_bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
88039b7ca45SAllan Jude 	explicit_bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
88139b7ca45SAllan Jude 	explicit_bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
8825ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
8830d2f5a4eSPawel Jakub Dawidek 	G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
8845ad4a7c7SPawel Jakub Dawidek }
8855ad4a7c7SPawel Jakub Dawidek 
8865ad4a7c7SPawel Jakub Dawidek static void
8875ad4a7c7SPawel Jakub Dawidek g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
8885ad4a7c7SPawel Jakub Dawidek {
8895ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
8905ad4a7c7SPawel Jakub Dawidek 	int *all, *nargs;
8915ad4a7c7SPawel Jakub Dawidek 
8925ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8935ad4a7c7SPawel Jakub Dawidek 
8945ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
8955ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
8965ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
8975ad4a7c7SPawel Jakub Dawidek 		return;
8985ad4a7c7SPawel Jakub Dawidek 	}
8995ad4a7c7SPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
9005ad4a7c7SPawel Jakub Dawidek 	if (all == NULL) {
9015ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
9025ad4a7c7SPawel Jakub Dawidek 		return;
9035ad4a7c7SPawel Jakub Dawidek 	}
9045ad4a7c7SPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
9055ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
9065ad4a7c7SPawel Jakub Dawidek 		return;
9075ad4a7c7SPawel Jakub Dawidek 	}
9085ad4a7c7SPawel Jakub Dawidek 
9095ad4a7c7SPawel Jakub Dawidek 	if (*all) {
9105ad4a7c7SPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
9115ad4a7c7SPawel Jakub Dawidek 
9125ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
9135ad4a7c7SPawel Jakub Dawidek 			sc = gp->softc;
9140d2f5a4eSPawel Jakub Dawidek 			if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
9150d2f5a4eSPawel Jakub Dawidek 				G_ELI_DEBUG(0,
9160d2f5a4eSPawel Jakub Dawidek 				    "Device %s is using one-time key, suspend not supported, skipping.",
9170d2f5a4eSPawel Jakub Dawidek 				    sc->sc_name);
9185ad4a7c7SPawel Jakub Dawidek 				continue;
9190d2f5a4eSPawel Jakub Dawidek 			}
9200d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9215ad4a7c7SPawel Jakub Dawidek 		}
9225ad4a7c7SPawel Jakub Dawidek 	} else {
9235ad4a7c7SPawel Jakub Dawidek 		const char *prov;
9245ad4a7c7SPawel Jakub Dawidek 		char param[16];
9255ad4a7c7SPawel Jakub Dawidek 		int i;
9265ad4a7c7SPawel Jakub Dawidek 
9275ad4a7c7SPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
9285ad4a7c7SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
9295ad4a7c7SPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
9305ad4a7c7SPawel Jakub Dawidek 			if (prov == NULL) {
9315ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
9325ad4a7c7SPawel Jakub Dawidek 				continue;
9335ad4a7c7SPawel Jakub Dawidek 			}
9345ad4a7c7SPawel Jakub Dawidek 
9355ad4a7c7SPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
9365ad4a7c7SPawel Jakub Dawidek 			if (sc == NULL) {
9375ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
9385ad4a7c7SPawel Jakub Dawidek 				continue;
9395ad4a7c7SPawel Jakub Dawidek 			}
9400d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9415ad4a7c7SPawel Jakub Dawidek 		}
9425ad4a7c7SPawel Jakub Dawidek 	}
9435ad4a7c7SPawel Jakub Dawidek }
9445ad4a7c7SPawel Jakub Dawidek 
9455ad4a7c7SPawel Jakub Dawidek static void
9465ad4a7c7SPawel Jakub Dawidek g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
9475ad4a7c7SPawel Jakub Dawidek {
9485ad4a7c7SPawel Jakub Dawidek 	struct g_eli_metadata md;
9495ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
9505ad4a7c7SPawel Jakub Dawidek 	struct g_provider *pp;
9515ad4a7c7SPawel Jakub Dawidek 	struct g_consumer *cp;
9525ad4a7c7SPawel Jakub Dawidek 	const char *name;
9535ad4a7c7SPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
9545ad4a7c7SPawel Jakub Dawidek 	int *nargs, keysize, error;
9555ad4a7c7SPawel Jakub Dawidek 	u_int nkey;
9565ad4a7c7SPawel Jakub Dawidek 
9575ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
9585ad4a7c7SPawel Jakub Dawidek 
9595ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
9605ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
9615ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
9625ad4a7c7SPawel Jakub Dawidek 		return;
9635ad4a7c7SPawel Jakub Dawidek 	}
9645ad4a7c7SPawel Jakub Dawidek 	if (*nargs != 1) {
9655ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
9665ad4a7c7SPawel Jakub Dawidek 		return;
9675ad4a7c7SPawel Jakub Dawidek 	}
9685ad4a7c7SPawel Jakub Dawidek 
9695ad4a7c7SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
9705ad4a7c7SPawel Jakub Dawidek 	if (name == NULL) {
9715ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
9725ad4a7c7SPawel Jakub Dawidek 		return;
9735ad4a7c7SPawel Jakub Dawidek 	}
97439b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
97539b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
97639b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
97739b7ca45SAllan Jude 		return;
97839b7ca45SAllan Jude 	}
9795ad4a7c7SPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
9805ad4a7c7SPawel Jakub Dawidek 	if (sc == NULL) {
9815ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
9825ad4a7c7SPawel Jakub Dawidek 		return;
9835ad4a7c7SPawel Jakub Dawidek 	}
9845ad4a7c7SPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
9855ad4a7c7SPawel Jakub Dawidek 	pp = cp->provider;
9865ad4a7c7SPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
9875ad4a7c7SPawel Jakub Dawidek 	if (error != 0) {
9885ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
9895ad4a7c7SPawel Jakub Dawidek 		    name, error);
9905ad4a7c7SPawel Jakub Dawidek 		return;
9915ad4a7c7SPawel Jakub Dawidek 	}
9925ad4a7c7SPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
99339b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9945ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
9955ad4a7c7SPawel Jakub Dawidek 		return;
9965ad4a7c7SPawel Jakub Dawidek 	}
9975ad4a7c7SPawel Jakub Dawidek 
998*31f7586dSMariusz Zaborski 	error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey);
99939b7ca45SAllan Jude 	explicit_bzero(key, keysize);
10005ad4a7c7SPawel Jakub Dawidek 	if (error == -1) {
100139b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
10025ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
10035ad4a7c7SPawel Jakub Dawidek 		return;
10045ad4a7c7SPawel Jakub Dawidek 	} else if (error > 0) {
100539b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
10065ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
10075ad4a7c7SPawel Jakub Dawidek 		    pp->name, error);
10085ad4a7c7SPawel Jakub Dawidek 		return;
10095ad4a7c7SPawel Jakub Dawidek 	}
10105ad4a7c7SPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
10115ad4a7c7SPawel Jakub Dawidek 
10125ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
10132f2d7830SPawel Jakub Dawidek 	if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
10142f2d7830SPawel Jakub Dawidek 		gctl_error(req, "Device %s is not suspended.", name);
10152f2d7830SPawel Jakub Dawidek 	else {
10165ad4a7c7SPawel Jakub Dawidek 		/* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
10175ad4a7c7SPawel Jakub Dawidek 		g_eli_mkey_propagate(sc, mkey);
10185ad4a7c7SPawel Jakub Dawidek 		sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
10192f2d7830SPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Resumed %s.", pp->name);
10202f2d7830SPawel Jakub Dawidek 		wakeup(sc);
10212f2d7830SPawel Jakub Dawidek 	}
10225ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
102339b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
102439b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
10255ad4a7c7SPawel Jakub Dawidek }
10265ad4a7c7SPawel Jakub Dawidek 
10275ad4a7c7SPawel Jakub Dawidek static int
1028c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc)
1029c58794deSPawel Jakub Dawidek {
1030c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
1031c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
103285059016SPawel Jakub Dawidek 	int error = 0;
1033c58794deSPawel Jakub Dawidek 
1034c58794deSPawel Jakub Dawidek 	g_topology_assert();
1035c58794deSPawel Jakub Dawidek 
1036c58794deSPawel Jakub Dawidek 	if (sc == NULL)
1037c58794deSPawel Jakub Dawidek 		return (ENOENT);
1038c58794deSPawel Jakub Dawidek 
1039c58794deSPawel Jakub Dawidek 	pp = LIST_FIRST(&sc->sc_geom->provider);
1040c58794deSPawel Jakub Dawidek 	g_error_provider(pp, ENXIO);
1041c58794deSPawel Jakub Dawidek 
1042c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
1043c58794deSPawel Jakub Dawidek 	pp = cp->provider;
1044c58794deSPawel Jakub Dawidek 
104585059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
104685059016SPawel Jakub Dawidek 		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
104785059016SPawel Jakub Dawidek 		    "provider: %s.", pp->name);
104885059016SPawel Jakub Dawidek 	} else {
104985059016SPawel Jakub Dawidek 		u_char *sector;
105085059016SPawel Jakub Dawidek 		u_int i;
105185059016SPawel Jakub Dawidek 		int err;
105285059016SPawel Jakub Dawidek 
1053c58794deSPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
1054c58794deSPawel Jakub Dawidek 		for (i = 0; i <= g_eli_overwrites; i++) {
1055c58794deSPawel Jakub Dawidek 			if (i == g_eli_overwrites)
1056c58794deSPawel Jakub Dawidek 				bzero(sector, pp->sectorsize);
1057c58794deSPawel Jakub Dawidek 			else
1058c58794deSPawel Jakub Dawidek 				arc4rand(sector, pp->sectorsize, 0);
105985059016SPawel Jakub Dawidek 			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
106085059016SPawel Jakub Dawidek 			    sector, pp->sectorsize);
1061c58794deSPawel Jakub Dawidek 			if (err != 0) {
1062c58794deSPawel Jakub Dawidek 				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
1063c58794deSPawel Jakub Dawidek 				    "(error=%d).", pp->name, err);
1064c58794deSPawel Jakub Dawidek 				if (error == 0)
1065c58794deSPawel Jakub Dawidek 					error = err;
1066c58794deSPawel Jakub Dawidek 			}
1067350e8df8SPawel Jakub Dawidek 			/*
1068350e8df8SPawel Jakub Dawidek 			 * Flush write cache so we don't overwrite data N times
1069350e8df8SPawel Jakub Dawidek 			 * in cache and only once on disk.
1070350e8df8SPawel Jakub Dawidek 			 */
1071350e8df8SPawel Jakub Dawidek 			(void)g_io_flush(cp);
1072c58794deSPawel Jakub Dawidek 		}
1073c58794deSPawel Jakub Dawidek 		free(sector, M_ELI);
107485059016SPawel Jakub Dawidek 	}
1075c58794deSPawel Jakub Dawidek 	if (error == 0)
1076c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
10775ad4a7c7SPawel Jakub Dawidek 	g_eli_destroy(sc, TRUE);
1078c58794deSPawel Jakub Dawidek 	return (error);
1079c58794deSPawel Jakub Dawidek }
1080c58794deSPawel Jakub Dawidek 
1081c58794deSPawel Jakub Dawidek static void
1082c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
1083c58794deSPawel Jakub Dawidek {
1084c58794deSPawel Jakub Dawidek 	int *all, *nargs;
1085c58794deSPawel Jakub Dawidek 	int error;
1086c58794deSPawel Jakub Dawidek 
1087c58794deSPawel Jakub Dawidek 	g_topology_assert();
1088c58794deSPawel Jakub Dawidek 
1089c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1090c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
1091c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
1092c58794deSPawel Jakub Dawidek 		return;
1093c58794deSPawel Jakub Dawidek 	}
1094c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
1095c58794deSPawel Jakub Dawidek 	if (all == NULL) {
1096c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
1097c58794deSPawel Jakub Dawidek 		return;
1098c58794deSPawel Jakub Dawidek 	}
1099c58794deSPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
1100c58794deSPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
1101c58794deSPawel Jakub Dawidek 		return;
1102c58794deSPawel Jakub Dawidek 	}
1103c58794deSPawel Jakub Dawidek 
1104c58794deSPawel Jakub Dawidek 	if (*all) {
1105c58794deSPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
1106c58794deSPawel Jakub Dawidek 
1107c58794deSPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
1108c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(gp->softc);
1109c58794deSPawel Jakub Dawidek 			if (error != 0)
1110c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1111c58794deSPawel Jakub Dawidek 		}
1112c58794deSPawel Jakub Dawidek 	} else {
1113c58794deSPawel Jakub Dawidek 		struct g_eli_softc *sc;
1114c58794deSPawel Jakub Dawidek 		const char *prov;
1115c58794deSPawel Jakub Dawidek 		char param[16];
1116c58794deSPawel Jakub Dawidek 		int i;
1117c58794deSPawel Jakub Dawidek 
1118c58794deSPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
11197d54b385SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
1120c58794deSPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
1121b5f30223SPawel Jakub Dawidek 			if (prov == NULL) {
1122b5f30223SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
1123b5f30223SPawel Jakub Dawidek 				continue;
1124b5f30223SPawel Jakub Dawidek 			}
1125c58794deSPawel Jakub Dawidek 
1126c58794deSPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
1127c58794deSPawel Jakub Dawidek 			if (sc == NULL) {
11287d54b385SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
1129c58794deSPawel Jakub Dawidek 				continue;
1130c58794deSPawel Jakub Dawidek 			}
1131c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(sc);
1132c58794deSPawel Jakub Dawidek 			if (error != 0)
1133c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1134c58794deSPawel Jakub Dawidek 		}
1135c58794deSPawel Jakub Dawidek 	}
1136c58794deSPawel Jakub Dawidek }
1137c58794deSPawel Jakub Dawidek 
1138c58794deSPawel Jakub Dawidek void
1139c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1140c58794deSPawel Jakub Dawidek {
1141c58794deSPawel Jakub Dawidek 	uint32_t *version;
1142c58794deSPawel Jakub Dawidek 
1143c58794deSPawel Jakub Dawidek 	g_topology_assert();
1144c58794deSPawel Jakub Dawidek 
1145c58794deSPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
1146c58794deSPawel Jakub Dawidek 	if (version == NULL) {
1147c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
1148c58794deSPawel Jakub Dawidek 		return;
1149c58794deSPawel Jakub Dawidek 	}
1150731adc86SPawel Jakub Dawidek 	while (*version != G_ELI_VERSION) {
1151731adc86SPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_06 &&
1152731adc86SPawel Jakub Dawidek 		    *version == G_ELI_VERSION_05) {
1153731adc86SPawel Jakub Dawidek 			/* Compatible. */
1154731adc86SPawel Jakub Dawidek 			break;
1155731adc86SPawel Jakub Dawidek 		}
1156457bbc4fSPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_07 &&
1157457bbc4fSPawel Jakub Dawidek 		    (*version == G_ELI_VERSION_05 ||
1158457bbc4fSPawel Jakub Dawidek 		     *version == G_ELI_VERSION_06)) {
1159457bbc4fSPawel Jakub Dawidek 			/* Compatible. */
1160457bbc4fSPawel Jakub Dawidek 			break;
1161457bbc4fSPawel Jakub Dawidek 		}
1162c58794deSPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
1163c58794deSPawel Jakub Dawidek 		return;
1164c58794deSPawel Jakub Dawidek 	}
1165c58794deSPawel Jakub Dawidek 
1166c58794deSPawel Jakub Dawidek 	if (strcmp(verb, "attach") == 0)
1167c58794deSPawel Jakub Dawidek 		g_eli_ctl_attach(req, mp);
1168c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
1169c58794deSPawel Jakub Dawidek 		g_eli_ctl_detach(req, mp);
1170c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "onetime") == 0)
1171c58794deSPawel Jakub Dawidek 		g_eli_ctl_onetime(req, mp);
11728abd1ad1SPawel Jakub Dawidek 	else if (strcmp(verb, "configure") == 0)
11738abd1ad1SPawel Jakub Dawidek 		g_eli_ctl_configure(req, mp);
1174c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "setkey") == 0)
1175c58794deSPawel Jakub Dawidek 		g_eli_ctl_setkey(req, mp);
1176c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "delkey") == 0)
1177c58794deSPawel Jakub Dawidek 		g_eli_ctl_delkey(req, mp);
11785ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "suspend") == 0)
11795ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_suspend(req, mp);
11805ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "resume") == 0)
11815ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_resume(req, mp);
1182c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "kill") == 0)
1183c58794deSPawel Jakub Dawidek 		g_eli_ctl_kill(req, mp);
1184c58794deSPawel Jakub Dawidek 	else
1185c58794deSPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
1186c58794deSPawel Jakub Dawidek }
1187