xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision 0db665bb987c9091d3a1cbe37b23ebe12ed159b9)
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];
62*0db665bbSXin LI 	int *nargs, *detach, *readonly, *dryrunp;
63*0db665bbSXin LI 	int keysize, error, nkey, dryrun, dummy;
6431f7586dSMariusz 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*0db665bbSXin LI 	/* "keyno" is optional for backward compatibility */
85*0db665bbSXin LI 	nkey = -1;
86*0db665bbSXin LI 	valp = gctl_get_param(req, "keyno", &dummy);
87*0db665bbSXin LI 	if (valp != NULL) {
8831f7586dSMariusz Zaborski 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
89*0db665bbSXin LI 		if (valp != NULL)
9031f7586dSMariusz Zaborski 			nkey = *valp;
91*0db665bbSXin LI 	}
9231f7586dSMariusz Zaborski 	if (nkey < -1 || nkey >= G_ELI_MAXMKEYS) {
9331f7586dSMariusz Zaborski 		gctl_error(req, "Invalid '%s' argument.", "keyno");
9431f7586dSMariusz Zaborski 		return;
9531f7586dSMariusz Zaborski 	}
9631f7586dSMariusz Zaborski 
9785059016SPawel Jakub Dawidek 	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
9885059016SPawel Jakub Dawidek 	if (readonly == NULL) {
9985059016SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "readonly");
10085059016SPawel Jakub Dawidek 		return;
10185059016SPawel Jakub Dawidek 	}
10285059016SPawel Jakub Dawidek 
103*0db665bbSXin LI 	/* "dryrun" is optional for backward compatibility */
104*0db665bbSXin LI 	dryrun = 0;
105*0db665bbSXin LI 	dryrunp = gctl_get_param(req, "dryrun", &dummy);
106*0db665bbSXin LI 	if (dryrunp != NULL) {
107*0db665bbSXin LI 		dryrunp = gctl_get_paraml(req, "dryrun", sizeof(*dryrunp));
108*0db665bbSXin LI 		if (dryrunp != NULL)
109*0db665bbSXin LI 			dryrun = *dryrunp;
1108f1c45c2SMariusz Zaborski 	}
1118f1c45c2SMariusz Zaborski 
11239b7ca45SAllan Jude 	if (*detach && *readonly) {
11339b7ca45SAllan Jude 		gctl_error(req, "Options -d and -r are mutually exclusive.");
11439b7ca45SAllan Jude 		return;
11539b7ca45SAllan Jude 	}
11639b7ca45SAllan Jude 
117c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
118c58794deSPawel Jakub Dawidek 	if (name == NULL) {
119c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
120c58794deSPawel Jakub Dawidek 		return;
121c58794deSPawel Jakub Dawidek 	}
122c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
123c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
124c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
125c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
126c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
127c58794deSPawel Jakub Dawidek 		return;
128c58794deSPawel Jakub Dawidek 	}
129c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
130c58794deSPawel Jakub Dawidek 	if (error != 0) {
131c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
132c58794deSPawel Jakub Dawidek 		    name, error);
133c58794deSPawel Jakub Dawidek 		return;
134c58794deSPawel Jakub Dawidek 	}
135c58794deSPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
13639b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
137c58794deSPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
138c58794deSPawel Jakub Dawidek 		return;
139c58794deSPawel Jakub Dawidek 	}
140c58794deSPawel Jakub Dawidek 
141c58794deSPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
142c58794deSPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
14339b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
144c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
145c58794deSPawel Jakub Dawidek 		return;
146c58794deSPawel Jakub Dawidek 	}
147c58794deSPawel Jakub Dawidek 
14831f7586dSMariusz Zaborski 	if (nkey == -1)
14931f7586dSMariusz Zaborski 		error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey);
15031f7586dSMariusz Zaborski 	else
15131f7586dSMariusz Zaborski 		error = g_eli_mkey_decrypt(&md, key, mkey, nkey);
15239b7ca45SAllan Jude 	explicit_bzero(key, keysize);
153c58794deSPawel Jakub Dawidek 	if (error == -1) {
15439b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
155c58794deSPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
156c58794deSPawel Jakub Dawidek 		return;
157c58794deSPawel Jakub Dawidek 	} else if (error > 0) {
15839b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
159c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
160c58794deSPawel Jakub Dawidek 		    pp->name, error);
161c58794deSPawel Jakub Dawidek 		return;
162c58794deSPawel Jakub Dawidek 	}
163c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
164c58794deSPawel Jakub Dawidek 
165c58794deSPawel Jakub Dawidek 	if (*detach)
166c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
16785059016SPawel Jakub Dawidek 	if (*readonly)
16885059016SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_RO;
169*0db665bbSXin LI 	if (!dryrun)
170c58794deSPawel Jakub Dawidek 		g_eli_create(req, mp, pp, &md, mkey, nkey);
17139b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
17239b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
173c58794deSPawel Jakub Dawidek }
174c58794deSPawel Jakub Dawidek 
175c58794deSPawel Jakub Dawidek static struct g_eli_softc *
176c58794deSPawel Jakub Dawidek g_eli_find_device(struct g_class *mp, const char *prov)
177c58794deSPawel Jakub Dawidek {
178c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
179c58794deSPawel Jakub Dawidek 	struct g_geom *gp;
180c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
181c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
182c58794deSPawel Jakub Dawidek 
183c58794deSPawel Jakub Dawidek 	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
184c58794deSPawel Jakub Dawidek 		prov += strlen("/dev/");
185c58794deSPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
186c58794deSPawel Jakub Dawidek 		sc = gp->softc;
187c58794deSPawel Jakub Dawidek 		if (sc == NULL)
188c58794deSPawel Jakub Dawidek 			continue;
189c58794deSPawel Jakub Dawidek 		pp = LIST_FIRST(&gp->provider);
190c58794deSPawel Jakub Dawidek 		if (pp != NULL && strcmp(pp->name, prov) == 0)
191c58794deSPawel Jakub Dawidek 			return (sc);
192c58794deSPawel Jakub Dawidek 		cp = LIST_FIRST(&gp->consumer);
193c58794deSPawel Jakub Dawidek 		if (cp != NULL && cp->provider != NULL &&
194c58794deSPawel Jakub Dawidek 		    strcmp(cp->provider->name, prov) == 0) {
195c58794deSPawel Jakub Dawidek 			return (sc);
196c58794deSPawel Jakub Dawidek 		}
197c58794deSPawel Jakub Dawidek 	}
198c58794deSPawel Jakub Dawidek 	return (NULL);
199c58794deSPawel Jakub Dawidek }
200c58794deSPawel Jakub Dawidek 
201c58794deSPawel Jakub Dawidek static void
202c58794deSPawel Jakub Dawidek g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
203c58794deSPawel Jakub Dawidek {
204c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
205c58794deSPawel Jakub Dawidek 	int *force, *last, *nargs, error;
206c58794deSPawel Jakub Dawidek 	const char *prov;
207c58794deSPawel Jakub Dawidek 	char param[16];
2087d54b385SPawel Jakub Dawidek 	int i;
209c58794deSPawel Jakub Dawidek 
210c58794deSPawel Jakub Dawidek 	g_topology_assert();
211c58794deSPawel Jakub Dawidek 
212c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
213c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
214c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
215c58794deSPawel Jakub Dawidek 		return;
216c58794deSPawel Jakub Dawidek 	}
217c58794deSPawel Jakub Dawidek 	if (*nargs <= 0) {
218c58794deSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
219c58794deSPawel Jakub Dawidek 		return;
220c58794deSPawel Jakub Dawidek 	}
221c58794deSPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
222c58794deSPawel Jakub Dawidek 	if (force == NULL) {
223c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "force");
224c58794deSPawel Jakub Dawidek 		return;
225c58794deSPawel Jakub Dawidek 	}
226c58794deSPawel Jakub Dawidek 	last = gctl_get_paraml(req, "last", sizeof(*last));
227c58794deSPawel Jakub Dawidek 	if (last == NULL) {
228c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "last");
229c58794deSPawel Jakub Dawidek 		return;
230c58794deSPawel Jakub Dawidek 	}
231c58794deSPawel Jakub Dawidek 
2327d54b385SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
2337d54b385SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
234c58794deSPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
235c58794deSPawel Jakub Dawidek 		if (prov == NULL) {
2367d54b385SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
237c58794deSPawel Jakub Dawidek 			return;
238c58794deSPawel Jakub Dawidek 		}
239c58794deSPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
240c58794deSPawel Jakub Dawidek 		if (sc == NULL) {
241c58794deSPawel Jakub Dawidek 			gctl_error(req, "No such device: %s.", prov);
242c58794deSPawel Jakub Dawidek 			return;
243c58794deSPawel Jakub Dawidek 		}
244c58794deSPawel Jakub Dawidek 		if (*last) {
245c58794deSPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
246c58794deSPawel Jakub Dawidek 			sc->sc_geom->access = g_eli_access;
247c58794deSPawel Jakub Dawidek 		} else {
2485ad4a7c7SPawel Jakub Dawidek 			error = g_eli_destroy(sc, *force ? TRUE : FALSE);
249c58794deSPawel Jakub Dawidek 			if (error != 0) {
250c58794deSPawel Jakub Dawidek 				gctl_error(req,
251c58794deSPawel Jakub Dawidek 				    "Cannot destroy device %s (error=%d).",
252c58794deSPawel Jakub Dawidek 				    sc->sc_name, error);
253c58794deSPawel Jakub Dawidek 				return;
254c58794deSPawel Jakub Dawidek 			}
255c58794deSPawel Jakub Dawidek 		}
256c58794deSPawel Jakub Dawidek 	}
257c58794deSPawel Jakub Dawidek }
258c58794deSPawel Jakub Dawidek 
259c58794deSPawel Jakub Dawidek static void
260c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
261c58794deSPawel Jakub Dawidek {
262c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
263c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
264c58794deSPawel Jakub Dawidek 	const char *name;
265c58794deSPawel Jakub Dawidek 	intmax_t *keylen, *sectorsize;
266c58794deSPawel Jakub Dawidek 	u_char mkey[G_ELI_DATAIVKEYLEN];
26746e34470SPawel Jakub Dawidek 	int *nargs, *detach, *notrim;
268c58794deSPawel Jakub Dawidek 
269c58794deSPawel Jakub Dawidek 	g_topology_assert();
270c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
271c58794deSPawel Jakub Dawidek 
272c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
273c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
274c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
275c58794deSPawel Jakub Dawidek 		return;
276c58794deSPawel Jakub Dawidek 	}
277c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
278c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
279c58794deSPawel Jakub Dawidek 		return;
280c58794deSPawel Jakub Dawidek 	}
281c58794deSPawel Jakub Dawidek 
282c58794deSPawel Jakub Dawidek 	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
283c58794deSPawel Jakub Dawidek 	md.md_version = G_ELI_VERSION;
284c58794deSPawel Jakub Dawidek 	md.md_flags |= G_ELI_FLAG_ONETIME;
28546e34470SPawel Jakub Dawidek 
28646e34470SPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
28746e34470SPawel Jakub Dawidek 	if (detach != NULL && *detach)
288c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
28946e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
29046e34470SPawel Jakub Dawidek 	if (notrim != NULL && *notrim)
29146e34470SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_NODELETE;
292c58794deSPawel Jakub Dawidek 
293c84efdcaSPawel Jakub Dawidek 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
294eaa3b919SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "aalgo");
295c58794deSPawel Jakub Dawidek 	if (name == NULL) {
296eaa3b919SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "aalgo");
297c58794deSPawel Jakub Dawidek 		return;
298c58794deSPawel Jakub Dawidek 	}
299a478ea74SPawel Jakub Dawidek 	if (*name != '\0') {
300eaa3b919SPawel Jakub Dawidek 		md.md_aalgo = g_eli_str2aalgo(name);
301c84efdcaSPawel Jakub Dawidek 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
302c84efdcaSPawel Jakub Dawidek 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
303eaa3b919SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_AUTH;
304c84efdcaSPawel Jakub Dawidek 		} else {
305c84efdcaSPawel Jakub Dawidek 			/*
306c84efdcaSPawel Jakub Dawidek 			 * For backward compatibility, check if the -a option
307c84efdcaSPawel Jakub Dawidek 			 * was used to provide encryption algorithm.
308c84efdcaSPawel Jakub Dawidek 			 */
309c84efdcaSPawel Jakub Dawidek 			md.md_ealgo = g_eli_str2ealgo(name);
310c84efdcaSPawel Jakub Dawidek 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
311c84efdcaSPawel Jakub Dawidek 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
312c84efdcaSPawel Jakub Dawidek 				gctl_error(req,
313c84efdcaSPawel Jakub Dawidek 				    "Invalid authentication algorithm.");
314c84efdcaSPawel Jakub Dawidek 				return;
315c84efdcaSPawel Jakub Dawidek 			} else {
316c84efdcaSPawel Jakub Dawidek 				gctl_error(req, "warning: The -e option, not "
317c84efdcaSPawel Jakub Dawidek 				    "the -a option is now used to specify "
318c84efdcaSPawel Jakub Dawidek 				    "encryption algorithm to use.");
319c84efdcaSPawel Jakub Dawidek 			}
320c84efdcaSPawel Jakub Dawidek 		}
321eaa3b919SPawel Jakub Dawidek 	}
322eaa3b919SPawel Jakub Dawidek 
323c84efdcaSPawel Jakub Dawidek 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
324c84efdcaSPawel Jakub Dawidek 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
325eaa3b919SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, "ealgo");
326eaa3b919SPawel Jakub Dawidek 		if (name == NULL) {
327eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "ealgo");
328eaa3b919SPawel Jakub Dawidek 			return;
329eaa3b919SPawel Jakub Dawidek 		}
330eaa3b919SPawel Jakub Dawidek 		md.md_ealgo = g_eli_str2ealgo(name);
331eaa3b919SPawel Jakub Dawidek 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
332eaa3b919SPawel Jakub Dawidek 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
333eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "Invalid encryption algorithm.");
334c58794deSPawel Jakub Dawidek 			return;
335c58794deSPawel Jakub Dawidek 		}
336c84efdcaSPawel Jakub Dawidek 	}
337c58794deSPawel Jakub Dawidek 
338c58794deSPawel Jakub Dawidek 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
339c58794deSPawel Jakub Dawidek 	if (keylen == NULL) {
340c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keylen");
341c58794deSPawel Jakub Dawidek 		return;
342c58794deSPawel Jakub Dawidek 	}
343eaa3b919SPawel Jakub Dawidek 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
344c58794deSPawel Jakub Dawidek 	if (md.md_keylen == 0) {
345c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keylen");
346c58794deSPawel Jakub Dawidek 		return;
347c58794deSPawel Jakub Dawidek 	}
348c58794deSPawel Jakub Dawidek 
349c58794deSPawel Jakub Dawidek 	/* Not important here. */
350c58794deSPawel Jakub Dawidek 	md.md_provsize = 0;
351c58794deSPawel Jakub Dawidek 	/* Not important here. */
352c58794deSPawel Jakub Dawidek 	bzero(md.md_salt, sizeof(md.md_salt));
353c58794deSPawel Jakub Dawidek 
354c58794deSPawel Jakub Dawidek 	md.md_keys = 0x01;
355c58794deSPawel Jakub Dawidek 	arc4rand(mkey, sizeof(mkey), 0);
356c58794deSPawel Jakub Dawidek 
357c58794deSPawel Jakub Dawidek 	/* Not important here. */
358c58794deSPawel Jakub Dawidek 	bzero(md.md_hash, sizeof(md.md_hash));
359c58794deSPawel Jakub Dawidek 
360c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
361c58794deSPawel Jakub Dawidek 	if (name == NULL) {
362c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
363c58794deSPawel Jakub Dawidek 		return;
364c58794deSPawel Jakub Dawidek 	}
365c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
366c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
367c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
368c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
369c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
370c58794deSPawel Jakub Dawidek 		return;
371c58794deSPawel Jakub Dawidek 	}
372c58794deSPawel Jakub Dawidek 
373c58794deSPawel Jakub Dawidek 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
374c58794deSPawel Jakub Dawidek 	if (sectorsize == NULL) {
375c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "sectorsize");
376c58794deSPawel Jakub Dawidek 		return;
377c58794deSPawel Jakub Dawidek 	}
378c58794deSPawel Jakub Dawidek 	if (*sectorsize == 0)
379c58794deSPawel Jakub Dawidek 		md.md_sectorsize = pp->sectorsize;
380c58794deSPawel Jakub Dawidek 	else {
381c58794deSPawel Jakub Dawidek 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
382c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid sector size.");
383c58794deSPawel Jakub Dawidek 			return;
384c58794deSPawel Jakub Dawidek 		}
38597a669a3SPawel Jakub Dawidek 		if (*sectorsize > PAGE_SIZE) {
38697a669a3SPawel Jakub Dawidek 			gctl_error(req, "warning: Using sectorsize bigger than "
38797a669a3SPawel Jakub Dawidek 			    "the page size!");
38897a669a3SPawel Jakub Dawidek 		}
389c58794deSPawel Jakub Dawidek 		md.md_sectorsize = *sectorsize;
390c58794deSPawel Jakub Dawidek 	}
391c58794deSPawel Jakub Dawidek 
392c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, -1);
39339b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
39439b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
395c58794deSPawel Jakub Dawidek }
396c58794deSPawel Jakub Dawidek 
397c58794deSPawel Jakub Dawidek static void
3988abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
3998abd1ad1SPawel Jakub Dawidek {
4008abd1ad1SPawel Jakub Dawidek 	struct g_eli_softc *sc;
4018abd1ad1SPawel Jakub Dawidek 	struct g_eli_metadata md;
4028abd1ad1SPawel Jakub Dawidek 	struct g_provider *pp;
4038abd1ad1SPawel Jakub Dawidek 	struct g_consumer *cp;
4048abd1ad1SPawel Jakub Dawidek 	char param[16];
4058abd1ad1SPawel Jakub Dawidek 	const char *prov;
4068abd1ad1SPawel Jakub Dawidek 	u_char *sector;
407d8736625SAllan Jude 	int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot;
4083453dc72SMariusz Zaborski 	int *displaypass, *nodisplaypass;
40946e34470SPawel Jakub Dawidek 	int zero, error, changed;
4108abd1ad1SPawel Jakub Dawidek 	u_int i;
4118abd1ad1SPawel Jakub Dawidek 
4128abd1ad1SPawel Jakub Dawidek 	g_topology_assert();
4138abd1ad1SPawel Jakub Dawidek 
41446e34470SPawel Jakub Dawidek 	changed = 0;
41546e34470SPawel Jakub Dawidek 	zero = 0;
41646e34470SPawel Jakub Dawidek 
4178abd1ad1SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
4188abd1ad1SPawel Jakub Dawidek 	if (nargs == NULL) {
4198abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
4208abd1ad1SPawel Jakub Dawidek 		return;
4218abd1ad1SPawel Jakub Dawidek 	}
4228abd1ad1SPawel Jakub Dawidek 	if (*nargs <= 0) {
4238abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
4248abd1ad1SPawel Jakub Dawidek 		return;
4258abd1ad1SPawel Jakub Dawidek 	}
4268abd1ad1SPawel Jakub Dawidek 
4278abd1ad1SPawel Jakub Dawidek 	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
42846e34470SPawel Jakub Dawidek 	if (boot == NULL)
42946e34470SPawel Jakub Dawidek 		boot = &zero;
4308abd1ad1SPawel Jakub Dawidek 	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
43146e34470SPawel Jakub Dawidek 	if (noboot == NULL)
43246e34470SPawel Jakub Dawidek 		noboot = &zero;
4338abd1ad1SPawel Jakub Dawidek 	if (*boot && *noboot) {
4348abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Options -b and -B are mutually exclusive.");
4358abd1ad1SPawel Jakub Dawidek 		return;
4368abd1ad1SPawel Jakub Dawidek 	}
43746e34470SPawel Jakub Dawidek 	if (*boot || *noboot)
43846e34470SPawel Jakub Dawidek 		changed = 1;
43946e34470SPawel Jakub Dawidek 
44046e34470SPawel Jakub Dawidek 	trim = gctl_get_paraml(req, "trim", sizeof(*trim));
44146e34470SPawel Jakub Dawidek 	if (trim == NULL)
44246e34470SPawel Jakub Dawidek 		trim = &zero;
44346e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
44446e34470SPawel Jakub Dawidek 	if (notrim == NULL)
44546e34470SPawel Jakub Dawidek 		notrim = &zero;
44646e34470SPawel Jakub Dawidek 	if (*trim && *notrim) {
44746e34470SPawel Jakub Dawidek 		gctl_error(req, "Options -t and -T are mutually exclusive.");
44846e34470SPawel Jakub Dawidek 		return;
44946e34470SPawel Jakub Dawidek 	}
45046e34470SPawel Jakub Dawidek 	if (*trim || *notrim)
45146e34470SPawel Jakub Dawidek 		changed = 1;
45246e34470SPawel Jakub Dawidek 
453d8736625SAllan Jude 	geliboot = gctl_get_paraml(req, "geliboot", sizeof(*geliboot));
454d8736625SAllan Jude 	if (geliboot == NULL)
455d8736625SAllan Jude 		geliboot = &zero;
456d8736625SAllan Jude 	nogeliboot = gctl_get_paraml(req, "nogeliboot", sizeof(*nogeliboot));
457d8736625SAllan Jude 	if (nogeliboot == NULL)
458d8736625SAllan Jude 		nogeliboot = &zero;
459d8736625SAllan Jude 	if (*geliboot && *nogeliboot) {
460d8736625SAllan Jude 		gctl_error(req, "Options -g and -G are mutually exclusive.");
461d8736625SAllan Jude 		return;
462d8736625SAllan Jude 	}
463d8736625SAllan Jude 	if (*geliboot || *nogeliboot)
464d8736625SAllan Jude 		changed = 1;
465d8736625SAllan Jude 
4663453dc72SMariusz Zaborski 	displaypass = gctl_get_paraml(req, "displaypass", sizeof(*displaypass));
4673453dc72SMariusz Zaborski 	if (displaypass == NULL)
4683453dc72SMariusz Zaborski 		displaypass = &zero;
4693453dc72SMariusz Zaborski 	nodisplaypass = gctl_get_paraml(req, "nodisplaypass", sizeof(*nodisplaypass));
4703453dc72SMariusz Zaborski 	if (nodisplaypass == NULL)
4713453dc72SMariusz Zaborski 		nodisplaypass = &zero;
4723453dc72SMariusz Zaborski 	if (*displaypass && *nodisplaypass) {
4733453dc72SMariusz Zaborski 		gctl_error(req, "Options -d and -D are mutually exclusive.");
4743453dc72SMariusz Zaborski 		return;
4753453dc72SMariusz Zaborski 	}
4763453dc72SMariusz Zaborski 	if (*displaypass || *nodisplaypass)
4773453dc72SMariusz Zaborski 		changed = 1;
4783453dc72SMariusz Zaborski 
47946e34470SPawel Jakub Dawidek 	if (!changed) {
4808abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No option given.");
4818abd1ad1SPawel Jakub Dawidek 		return;
4828abd1ad1SPawel Jakub Dawidek 	}
4838abd1ad1SPawel Jakub Dawidek 
4848abd1ad1SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
4858abd1ad1SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
4868abd1ad1SPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
4878abd1ad1SPawel Jakub Dawidek 		if (prov == NULL) {
4888abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
4898abd1ad1SPawel Jakub Dawidek 			return;
4908abd1ad1SPawel Jakub Dawidek 		}
4918abd1ad1SPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
4928abd1ad1SPawel Jakub Dawidek 		if (sc == NULL) {
4938abd1ad1SPawel Jakub Dawidek 			/*
4948abd1ad1SPawel Jakub Dawidek 			 * We ignore not attached providers, userland part will
4958abd1ad1SPawel Jakub Dawidek 			 * take care of them.
4968abd1ad1SPawel Jakub Dawidek 			 */
4978abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "Skipping configuration of not attached "
4988abd1ad1SPawel Jakub Dawidek 			    "provider %s.", prov);
4998abd1ad1SPawel Jakub Dawidek 			continue;
5008abd1ad1SPawel Jakub Dawidek 		}
5018abd1ad1SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_RO) {
5028abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "Cannot change configuration of "
5038abd1ad1SPawel Jakub Dawidek 			    "read-only provider %s.", prov);
5048abd1ad1SPawel Jakub Dawidek 			continue;
5058abd1ad1SPawel Jakub Dawidek 		}
50646e34470SPawel Jakub Dawidek 
50746e34470SPawel Jakub Dawidek 		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
50846e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
50946e34470SPawel Jakub Dawidek 			    prov);
51046e34470SPawel Jakub Dawidek 			continue;
51146e34470SPawel Jakub Dawidek 		} else if (*noboot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
51246e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
51346e34470SPawel Jakub Dawidek 			    prov);
51446e34470SPawel Jakub Dawidek 			continue;
51546e34470SPawel Jakub Dawidek 		}
51646e34470SPawel Jakub Dawidek 
51746e34470SPawel Jakub Dawidek 		if (*notrim && (sc->sc_flags & G_ELI_FLAG_NODELETE)) {
51846e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag already configured for %s.",
51946e34470SPawel Jakub Dawidek 			    prov);
52046e34470SPawel Jakub Dawidek 			continue;
52146e34470SPawel Jakub Dawidek 		} else if (*trim && !(sc->sc_flags & G_ELI_FLAG_NODELETE)) {
52246e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag not configured for %s.",
52346e34470SPawel Jakub Dawidek 			    prov);
52446e34470SPawel Jakub Dawidek 			continue;
52546e34470SPawel Jakub Dawidek 		}
52646e34470SPawel Jakub Dawidek 
527d8736625SAllan Jude 		if (*geliboot && (sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
528d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag already configured for %s.",
529d8736625SAllan Jude 			    prov);
530d8736625SAllan Jude 			continue;
531d8736625SAllan Jude 		} else if (*nogeliboot && !(sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
532d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag not configured for %s.",
533d8736625SAllan Jude 			    prov);
534d8736625SAllan Jude 			continue;
535d8736625SAllan Jude 		}
536d8736625SAllan Jude 
5373453dc72SMariusz Zaborski 		if (*displaypass && (sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5383453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag already configured for %s.",
5393453dc72SMariusz Zaborski 			    prov);
5403453dc72SMariusz Zaborski 			continue;
5413453dc72SMariusz Zaborski 		} else if (*nodisplaypass &&
5423453dc72SMariusz Zaborski 		    !(sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5433453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag not configured for %s.",
5443453dc72SMariusz Zaborski 			    prov);
5453453dc72SMariusz Zaborski 			continue;
5463453dc72SMariusz Zaborski 		}
5473453dc72SMariusz Zaborski 
54846e34470SPawel Jakub Dawidek 		if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
54946e34470SPawel Jakub Dawidek 			/*
55046e34470SPawel Jakub Dawidek 			 * ONETIME providers don't write metadata to
55146e34470SPawel Jakub Dawidek 			 * disk, so don't try reading it.  This means
55246e34470SPawel Jakub Dawidek 			 * we're bit-flipping uninitialized memory in md
55346e34470SPawel Jakub Dawidek 			 * below, but that's OK; we don't do anything
55446e34470SPawel Jakub Dawidek 			 * with it later.
55546e34470SPawel Jakub Dawidek 			 */
5568abd1ad1SPawel Jakub Dawidek 			cp = LIST_FIRST(&sc->sc_geom->consumer);
5578abd1ad1SPawel Jakub Dawidek 			pp = cp->provider;
5588abd1ad1SPawel Jakub Dawidek 			error = g_eli_read_metadata(mp, pp, &md);
5598abd1ad1SPawel Jakub Dawidek 			if (error != 0) {
5608abd1ad1SPawel Jakub Dawidek 			    gctl_error(req,
5618abd1ad1SPawel Jakub Dawidek 				"Cannot read metadata from %s (error=%d).",
5628abd1ad1SPawel Jakub Dawidek 				prov, error);
5638abd1ad1SPawel Jakub Dawidek 			    continue;
5648abd1ad1SPawel Jakub Dawidek 			}
56546e34470SPawel Jakub Dawidek 		}
5668abd1ad1SPawel Jakub Dawidek 
5678abd1ad1SPawel Jakub Dawidek 		if (*boot) {
5688abd1ad1SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_BOOT;
5698abd1ad1SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_BOOT;
57046e34470SPawel Jakub Dawidek 		} else if (*noboot) {
5718abd1ad1SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_BOOT;
5728abd1ad1SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
5738abd1ad1SPawel Jakub Dawidek 		}
5748abd1ad1SPawel Jakub Dawidek 
57546e34470SPawel Jakub Dawidek 		if (*notrim) {
57646e34470SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_NODELETE;
57746e34470SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_NODELETE;
57846e34470SPawel Jakub Dawidek 		} else if (*trim) {
57946e34470SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_NODELETE;
58046e34470SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_NODELETE;
58146e34470SPawel Jakub Dawidek 		}
58246e34470SPawel Jakub Dawidek 
583d8736625SAllan Jude 		if (*geliboot) {
584d8736625SAllan Jude 			md.md_flags |= G_ELI_FLAG_GELIBOOT;
585d8736625SAllan Jude 			sc->sc_flags |= G_ELI_FLAG_GELIBOOT;
586d8736625SAllan Jude 		} else if (*nogeliboot) {
587d8736625SAllan Jude 			md.md_flags &= ~G_ELI_FLAG_GELIBOOT;
588d8736625SAllan Jude 			sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT;
589d8736625SAllan Jude 		}
590d8736625SAllan Jude 
5913453dc72SMariusz Zaborski 		if (*displaypass) {
5923453dc72SMariusz Zaborski 			md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5933453dc72SMariusz Zaborski 			sc->sc_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5943453dc72SMariusz Zaborski 		} else if (*nodisplaypass) {
5953453dc72SMariusz Zaborski 			md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5963453dc72SMariusz Zaborski 			sc->sc_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5973453dc72SMariusz Zaborski 		}
5983453dc72SMariusz Zaborski 
59946e34470SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
60046e34470SPawel Jakub Dawidek 			/* There's no metadata on disk so we are done here. */
60146e34470SPawel Jakub Dawidek 			continue;
60246e34470SPawel Jakub Dawidek 		}
60346e34470SPawel Jakub Dawidek 
6048abd1ad1SPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
6058abd1ad1SPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
6068abd1ad1SPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
6078abd1ad1SPawel Jakub Dawidek 		    pp->sectorsize);
6088abd1ad1SPawel Jakub Dawidek 		if (error != 0) {
6098abd1ad1SPawel Jakub Dawidek 			gctl_error(req,
6108abd1ad1SPawel Jakub Dawidek 			    "Cannot store metadata on %s (error=%d).",
6118abd1ad1SPawel Jakub Dawidek 			    prov, error);
6128abd1ad1SPawel Jakub Dawidek 		}
61339b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
61439b7ca45SAllan Jude 		explicit_bzero(sector, pp->sectorsize);
6158abd1ad1SPawel Jakub Dawidek 		free(sector, M_ELI);
6168abd1ad1SPawel Jakub Dawidek 	}
6178abd1ad1SPawel Jakub Dawidek }
6188abd1ad1SPawel Jakub Dawidek 
6198abd1ad1SPawel Jakub Dawidek static void
620c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
621c58794deSPawel Jakub Dawidek {
622c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
623c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
624c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
625c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
626c58794deSPawel Jakub Dawidek 	const char *name;
627c58794deSPawel Jakub Dawidek 	u_char *key, *mkeydst, *sector;
628c58794deSPawel Jakub Dawidek 	intmax_t *valp;
6297a5c26fcSPawel Jakub Dawidek 	int keysize, nkey, error;
630c58794deSPawel Jakub Dawidek 
631c58794deSPawel Jakub Dawidek 	g_topology_assert();
632c58794deSPawel Jakub Dawidek 
633c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
634c58794deSPawel Jakub Dawidek 	if (name == NULL) {
635c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
636c58794deSPawel Jakub Dawidek 		return;
637c58794deSPawel Jakub Dawidek 	}
63839b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
63939b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
64039b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
64139b7ca45SAllan Jude 		return;
64239b7ca45SAllan Jude 	}
643c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
644c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
645c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
646c58794deSPawel Jakub Dawidek 		return;
647c58794deSPawel Jakub Dawidek 	}
64885059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
64985059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot change keys for read-only provider.");
65085059016SPawel Jakub Dawidek 		return;
65185059016SPawel Jakub Dawidek 	}
652c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
653c58794deSPawel Jakub Dawidek 	pp = cp->provider;
654c58794deSPawel Jakub Dawidek 
655c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
656c58794deSPawel Jakub Dawidek 	if (error != 0) {
657c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
658c58794deSPawel Jakub Dawidek 		    name, error);
659c58794deSPawel Jakub Dawidek 		return;
660c58794deSPawel Jakub Dawidek 	}
661c58794deSPawel Jakub Dawidek 
662c58794deSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
663c58794deSPawel Jakub Dawidek 	if (valp == NULL) {
664c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keyno");
665c58794deSPawel Jakub Dawidek 		return;
666c58794deSPawel Jakub Dawidek 	}
667c58794deSPawel Jakub Dawidek 	if (*valp != -1)
668c58794deSPawel Jakub Dawidek 		nkey = *valp;
669c58794deSPawel Jakub Dawidek 	else
670c58794deSPawel Jakub Dawidek 		nkey = sc->sc_nkey;
671c58794deSPawel Jakub Dawidek 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
672c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keyno");
673c58794deSPawel Jakub Dawidek 		return;
674c58794deSPawel Jakub Dawidek 	}
675c58794deSPawel Jakub Dawidek 
6767a5c26fcSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
6777a5c26fcSPawel Jakub Dawidek 	if (valp == NULL) {
6787a5c26fcSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "iterations");
6797a5c26fcSPawel Jakub Dawidek 		return;
6807a5c26fcSPawel Jakub Dawidek 	}
6817a5c26fcSPawel Jakub Dawidek 	/* Check if iterations number should and can be changed. */
682d8880fd4SAlexander Motin 	if (*valp != -1 && md.md_iterations == -1) {
683d8880fd4SAlexander Motin 		md.md_iterations = *valp;
684d8880fd4SAlexander Motin 	} else if (*valp != -1 && *valp != md.md_iterations) {
6857a5c26fcSPawel Jakub Dawidek 		if (bitcount32(md.md_keys) != 1) {
6867a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "To be able to use '-i' option, only "
6877a5c26fcSPawel Jakub Dawidek 			    "one key can be defined.");
6887a5c26fcSPawel Jakub Dawidek 			return;
6897a5c26fcSPawel Jakub Dawidek 		}
6907a5c26fcSPawel Jakub Dawidek 		if (md.md_keys != (1 << nkey)) {
6917a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "Only already defined key can be "
6927a5c26fcSPawel Jakub Dawidek 			    "changed when '-i' option is used.");
6937a5c26fcSPawel Jakub Dawidek 			return;
6947a5c26fcSPawel Jakub Dawidek 		}
6957a5c26fcSPawel Jakub Dawidek 		md.md_iterations = *valp;
6967a5c26fcSPawel Jakub Dawidek 	}
6977a5c26fcSPawel Jakub Dawidek 
698c58794deSPawel Jakub Dawidek 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
699c58794deSPawel Jakub Dawidek 	md.md_keys |= (1 << nkey);
700c58794deSPawel Jakub Dawidek 
701eaa3b919SPawel Jakub Dawidek 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
702c58794deSPawel Jakub Dawidek 
703c58794deSPawel Jakub Dawidek 	/* Encrypt Master Key with the new key. */
704eaa3b919SPawel Jakub Dawidek 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
70539b7ca45SAllan Jude 	explicit_bzero(key, keysize);
706c58794deSPawel Jakub Dawidek 	if (error != 0) {
70739b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
708c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
709c58794deSPawel Jakub Dawidek 		return;
710c58794deSPawel Jakub Dawidek 	}
711c58794deSPawel Jakub Dawidek 
712c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
713c58794deSPawel Jakub Dawidek 	/* Store metadata with fresh key. */
714c58794deSPawel Jakub Dawidek 	eli_metadata_encode(&md, sector);
71539b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
716c58794deSPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
717c58794deSPawel Jakub Dawidek 	    pp->sectorsize);
71839b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
719c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
720c58794deSPawel Jakub Dawidek 	if (error != 0) {
721c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
722c58794deSPawel Jakub Dawidek 		    pp->name, error);
723c58794deSPawel Jakub Dawidek 		return;
724c58794deSPawel Jakub Dawidek 	}
725c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
726c58794deSPawel Jakub Dawidek }
727c58794deSPawel Jakub Dawidek 
728c58794deSPawel Jakub Dawidek static void
729c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
730c58794deSPawel Jakub Dawidek {
731c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
732c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
733c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
734c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
735c58794deSPawel Jakub Dawidek 	const char *name;
736c58794deSPawel Jakub Dawidek 	u_char *mkeydst, *sector;
737c58794deSPawel Jakub Dawidek 	intmax_t *valp;
738c58794deSPawel Jakub Dawidek 	size_t keysize;
739c58794deSPawel Jakub Dawidek 	int error, nkey, *all, *force;
740c58794deSPawel Jakub Dawidek 	u_int i;
741c58794deSPawel Jakub Dawidek 
742c58794deSPawel Jakub Dawidek 	g_topology_assert();
743c58794deSPawel Jakub Dawidek 
744c58794deSPawel Jakub Dawidek 	nkey = 0;	/* fixes causeless gcc warning */
745c58794deSPawel Jakub Dawidek 
746c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
747c58794deSPawel Jakub Dawidek 	if (name == NULL) {
748c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
749c58794deSPawel Jakub Dawidek 		return;
750c58794deSPawel Jakub Dawidek 	}
751c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
752c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
753c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
754c58794deSPawel Jakub Dawidek 		return;
755c58794deSPawel Jakub Dawidek 	}
75685059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
75785059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot delete keys for read-only provider.");
75885059016SPawel Jakub Dawidek 		return;
75985059016SPawel Jakub Dawidek 	}
760c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
761c58794deSPawel Jakub Dawidek 	pp = cp->provider;
762c58794deSPawel Jakub Dawidek 
763c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
764c58794deSPawel Jakub Dawidek 	if (error != 0) {
765c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
766c58794deSPawel Jakub Dawidek 		    name, error);
767c58794deSPawel Jakub Dawidek 		return;
768c58794deSPawel Jakub Dawidek 	}
769c58794deSPawel Jakub Dawidek 
770c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
771c58794deSPawel Jakub Dawidek 	if (all == NULL) {
772c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
773c58794deSPawel Jakub Dawidek 		return;
774c58794deSPawel Jakub Dawidek 	}
775c58794deSPawel Jakub Dawidek 
776c58794deSPawel Jakub Dawidek 	if (*all) {
777c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys;
778c58794deSPawel Jakub Dawidek 		keysize = sizeof(md.md_mkeys);
779c58794deSPawel Jakub Dawidek 	} else {
780c58794deSPawel Jakub Dawidek 		force = gctl_get_paraml(req, "force", sizeof(*force));
781c58794deSPawel Jakub Dawidek 		if (force == NULL) {
782c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "force");
783c58794deSPawel Jakub Dawidek 			return;
784c58794deSPawel Jakub Dawidek 		}
785c58794deSPawel Jakub Dawidek 
786c58794deSPawel Jakub Dawidek 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
787c58794deSPawel Jakub Dawidek 		if (valp == NULL) {
788c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "keyno");
789c58794deSPawel Jakub Dawidek 			return;
790c58794deSPawel Jakub Dawidek 		}
791c58794deSPawel Jakub Dawidek 		if (*valp != -1)
792c58794deSPawel Jakub Dawidek 			nkey = *valp;
793c58794deSPawel Jakub Dawidek 		else
794c58794deSPawel Jakub Dawidek 			nkey = sc->sc_nkey;
795c58794deSPawel Jakub Dawidek 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
796c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid '%s' argument.", "keyno");
797c58794deSPawel Jakub Dawidek 			return;
798c58794deSPawel Jakub Dawidek 		}
799c58794deSPawel Jakub Dawidek 		if (!(md.md_keys & (1 << nkey)) && !*force) {
800c58794deSPawel Jakub Dawidek 			gctl_error(req, "Master Key %u is not set.", nkey);
801c58794deSPawel Jakub Dawidek 			return;
802c58794deSPawel Jakub Dawidek 		}
803c58794deSPawel Jakub Dawidek 		md.md_keys &= ~(1 << nkey);
804c58794deSPawel Jakub Dawidek 		if (md.md_keys == 0 && !*force) {
805c58794deSPawel Jakub Dawidek 			gctl_error(req, "This is the last Master Key. Use '-f' "
806c58794deSPawel Jakub Dawidek 			    "flag if you really want to remove it.");
807c58794deSPawel Jakub Dawidek 			return;
808c58794deSPawel Jakub Dawidek 		}
809c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
810c58794deSPawel Jakub Dawidek 		keysize = G_ELI_MKEYLEN;
811c58794deSPawel Jakub Dawidek 	}
812c58794deSPawel Jakub Dawidek 
813c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
814c58794deSPawel Jakub Dawidek 	for (i = 0; i <= g_eli_overwrites; i++) {
815c58794deSPawel Jakub Dawidek 		if (i == g_eli_overwrites)
81639b7ca45SAllan Jude 			explicit_bzero(mkeydst, keysize);
817c58794deSPawel Jakub Dawidek 		else
818c58794deSPawel Jakub Dawidek 			arc4rand(mkeydst, keysize, 0);
819c58794deSPawel Jakub Dawidek 		/* Store metadata with destroyed key. */
820c58794deSPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
821c58794deSPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
822c58794deSPawel Jakub Dawidek 		    pp->sectorsize);
823c58794deSPawel Jakub Dawidek 		if (error != 0) {
824c58794deSPawel Jakub Dawidek 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
825c58794deSPawel Jakub Dawidek 			    "(error=%d).", pp->name, error);
826c58794deSPawel Jakub Dawidek 		}
827f0256e71SPawel Jakub Dawidek 		/*
828f0256e71SPawel Jakub Dawidek 		 * Flush write cache so we don't overwrite data N times in cache
829f0256e71SPawel Jakub Dawidek 		 * and only once on disk.
830f0256e71SPawel Jakub Dawidek 		 */
831350e8df8SPawel Jakub Dawidek 		(void)g_io_flush(cp);
832c58794deSPawel Jakub Dawidek 	}
83339b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
83439b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
835c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
836c58794deSPawel Jakub Dawidek 	if (*all)
837c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
838c58794deSPawel Jakub Dawidek 	else
839c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
840c58794deSPawel Jakub Dawidek }
841c58794deSPawel Jakub Dawidek 
8420d2f5a4eSPawel Jakub Dawidek static void
8430d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
8445ad4a7c7SPawel Jakub Dawidek {
8455ad4a7c7SPawel Jakub Dawidek 	struct g_eli_worker *wr;
8465ad4a7c7SPawel Jakub Dawidek 
8475ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8485ad4a7c7SPawel Jakub Dawidek 
8490d2f5a4eSPawel Jakub Dawidek 	KASSERT(sc != NULL, ("NULL sc"));
8500d2f5a4eSPawel Jakub Dawidek 
8510d2f5a4eSPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
8520d2f5a4eSPawel Jakub Dawidek 		gctl_error(req,
8530d2f5a4eSPawel Jakub Dawidek 		    "Device %s is using one-time key, suspend not supported.",
8540d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8550d2f5a4eSPawel Jakub Dawidek 		return;
8560d2f5a4eSPawel Jakub Dawidek 	}
8575ad4a7c7SPawel Jakub Dawidek 
8585ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
8595ad4a7c7SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
8605ad4a7c7SPawel Jakub Dawidek 		mtx_unlock(&sc->sc_queue_mtx);
8610d2f5a4eSPawel Jakub Dawidek 		gctl_error(req, "Device %s already suspended.",
8620d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8630d2f5a4eSPawel Jakub Dawidek 		return;
8645ad4a7c7SPawel Jakub Dawidek 	}
8655ad4a7c7SPawel Jakub Dawidek 	sc->sc_flags |= G_ELI_FLAG_SUSPEND;
8665ad4a7c7SPawel Jakub Dawidek 	wakeup(sc);
8675ad4a7c7SPawel Jakub Dawidek 	for (;;) {
8685ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH(wr, &sc->sc_workers, w_next) {
8695ad4a7c7SPawel Jakub Dawidek 			if (wr->w_active)
8705ad4a7c7SPawel Jakub Dawidek 				break;
8715ad4a7c7SPawel Jakub Dawidek 		}
8725ad4a7c7SPawel Jakub Dawidek 		if (wr == NULL)
8735ad4a7c7SPawel Jakub Dawidek 			break;
8745ad4a7c7SPawel Jakub Dawidek 		/* Not all threads suspended. */
8755ad4a7c7SPawel Jakub Dawidek 		msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
8765ad4a7c7SPawel Jakub Dawidek 		    "geli:suspend", 0);
8775ad4a7c7SPawel Jakub Dawidek 	}
8785ad4a7c7SPawel Jakub Dawidek 	/*
8795ad4a7c7SPawel Jakub Dawidek 	 * Clear sensitive data on suspend, they will be recovered on resume.
8805ad4a7c7SPawel Jakub Dawidek 	 */
88139b7ca45SAllan Jude 	explicit_bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
8821e09ff3dSPawel Jakub Dawidek 	g_eli_key_destroy(sc);
88339b7ca45SAllan Jude 	explicit_bzero(sc->sc_akey, sizeof(sc->sc_akey));
88439b7ca45SAllan Jude 	explicit_bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
88539b7ca45SAllan Jude 	explicit_bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
88639b7ca45SAllan Jude 	explicit_bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
8875ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
8880d2f5a4eSPawel Jakub Dawidek 	G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
8895ad4a7c7SPawel Jakub Dawidek }
8905ad4a7c7SPawel Jakub Dawidek 
8915ad4a7c7SPawel Jakub Dawidek static void
8925ad4a7c7SPawel Jakub Dawidek g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
8935ad4a7c7SPawel Jakub Dawidek {
8945ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
8955ad4a7c7SPawel Jakub Dawidek 	int *all, *nargs;
8965ad4a7c7SPawel Jakub Dawidek 
8975ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8985ad4a7c7SPawel Jakub Dawidek 
8995ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
9005ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
9015ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
9025ad4a7c7SPawel Jakub Dawidek 		return;
9035ad4a7c7SPawel Jakub Dawidek 	}
9045ad4a7c7SPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
9055ad4a7c7SPawel Jakub Dawidek 	if (all == NULL) {
9065ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
9075ad4a7c7SPawel Jakub Dawidek 		return;
9085ad4a7c7SPawel Jakub Dawidek 	}
9095ad4a7c7SPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
9105ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
9115ad4a7c7SPawel Jakub Dawidek 		return;
9125ad4a7c7SPawel Jakub Dawidek 	}
9135ad4a7c7SPawel Jakub Dawidek 
9145ad4a7c7SPawel Jakub Dawidek 	if (*all) {
9155ad4a7c7SPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
9165ad4a7c7SPawel Jakub Dawidek 
9175ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
9185ad4a7c7SPawel Jakub Dawidek 			sc = gp->softc;
9190d2f5a4eSPawel Jakub Dawidek 			if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
9200d2f5a4eSPawel Jakub Dawidek 				G_ELI_DEBUG(0,
9210d2f5a4eSPawel Jakub Dawidek 				    "Device %s is using one-time key, suspend not supported, skipping.",
9220d2f5a4eSPawel Jakub Dawidek 				    sc->sc_name);
9235ad4a7c7SPawel Jakub Dawidek 				continue;
9240d2f5a4eSPawel Jakub Dawidek 			}
9250d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9265ad4a7c7SPawel Jakub Dawidek 		}
9275ad4a7c7SPawel Jakub Dawidek 	} else {
9285ad4a7c7SPawel Jakub Dawidek 		const char *prov;
9295ad4a7c7SPawel Jakub Dawidek 		char param[16];
9305ad4a7c7SPawel Jakub Dawidek 		int i;
9315ad4a7c7SPawel Jakub Dawidek 
9325ad4a7c7SPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
9335ad4a7c7SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
9345ad4a7c7SPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
9355ad4a7c7SPawel Jakub Dawidek 			if (prov == NULL) {
9365ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
9375ad4a7c7SPawel Jakub Dawidek 				continue;
9385ad4a7c7SPawel Jakub Dawidek 			}
9395ad4a7c7SPawel Jakub Dawidek 
9405ad4a7c7SPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
9415ad4a7c7SPawel Jakub Dawidek 			if (sc == NULL) {
9425ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
9435ad4a7c7SPawel Jakub Dawidek 				continue;
9445ad4a7c7SPawel Jakub Dawidek 			}
9450d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9465ad4a7c7SPawel Jakub Dawidek 		}
9475ad4a7c7SPawel Jakub Dawidek 	}
9485ad4a7c7SPawel Jakub Dawidek }
9495ad4a7c7SPawel Jakub Dawidek 
9505ad4a7c7SPawel Jakub Dawidek static void
9515ad4a7c7SPawel Jakub Dawidek g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
9525ad4a7c7SPawel Jakub Dawidek {
9535ad4a7c7SPawel Jakub Dawidek 	struct g_eli_metadata md;
9545ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
9555ad4a7c7SPawel Jakub Dawidek 	struct g_provider *pp;
9565ad4a7c7SPawel Jakub Dawidek 	struct g_consumer *cp;
9575ad4a7c7SPawel Jakub Dawidek 	const char *name;
9585ad4a7c7SPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
9595ad4a7c7SPawel Jakub Dawidek 	int *nargs, keysize, error;
9605ad4a7c7SPawel Jakub Dawidek 	u_int nkey;
9615ad4a7c7SPawel Jakub Dawidek 
9625ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
9635ad4a7c7SPawel Jakub Dawidek 
9645ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
9655ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
9665ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
9675ad4a7c7SPawel Jakub Dawidek 		return;
9685ad4a7c7SPawel Jakub Dawidek 	}
9695ad4a7c7SPawel Jakub Dawidek 	if (*nargs != 1) {
9705ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
9715ad4a7c7SPawel Jakub Dawidek 		return;
9725ad4a7c7SPawel Jakub Dawidek 	}
9735ad4a7c7SPawel Jakub Dawidek 
9745ad4a7c7SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
9755ad4a7c7SPawel Jakub Dawidek 	if (name == NULL) {
9765ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
9775ad4a7c7SPawel Jakub Dawidek 		return;
9785ad4a7c7SPawel Jakub Dawidek 	}
97939b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
98039b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
98139b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
98239b7ca45SAllan Jude 		return;
98339b7ca45SAllan Jude 	}
9845ad4a7c7SPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
9855ad4a7c7SPawel Jakub Dawidek 	if (sc == NULL) {
9865ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
9875ad4a7c7SPawel Jakub Dawidek 		return;
9885ad4a7c7SPawel Jakub Dawidek 	}
9895ad4a7c7SPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
9905ad4a7c7SPawel Jakub Dawidek 	pp = cp->provider;
9915ad4a7c7SPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
9925ad4a7c7SPawel Jakub Dawidek 	if (error != 0) {
9935ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
9945ad4a7c7SPawel Jakub Dawidek 		    name, error);
9955ad4a7c7SPawel Jakub Dawidek 		return;
9965ad4a7c7SPawel Jakub Dawidek 	}
9975ad4a7c7SPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
99839b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9995ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
10005ad4a7c7SPawel Jakub Dawidek 		return;
10015ad4a7c7SPawel Jakub Dawidek 	}
10025ad4a7c7SPawel Jakub Dawidek 
100331f7586dSMariusz Zaborski 	error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey);
100439b7ca45SAllan Jude 	explicit_bzero(key, keysize);
10055ad4a7c7SPawel Jakub Dawidek 	if (error == -1) {
100639b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
10075ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
10085ad4a7c7SPawel Jakub Dawidek 		return;
10095ad4a7c7SPawel Jakub Dawidek 	} else if (error > 0) {
101039b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
10115ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
10125ad4a7c7SPawel Jakub Dawidek 		    pp->name, error);
10135ad4a7c7SPawel Jakub Dawidek 		return;
10145ad4a7c7SPawel Jakub Dawidek 	}
10155ad4a7c7SPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
10165ad4a7c7SPawel Jakub Dawidek 
10175ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
10182f2d7830SPawel Jakub Dawidek 	if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
10192f2d7830SPawel Jakub Dawidek 		gctl_error(req, "Device %s is not suspended.", name);
10202f2d7830SPawel Jakub Dawidek 	else {
10215ad4a7c7SPawel Jakub Dawidek 		/* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
10225ad4a7c7SPawel Jakub Dawidek 		g_eli_mkey_propagate(sc, mkey);
10235ad4a7c7SPawel Jakub Dawidek 		sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
10242f2d7830SPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Resumed %s.", pp->name);
10252f2d7830SPawel Jakub Dawidek 		wakeup(sc);
10262f2d7830SPawel Jakub Dawidek 	}
10275ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
102839b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
102939b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
10305ad4a7c7SPawel Jakub Dawidek }
10315ad4a7c7SPawel Jakub Dawidek 
10325ad4a7c7SPawel Jakub Dawidek static int
1033c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc)
1034c58794deSPawel Jakub Dawidek {
1035c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
1036c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
103785059016SPawel Jakub Dawidek 	int error = 0;
1038c58794deSPawel Jakub Dawidek 
1039c58794deSPawel Jakub Dawidek 	g_topology_assert();
1040c58794deSPawel Jakub Dawidek 
1041c58794deSPawel Jakub Dawidek 	if (sc == NULL)
1042c58794deSPawel Jakub Dawidek 		return (ENOENT);
1043c58794deSPawel Jakub Dawidek 
1044c58794deSPawel Jakub Dawidek 	pp = LIST_FIRST(&sc->sc_geom->provider);
1045c58794deSPawel Jakub Dawidek 	g_error_provider(pp, ENXIO);
1046c58794deSPawel Jakub Dawidek 
1047c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
1048c58794deSPawel Jakub Dawidek 	pp = cp->provider;
1049c58794deSPawel Jakub Dawidek 
105085059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
105185059016SPawel Jakub Dawidek 		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
105285059016SPawel Jakub Dawidek 		    "provider: %s.", pp->name);
105385059016SPawel Jakub Dawidek 	} else {
105485059016SPawel Jakub Dawidek 		u_char *sector;
105585059016SPawel Jakub Dawidek 		u_int i;
105685059016SPawel Jakub Dawidek 		int err;
105785059016SPawel Jakub Dawidek 
1058c58794deSPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
1059c58794deSPawel Jakub Dawidek 		for (i = 0; i <= g_eli_overwrites; i++) {
1060c58794deSPawel Jakub Dawidek 			if (i == g_eli_overwrites)
1061c58794deSPawel Jakub Dawidek 				bzero(sector, pp->sectorsize);
1062c58794deSPawel Jakub Dawidek 			else
1063c58794deSPawel Jakub Dawidek 				arc4rand(sector, pp->sectorsize, 0);
106485059016SPawel Jakub Dawidek 			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
106585059016SPawel Jakub Dawidek 			    sector, pp->sectorsize);
1066c58794deSPawel Jakub Dawidek 			if (err != 0) {
1067c58794deSPawel Jakub Dawidek 				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
1068c58794deSPawel Jakub Dawidek 				    "(error=%d).", pp->name, err);
1069c58794deSPawel Jakub Dawidek 				if (error == 0)
1070c58794deSPawel Jakub Dawidek 					error = err;
1071c58794deSPawel Jakub Dawidek 			}
1072350e8df8SPawel Jakub Dawidek 			/*
1073350e8df8SPawel Jakub Dawidek 			 * Flush write cache so we don't overwrite data N times
1074350e8df8SPawel Jakub Dawidek 			 * in cache and only once on disk.
1075350e8df8SPawel Jakub Dawidek 			 */
1076350e8df8SPawel Jakub Dawidek 			(void)g_io_flush(cp);
1077c58794deSPawel Jakub Dawidek 		}
1078c58794deSPawel Jakub Dawidek 		free(sector, M_ELI);
107985059016SPawel Jakub Dawidek 	}
1080c58794deSPawel Jakub Dawidek 	if (error == 0)
1081c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
10825ad4a7c7SPawel Jakub Dawidek 	g_eli_destroy(sc, TRUE);
1083c58794deSPawel Jakub Dawidek 	return (error);
1084c58794deSPawel Jakub Dawidek }
1085c58794deSPawel Jakub Dawidek 
1086c58794deSPawel Jakub Dawidek static void
1087c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
1088c58794deSPawel Jakub Dawidek {
1089c58794deSPawel Jakub Dawidek 	int *all, *nargs;
1090c58794deSPawel Jakub Dawidek 	int error;
1091c58794deSPawel Jakub Dawidek 
1092c58794deSPawel Jakub Dawidek 	g_topology_assert();
1093c58794deSPawel Jakub Dawidek 
1094c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1095c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
1096c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
1097c58794deSPawel Jakub Dawidek 		return;
1098c58794deSPawel Jakub Dawidek 	}
1099c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
1100c58794deSPawel Jakub Dawidek 	if (all == NULL) {
1101c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
1102c58794deSPawel Jakub Dawidek 		return;
1103c58794deSPawel Jakub Dawidek 	}
1104c58794deSPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
1105c58794deSPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
1106c58794deSPawel Jakub Dawidek 		return;
1107c58794deSPawel Jakub Dawidek 	}
1108c58794deSPawel Jakub Dawidek 
1109c58794deSPawel Jakub Dawidek 	if (*all) {
1110c58794deSPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
1111c58794deSPawel Jakub Dawidek 
1112c58794deSPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
1113c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(gp->softc);
1114c58794deSPawel Jakub Dawidek 			if (error != 0)
1115c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1116c58794deSPawel Jakub Dawidek 		}
1117c58794deSPawel Jakub Dawidek 	} else {
1118c58794deSPawel Jakub Dawidek 		struct g_eli_softc *sc;
1119c58794deSPawel Jakub Dawidek 		const char *prov;
1120c58794deSPawel Jakub Dawidek 		char param[16];
1121c58794deSPawel Jakub Dawidek 		int i;
1122c58794deSPawel Jakub Dawidek 
1123c58794deSPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
11247d54b385SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
1125c58794deSPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
1126b5f30223SPawel Jakub Dawidek 			if (prov == NULL) {
1127b5f30223SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
1128b5f30223SPawel Jakub Dawidek 				continue;
1129b5f30223SPawel Jakub Dawidek 			}
1130c58794deSPawel Jakub Dawidek 
1131c58794deSPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
1132c58794deSPawel Jakub Dawidek 			if (sc == NULL) {
11337d54b385SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
1134c58794deSPawel Jakub Dawidek 				continue;
1135c58794deSPawel Jakub Dawidek 			}
1136c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(sc);
1137c58794deSPawel Jakub Dawidek 			if (error != 0)
1138c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1139c58794deSPawel Jakub Dawidek 		}
1140c58794deSPawel Jakub Dawidek 	}
1141c58794deSPawel Jakub Dawidek }
1142c58794deSPawel Jakub Dawidek 
1143c58794deSPawel Jakub Dawidek void
1144c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1145c58794deSPawel Jakub Dawidek {
1146c58794deSPawel Jakub Dawidek 	uint32_t *version;
1147c58794deSPawel Jakub Dawidek 
1148c58794deSPawel Jakub Dawidek 	g_topology_assert();
1149c58794deSPawel Jakub Dawidek 
1150c58794deSPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
1151c58794deSPawel Jakub Dawidek 	if (version == NULL) {
1152c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
1153c58794deSPawel Jakub Dawidek 		return;
1154c58794deSPawel Jakub Dawidek 	}
1155731adc86SPawel Jakub Dawidek 	while (*version != G_ELI_VERSION) {
1156731adc86SPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_06 &&
1157731adc86SPawel Jakub Dawidek 		    *version == G_ELI_VERSION_05) {
1158731adc86SPawel Jakub Dawidek 			/* Compatible. */
1159731adc86SPawel Jakub Dawidek 			break;
1160731adc86SPawel Jakub Dawidek 		}
1161457bbc4fSPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_07 &&
1162457bbc4fSPawel Jakub Dawidek 		    (*version == G_ELI_VERSION_05 ||
1163457bbc4fSPawel Jakub Dawidek 		     *version == G_ELI_VERSION_06)) {
1164457bbc4fSPawel Jakub Dawidek 			/* Compatible. */
1165457bbc4fSPawel Jakub Dawidek 			break;
1166457bbc4fSPawel Jakub Dawidek 		}
1167c58794deSPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
1168c58794deSPawel Jakub Dawidek 		return;
1169c58794deSPawel Jakub Dawidek 	}
1170c58794deSPawel Jakub Dawidek 
1171c58794deSPawel Jakub Dawidek 	if (strcmp(verb, "attach") == 0)
1172c58794deSPawel Jakub Dawidek 		g_eli_ctl_attach(req, mp);
1173c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
1174c58794deSPawel Jakub Dawidek 		g_eli_ctl_detach(req, mp);
1175c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "onetime") == 0)
1176c58794deSPawel Jakub Dawidek 		g_eli_ctl_onetime(req, mp);
11778abd1ad1SPawel Jakub Dawidek 	else if (strcmp(verb, "configure") == 0)
11788abd1ad1SPawel Jakub Dawidek 		g_eli_ctl_configure(req, mp);
1179c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "setkey") == 0)
1180c58794deSPawel Jakub Dawidek 		g_eli_ctl_setkey(req, mp);
1181c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "delkey") == 0)
1182c58794deSPawel Jakub Dawidek 		g_eli_ctl_delkey(req, mp);
11835ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "suspend") == 0)
11845ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_suspend(req, mp);
11855ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "resume") == 0)
11865ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_resume(req, mp);
1187c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "kill") == 0)
1188c58794deSPawel Jakub Dawidek 		g_eli_ctl_kill(req, mp);
1189c58794deSPawel Jakub Dawidek 	else
1190c58794deSPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
1191c58794deSPawel Jakub Dawidek }
1192