xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision 3728855a0f66545c4aa90dc0d478dc403bdfa667)
1c58794deSPawel Jakub Dawidek /*-
2*3728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*3728855aSPedro 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];
6285059016SPawel Jakub Dawidek 	int *nargs, *detach, *readonly;
63c58794deSPawel Jakub Dawidek 	int keysize, error;
64c58794deSPawel Jakub Dawidek 	u_int nkey;
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 
8485059016SPawel Jakub Dawidek 	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
8585059016SPawel Jakub Dawidek 	if (readonly == NULL) {
8685059016SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "readonly");
8785059016SPawel Jakub Dawidek 		return;
8885059016SPawel Jakub Dawidek 	}
8985059016SPawel Jakub Dawidek 
9039b7ca45SAllan Jude 	if (*detach && *readonly) {
9139b7ca45SAllan Jude 		gctl_error(req, "Options -d and -r are mutually exclusive.");
9239b7ca45SAllan Jude 		return;
9339b7ca45SAllan Jude 	}
9439b7ca45SAllan Jude 
95c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
96c58794deSPawel Jakub Dawidek 	if (name == NULL) {
97c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
98c58794deSPawel Jakub Dawidek 		return;
99c58794deSPawel Jakub Dawidek 	}
100c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
101c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
102c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
103c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
104c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
105c58794deSPawel Jakub Dawidek 		return;
106c58794deSPawel Jakub Dawidek 	}
107c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
108c58794deSPawel Jakub Dawidek 	if (error != 0) {
109c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
110c58794deSPawel Jakub Dawidek 		    name, error);
111c58794deSPawel Jakub Dawidek 		return;
112c58794deSPawel Jakub Dawidek 	}
113c58794deSPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
11439b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
115c58794deSPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
116c58794deSPawel Jakub Dawidek 		return;
117c58794deSPawel Jakub Dawidek 	}
118c58794deSPawel Jakub Dawidek 
119c58794deSPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
120c58794deSPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
12139b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
122c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
123c58794deSPawel Jakub Dawidek 		return;
124c58794deSPawel Jakub Dawidek 	}
125c58794deSPawel Jakub Dawidek 
126c58794deSPawel Jakub Dawidek 	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
12739b7ca45SAllan Jude 	explicit_bzero(key, keysize);
128c58794deSPawel Jakub Dawidek 	if (error == -1) {
12939b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
130c58794deSPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
131c58794deSPawel Jakub Dawidek 		return;
132c58794deSPawel Jakub Dawidek 	} else if (error > 0) {
13339b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
134c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
135c58794deSPawel Jakub Dawidek 		    pp->name, error);
136c58794deSPawel Jakub Dawidek 		return;
137c58794deSPawel Jakub Dawidek 	}
138c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
139c58794deSPawel Jakub Dawidek 
140c58794deSPawel Jakub Dawidek 	if (*detach)
141c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
14285059016SPawel Jakub Dawidek 	if (*readonly)
14385059016SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_RO;
144c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, nkey);
14539b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
14639b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
147c58794deSPawel Jakub Dawidek }
148c58794deSPawel Jakub Dawidek 
149c58794deSPawel Jakub Dawidek static struct g_eli_softc *
150c58794deSPawel Jakub Dawidek g_eli_find_device(struct g_class *mp, const char *prov)
151c58794deSPawel Jakub Dawidek {
152c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
153c58794deSPawel Jakub Dawidek 	struct g_geom *gp;
154c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
155c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
156c58794deSPawel Jakub Dawidek 
157c58794deSPawel Jakub Dawidek 	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
158c58794deSPawel Jakub Dawidek 		prov += strlen("/dev/");
159c58794deSPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
160c58794deSPawel Jakub Dawidek 		sc = gp->softc;
161c58794deSPawel Jakub Dawidek 		if (sc == NULL)
162c58794deSPawel Jakub Dawidek 			continue;
163c58794deSPawel Jakub Dawidek 		pp = LIST_FIRST(&gp->provider);
164c58794deSPawel Jakub Dawidek 		if (pp != NULL && strcmp(pp->name, prov) == 0)
165c58794deSPawel Jakub Dawidek 			return (sc);
166c58794deSPawel Jakub Dawidek 		cp = LIST_FIRST(&gp->consumer);
167c58794deSPawel Jakub Dawidek 		if (cp != NULL && cp->provider != NULL &&
168c58794deSPawel Jakub Dawidek 		    strcmp(cp->provider->name, prov) == 0) {
169c58794deSPawel Jakub Dawidek 			return (sc);
170c58794deSPawel Jakub Dawidek 		}
171c58794deSPawel Jakub Dawidek 	}
172c58794deSPawel Jakub Dawidek 	return (NULL);
173c58794deSPawel Jakub Dawidek }
174c58794deSPawel Jakub Dawidek 
175c58794deSPawel Jakub Dawidek static void
176c58794deSPawel Jakub Dawidek g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
177c58794deSPawel Jakub Dawidek {
178c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
179c58794deSPawel Jakub Dawidek 	int *force, *last, *nargs, error;
180c58794deSPawel Jakub Dawidek 	const char *prov;
181c58794deSPawel Jakub Dawidek 	char param[16];
1827d54b385SPawel Jakub Dawidek 	int i;
183c58794deSPawel Jakub Dawidek 
184c58794deSPawel Jakub Dawidek 	g_topology_assert();
185c58794deSPawel Jakub Dawidek 
186c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
187c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
188c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
189c58794deSPawel Jakub Dawidek 		return;
190c58794deSPawel Jakub Dawidek 	}
191c58794deSPawel Jakub Dawidek 	if (*nargs <= 0) {
192c58794deSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
193c58794deSPawel Jakub Dawidek 		return;
194c58794deSPawel Jakub Dawidek 	}
195c58794deSPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
196c58794deSPawel Jakub Dawidek 	if (force == NULL) {
197c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "force");
198c58794deSPawel Jakub Dawidek 		return;
199c58794deSPawel Jakub Dawidek 	}
200c58794deSPawel Jakub Dawidek 	last = gctl_get_paraml(req, "last", sizeof(*last));
201c58794deSPawel Jakub Dawidek 	if (last == NULL) {
202c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "last");
203c58794deSPawel Jakub Dawidek 		return;
204c58794deSPawel Jakub Dawidek 	}
205c58794deSPawel Jakub Dawidek 
2067d54b385SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
2077d54b385SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
208c58794deSPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
209c58794deSPawel Jakub Dawidek 		if (prov == NULL) {
2107d54b385SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
211c58794deSPawel Jakub Dawidek 			return;
212c58794deSPawel Jakub Dawidek 		}
213c58794deSPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
214c58794deSPawel Jakub Dawidek 		if (sc == NULL) {
215c58794deSPawel Jakub Dawidek 			gctl_error(req, "No such device: %s.", prov);
216c58794deSPawel Jakub Dawidek 			return;
217c58794deSPawel Jakub Dawidek 		}
218c58794deSPawel Jakub Dawidek 		if (*last) {
219c58794deSPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
220c58794deSPawel Jakub Dawidek 			sc->sc_geom->access = g_eli_access;
221c58794deSPawel Jakub Dawidek 		} else {
2225ad4a7c7SPawel Jakub Dawidek 			error = g_eli_destroy(sc, *force ? TRUE : FALSE);
223c58794deSPawel Jakub Dawidek 			if (error != 0) {
224c58794deSPawel Jakub Dawidek 				gctl_error(req,
225c58794deSPawel Jakub Dawidek 				    "Cannot destroy device %s (error=%d).",
226c58794deSPawel Jakub Dawidek 				    sc->sc_name, error);
227c58794deSPawel Jakub Dawidek 				return;
228c58794deSPawel Jakub Dawidek 			}
229c58794deSPawel Jakub Dawidek 		}
230c58794deSPawel Jakub Dawidek 	}
231c58794deSPawel Jakub Dawidek }
232c58794deSPawel Jakub Dawidek 
233c58794deSPawel Jakub Dawidek static void
234c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
235c58794deSPawel Jakub Dawidek {
236c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
237c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
238c58794deSPawel Jakub Dawidek 	const char *name;
239c58794deSPawel Jakub Dawidek 	intmax_t *keylen, *sectorsize;
240c58794deSPawel Jakub Dawidek 	u_char mkey[G_ELI_DATAIVKEYLEN];
24146e34470SPawel Jakub Dawidek 	int *nargs, *detach, *notrim;
242c58794deSPawel Jakub Dawidek 
243c58794deSPawel Jakub Dawidek 	g_topology_assert();
244c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
245c58794deSPawel Jakub Dawidek 
246c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
247c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
248c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
249c58794deSPawel Jakub Dawidek 		return;
250c58794deSPawel Jakub Dawidek 	}
251c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
252c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
253c58794deSPawel Jakub Dawidek 		return;
254c58794deSPawel Jakub Dawidek 	}
255c58794deSPawel Jakub Dawidek 
256c58794deSPawel Jakub Dawidek 	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
257c58794deSPawel Jakub Dawidek 	md.md_version = G_ELI_VERSION;
258c58794deSPawel Jakub Dawidek 	md.md_flags |= G_ELI_FLAG_ONETIME;
25946e34470SPawel Jakub Dawidek 
26046e34470SPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
26146e34470SPawel Jakub Dawidek 	if (detach != NULL && *detach)
262c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
26346e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
26446e34470SPawel Jakub Dawidek 	if (notrim != NULL && *notrim)
26546e34470SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_NODELETE;
266c58794deSPawel Jakub Dawidek 
267c84efdcaSPawel Jakub Dawidek 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
268eaa3b919SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "aalgo");
269c58794deSPawel Jakub Dawidek 	if (name == NULL) {
270eaa3b919SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "aalgo");
271c58794deSPawel Jakub Dawidek 		return;
272c58794deSPawel Jakub Dawidek 	}
273a478ea74SPawel Jakub Dawidek 	if (*name != '\0') {
274eaa3b919SPawel Jakub Dawidek 		md.md_aalgo = g_eli_str2aalgo(name);
275c84efdcaSPawel Jakub Dawidek 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
276c84efdcaSPawel Jakub Dawidek 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
277eaa3b919SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_AUTH;
278c84efdcaSPawel Jakub Dawidek 		} else {
279c84efdcaSPawel Jakub Dawidek 			/*
280c84efdcaSPawel Jakub Dawidek 			 * For backward compatibility, check if the -a option
281c84efdcaSPawel Jakub Dawidek 			 * was used to provide encryption algorithm.
282c84efdcaSPawel Jakub Dawidek 			 */
283c84efdcaSPawel Jakub Dawidek 			md.md_ealgo = g_eli_str2ealgo(name);
284c84efdcaSPawel Jakub Dawidek 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
285c84efdcaSPawel Jakub Dawidek 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
286c84efdcaSPawel Jakub Dawidek 				gctl_error(req,
287c84efdcaSPawel Jakub Dawidek 				    "Invalid authentication algorithm.");
288c84efdcaSPawel Jakub Dawidek 				return;
289c84efdcaSPawel Jakub Dawidek 			} else {
290c84efdcaSPawel Jakub Dawidek 				gctl_error(req, "warning: The -e option, not "
291c84efdcaSPawel Jakub Dawidek 				    "the -a option is now used to specify "
292c84efdcaSPawel Jakub Dawidek 				    "encryption algorithm to use.");
293c84efdcaSPawel Jakub Dawidek 			}
294c84efdcaSPawel Jakub Dawidek 		}
295eaa3b919SPawel Jakub Dawidek 	}
296eaa3b919SPawel Jakub Dawidek 
297c84efdcaSPawel Jakub Dawidek 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
298c84efdcaSPawel Jakub Dawidek 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
299eaa3b919SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, "ealgo");
300eaa3b919SPawel Jakub Dawidek 		if (name == NULL) {
301eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "ealgo");
302eaa3b919SPawel Jakub Dawidek 			return;
303eaa3b919SPawel Jakub Dawidek 		}
304eaa3b919SPawel Jakub Dawidek 		md.md_ealgo = g_eli_str2ealgo(name);
305eaa3b919SPawel Jakub Dawidek 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
306eaa3b919SPawel Jakub Dawidek 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
307eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "Invalid encryption algorithm.");
308c58794deSPawel Jakub Dawidek 			return;
309c58794deSPawel Jakub Dawidek 		}
310c84efdcaSPawel Jakub Dawidek 	}
311c58794deSPawel Jakub Dawidek 
312c58794deSPawel Jakub Dawidek 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
313c58794deSPawel Jakub Dawidek 	if (keylen == NULL) {
314c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keylen");
315c58794deSPawel Jakub Dawidek 		return;
316c58794deSPawel Jakub Dawidek 	}
317eaa3b919SPawel Jakub Dawidek 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
318c58794deSPawel Jakub Dawidek 	if (md.md_keylen == 0) {
319c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keylen");
320c58794deSPawel Jakub Dawidek 		return;
321c58794deSPawel Jakub Dawidek 	}
322c58794deSPawel Jakub Dawidek 
323c58794deSPawel Jakub Dawidek 	/* Not important here. */
324c58794deSPawel Jakub Dawidek 	md.md_provsize = 0;
325c58794deSPawel Jakub Dawidek 	/* Not important here. */
326c58794deSPawel Jakub Dawidek 	bzero(md.md_salt, sizeof(md.md_salt));
327c58794deSPawel Jakub Dawidek 
328c58794deSPawel Jakub Dawidek 	md.md_keys = 0x01;
329c58794deSPawel Jakub Dawidek 	arc4rand(mkey, sizeof(mkey), 0);
330c58794deSPawel Jakub Dawidek 
331c58794deSPawel Jakub Dawidek 	/* Not important here. */
332c58794deSPawel Jakub Dawidek 	bzero(md.md_hash, sizeof(md.md_hash));
333c58794deSPawel Jakub Dawidek 
334c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
335c58794deSPawel Jakub Dawidek 	if (name == NULL) {
336c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
337c58794deSPawel Jakub Dawidek 		return;
338c58794deSPawel Jakub Dawidek 	}
339c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
340c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
341c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
342c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
343c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
344c58794deSPawel Jakub Dawidek 		return;
345c58794deSPawel Jakub Dawidek 	}
346c58794deSPawel Jakub Dawidek 
347c58794deSPawel Jakub Dawidek 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
348c58794deSPawel Jakub Dawidek 	if (sectorsize == NULL) {
349c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "sectorsize");
350c58794deSPawel Jakub Dawidek 		return;
351c58794deSPawel Jakub Dawidek 	}
352c58794deSPawel Jakub Dawidek 	if (*sectorsize == 0)
353c58794deSPawel Jakub Dawidek 		md.md_sectorsize = pp->sectorsize;
354c58794deSPawel Jakub Dawidek 	else {
355c58794deSPawel Jakub Dawidek 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
356c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid sector size.");
357c58794deSPawel Jakub Dawidek 			return;
358c58794deSPawel Jakub Dawidek 		}
35997a669a3SPawel Jakub Dawidek 		if (*sectorsize > PAGE_SIZE) {
36097a669a3SPawel Jakub Dawidek 			gctl_error(req, "warning: Using sectorsize bigger than "
36197a669a3SPawel Jakub Dawidek 			    "the page size!");
36297a669a3SPawel Jakub Dawidek 		}
363c58794deSPawel Jakub Dawidek 		md.md_sectorsize = *sectorsize;
364c58794deSPawel Jakub Dawidek 	}
365c58794deSPawel Jakub Dawidek 
366c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, -1);
36739b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
36839b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
369c58794deSPawel Jakub Dawidek }
370c58794deSPawel Jakub Dawidek 
371c58794deSPawel Jakub Dawidek static void
3728abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
3738abd1ad1SPawel Jakub Dawidek {
3748abd1ad1SPawel Jakub Dawidek 	struct g_eli_softc *sc;
3758abd1ad1SPawel Jakub Dawidek 	struct g_eli_metadata md;
3768abd1ad1SPawel Jakub Dawidek 	struct g_provider *pp;
3778abd1ad1SPawel Jakub Dawidek 	struct g_consumer *cp;
3788abd1ad1SPawel Jakub Dawidek 	char param[16];
3798abd1ad1SPawel Jakub Dawidek 	const char *prov;
3808abd1ad1SPawel Jakub Dawidek 	u_char *sector;
381d8736625SAllan Jude 	int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot;
3823453dc72SMariusz Zaborski 	int *displaypass, *nodisplaypass;
38346e34470SPawel Jakub Dawidek 	int zero, error, changed;
3848abd1ad1SPawel Jakub Dawidek 	u_int i;
3858abd1ad1SPawel Jakub Dawidek 
3868abd1ad1SPawel Jakub Dawidek 	g_topology_assert();
3878abd1ad1SPawel Jakub Dawidek 
38846e34470SPawel Jakub Dawidek 	changed = 0;
38946e34470SPawel Jakub Dawidek 	zero = 0;
39046e34470SPawel Jakub Dawidek 
3918abd1ad1SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
3928abd1ad1SPawel Jakub Dawidek 	if (nargs == NULL) {
3938abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
3948abd1ad1SPawel Jakub Dawidek 		return;
3958abd1ad1SPawel Jakub Dawidek 	}
3968abd1ad1SPawel Jakub Dawidek 	if (*nargs <= 0) {
3978abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
3988abd1ad1SPawel Jakub Dawidek 		return;
3998abd1ad1SPawel Jakub Dawidek 	}
4008abd1ad1SPawel Jakub Dawidek 
4018abd1ad1SPawel Jakub Dawidek 	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
40246e34470SPawel Jakub Dawidek 	if (boot == NULL)
40346e34470SPawel Jakub Dawidek 		boot = &zero;
4048abd1ad1SPawel Jakub Dawidek 	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
40546e34470SPawel Jakub Dawidek 	if (noboot == NULL)
40646e34470SPawel Jakub Dawidek 		noboot = &zero;
4078abd1ad1SPawel Jakub Dawidek 	if (*boot && *noboot) {
4088abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Options -b and -B are mutually exclusive.");
4098abd1ad1SPawel Jakub Dawidek 		return;
4108abd1ad1SPawel Jakub Dawidek 	}
41146e34470SPawel Jakub Dawidek 	if (*boot || *noboot)
41246e34470SPawel Jakub Dawidek 		changed = 1;
41346e34470SPawel Jakub Dawidek 
41446e34470SPawel Jakub Dawidek 	trim = gctl_get_paraml(req, "trim", sizeof(*trim));
41546e34470SPawel Jakub Dawidek 	if (trim == NULL)
41646e34470SPawel Jakub Dawidek 		trim = &zero;
41746e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
41846e34470SPawel Jakub Dawidek 	if (notrim == NULL)
41946e34470SPawel Jakub Dawidek 		notrim = &zero;
42046e34470SPawel Jakub Dawidek 	if (*trim && *notrim) {
42146e34470SPawel Jakub Dawidek 		gctl_error(req, "Options -t and -T are mutually exclusive.");
42246e34470SPawel Jakub Dawidek 		return;
42346e34470SPawel Jakub Dawidek 	}
42446e34470SPawel Jakub Dawidek 	if (*trim || *notrim)
42546e34470SPawel Jakub Dawidek 		changed = 1;
42646e34470SPawel Jakub Dawidek 
427d8736625SAllan Jude 	geliboot = gctl_get_paraml(req, "geliboot", sizeof(*geliboot));
428d8736625SAllan Jude 	if (geliboot == NULL)
429d8736625SAllan Jude 		geliboot = &zero;
430d8736625SAllan Jude 	nogeliboot = gctl_get_paraml(req, "nogeliboot", sizeof(*nogeliboot));
431d8736625SAllan Jude 	if (nogeliboot == NULL)
432d8736625SAllan Jude 		nogeliboot = &zero;
433d8736625SAllan Jude 	if (*geliboot && *nogeliboot) {
434d8736625SAllan Jude 		gctl_error(req, "Options -g and -G are mutually exclusive.");
435d8736625SAllan Jude 		return;
436d8736625SAllan Jude 	}
437d8736625SAllan Jude 	if (*geliboot || *nogeliboot)
438d8736625SAllan Jude 		changed = 1;
439d8736625SAllan Jude 
4403453dc72SMariusz Zaborski 	displaypass = gctl_get_paraml(req, "displaypass", sizeof(*displaypass));
4413453dc72SMariusz Zaborski 	if (displaypass == NULL)
4423453dc72SMariusz Zaborski 		displaypass = &zero;
4433453dc72SMariusz Zaborski 	nodisplaypass = gctl_get_paraml(req, "nodisplaypass", sizeof(*nodisplaypass));
4443453dc72SMariusz Zaborski 	if (nodisplaypass == NULL)
4453453dc72SMariusz Zaborski 		nodisplaypass = &zero;
4463453dc72SMariusz Zaborski 	if (*displaypass && *nodisplaypass) {
4473453dc72SMariusz Zaborski 		gctl_error(req, "Options -d and -D are mutually exclusive.");
4483453dc72SMariusz Zaborski 		return;
4493453dc72SMariusz Zaborski 	}
4503453dc72SMariusz Zaborski 	if (*displaypass || *nodisplaypass)
4513453dc72SMariusz Zaborski 		changed = 1;
4523453dc72SMariusz Zaborski 
45346e34470SPawel Jakub Dawidek 	if (!changed) {
4548abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No option given.");
4558abd1ad1SPawel Jakub Dawidek 		return;
4568abd1ad1SPawel Jakub Dawidek 	}
4578abd1ad1SPawel Jakub Dawidek 
4588abd1ad1SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
4598abd1ad1SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
4608abd1ad1SPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
4618abd1ad1SPawel Jakub Dawidek 		if (prov == NULL) {
4628abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
4638abd1ad1SPawel Jakub Dawidek 			return;
4648abd1ad1SPawel Jakub Dawidek 		}
4658abd1ad1SPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
4668abd1ad1SPawel Jakub Dawidek 		if (sc == NULL) {
4678abd1ad1SPawel Jakub Dawidek 			/*
4688abd1ad1SPawel Jakub Dawidek 			 * We ignore not attached providers, userland part will
4698abd1ad1SPawel Jakub Dawidek 			 * take care of them.
4708abd1ad1SPawel Jakub Dawidek 			 */
4718abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "Skipping configuration of not attached "
4728abd1ad1SPawel Jakub Dawidek 			    "provider %s.", prov);
4738abd1ad1SPawel Jakub Dawidek 			continue;
4748abd1ad1SPawel Jakub Dawidek 		}
4758abd1ad1SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_RO) {
4768abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "Cannot change configuration of "
4778abd1ad1SPawel Jakub Dawidek 			    "read-only provider %s.", prov);
4788abd1ad1SPawel Jakub Dawidek 			continue;
4798abd1ad1SPawel Jakub Dawidek 		}
48046e34470SPawel Jakub Dawidek 
48146e34470SPawel Jakub Dawidek 		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
48246e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
48346e34470SPawel Jakub Dawidek 			    prov);
48446e34470SPawel Jakub Dawidek 			continue;
48546e34470SPawel Jakub Dawidek 		} else if (*noboot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
48646e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
48746e34470SPawel Jakub Dawidek 			    prov);
48846e34470SPawel Jakub Dawidek 			continue;
48946e34470SPawel Jakub Dawidek 		}
49046e34470SPawel Jakub Dawidek 
49146e34470SPawel Jakub Dawidek 		if (*notrim && (sc->sc_flags & G_ELI_FLAG_NODELETE)) {
49246e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag already configured for %s.",
49346e34470SPawel Jakub Dawidek 			    prov);
49446e34470SPawel Jakub Dawidek 			continue;
49546e34470SPawel Jakub Dawidek 		} else if (*trim && !(sc->sc_flags & G_ELI_FLAG_NODELETE)) {
49646e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag not configured for %s.",
49746e34470SPawel Jakub Dawidek 			    prov);
49846e34470SPawel Jakub Dawidek 			continue;
49946e34470SPawel Jakub Dawidek 		}
50046e34470SPawel Jakub Dawidek 
501d8736625SAllan Jude 		if (*geliboot && (sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
502d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag already configured for %s.",
503d8736625SAllan Jude 			    prov);
504d8736625SAllan Jude 			continue;
505d8736625SAllan Jude 		} else if (*nogeliboot && !(sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
506d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag not configured for %s.",
507d8736625SAllan Jude 			    prov);
508d8736625SAllan Jude 			continue;
509d8736625SAllan Jude 		}
510d8736625SAllan Jude 
5113453dc72SMariusz Zaborski 		if (*displaypass && (sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5123453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag already configured for %s.",
5133453dc72SMariusz Zaborski 			    prov);
5143453dc72SMariusz Zaborski 			continue;
5153453dc72SMariusz Zaborski 		} else if (*nodisplaypass &&
5163453dc72SMariusz Zaborski 		    !(sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5173453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag not configured for %s.",
5183453dc72SMariusz Zaborski 			    prov);
5193453dc72SMariusz Zaborski 			continue;
5203453dc72SMariusz Zaborski 		}
5213453dc72SMariusz Zaborski 
52246e34470SPawel Jakub Dawidek 		if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
52346e34470SPawel Jakub Dawidek 			/*
52446e34470SPawel Jakub Dawidek 			 * ONETIME providers don't write metadata to
52546e34470SPawel Jakub Dawidek 			 * disk, so don't try reading it.  This means
52646e34470SPawel Jakub Dawidek 			 * we're bit-flipping uninitialized memory in md
52746e34470SPawel Jakub Dawidek 			 * below, but that's OK; we don't do anything
52846e34470SPawel Jakub Dawidek 			 * with it later.
52946e34470SPawel Jakub Dawidek 			 */
5308abd1ad1SPawel Jakub Dawidek 			cp = LIST_FIRST(&sc->sc_geom->consumer);
5318abd1ad1SPawel Jakub Dawidek 			pp = cp->provider;
5328abd1ad1SPawel Jakub Dawidek 			error = g_eli_read_metadata(mp, pp, &md);
5338abd1ad1SPawel Jakub Dawidek 			if (error != 0) {
5348abd1ad1SPawel Jakub Dawidek 			    gctl_error(req,
5358abd1ad1SPawel Jakub Dawidek 				"Cannot read metadata from %s (error=%d).",
5368abd1ad1SPawel Jakub Dawidek 				prov, error);
5378abd1ad1SPawel Jakub Dawidek 			    continue;
5388abd1ad1SPawel Jakub Dawidek 			}
53946e34470SPawel Jakub Dawidek 		}
5408abd1ad1SPawel Jakub Dawidek 
5418abd1ad1SPawel Jakub Dawidek 		if (*boot) {
5428abd1ad1SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_BOOT;
5438abd1ad1SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_BOOT;
54446e34470SPawel Jakub Dawidek 		} else if (*noboot) {
5458abd1ad1SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_BOOT;
5468abd1ad1SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
5478abd1ad1SPawel Jakub Dawidek 		}
5488abd1ad1SPawel Jakub Dawidek 
54946e34470SPawel Jakub Dawidek 		if (*notrim) {
55046e34470SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_NODELETE;
55146e34470SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_NODELETE;
55246e34470SPawel Jakub Dawidek 		} else if (*trim) {
55346e34470SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_NODELETE;
55446e34470SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_NODELETE;
55546e34470SPawel Jakub Dawidek 		}
55646e34470SPawel Jakub Dawidek 
557d8736625SAllan Jude 		if (*geliboot) {
558d8736625SAllan Jude 			md.md_flags |= G_ELI_FLAG_GELIBOOT;
559d8736625SAllan Jude 			sc->sc_flags |= G_ELI_FLAG_GELIBOOT;
560d8736625SAllan Jude 		} else if (*nogeliboot) {
561d8736625SAllan Jude 			md.md_flags &= ~G_ELI_FLAG_GELIBOOT;
562d8736625SAllan Jude 			sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT;
563d8736625SAllan Jude 		}
564d8736625SAllan Jude 
5653453dc72SMariusz Zaborski 		if (*displaypass) {
5663453dc72SMariusz Zaborski 			md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5673453dc72SMariusz Zaborski 			sc->sc_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5683453dc72SMariusz Zaborski 		} else if (*nodisplaypass) {
5693453dc72SMariusz Zaborski 			md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5703453dc72SMariusz Zaborski 			sc->sc_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5713453dc72SMariusz Zaborski 		}
5723453dc72SMariusz Zaborski 
57346e34470SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
57446e34470SPawel Jakub Dawidek 			/* There's no metadata on disk so we are done here. */
57546e34470SPawel Jakub Dawidek 			continue;
57646e34470SPawel Jakub Dawidek 		}
57746e34470SPawel Jakub Dawidek 
5788abd1ad1SPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
5798abd1ad1SPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
5808abd1ad1SPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
5818abd1ad1SPawel Jakub Dawidek 		    pp->sectorsize);
5828abd1ad1SPawel Jakub Dawidek 		if (error != 0) {
5838abd1ad1SPawel Jakub Dawidek 			gctl_error(req,
5848abd1ad1SPawel Jakub Dawidek 			    "Cannot store metadata on %s (error=%d).",
5858abd1ad1SPawel Jakub Dawidek 			    prov, error);
5868abd1ad1SPawel Jakub Dawidek 		}
58739b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
58839b7ca45SAllan Jude 		explicit_bzero(sector, pp->sectorsize);
5898abd1ad1SPawel Jakub Dawidek 		free(sector, M_ELI);
5908abd1ad1SPawel Jakub Dawidek 	}
5918abd1ad1SPawel Jakub Dawidek }
5928abd1ad1SPawel Jakub Dawidek 
5938abd1ad1SPawel Jakub Dawidek static void
594c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
595c58794deSPawel Jakub Dawidek {
596c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
597c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
598c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
599c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
600c58794deSPawel Jakub Dawidek 	const char *name;
601c58794deSPawel Jakub Dawidek 	u_char *key, *mkeydst, *sector;
602c58794deSPawel Jakub Dawidek 	intmax_t *valp;
6037a5c26fcSPawel Jakub Dawidek 	int keysize, nkey, error;
604c58794deSPawel Jakub Dawidek 
605c58794deSPawel Jakub Dawidek 	g_topology_assert();
606c58794deSPawel Jakub Dawidek 
607c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
608c58794deSPawel Jakub Dawidek 	if (name == NULL) {
609c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
610c58794deSPawel Jakub Dawidek 		return;
611c58794deSPawel Jakub Dawidek 	}
61239b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
61339b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
61439b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
61539b7ca45SAllan Jude 		return;
61639b7ca45SAllan Jude 	}
617c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
618c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
619c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
620c58794deSPawel Jakub Dawidek 		return;
621c58794deSPawel Jakub Dawidek 	}
62285059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
62385059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot change keys for read-only provider.");
62485059016SPawel Jakub Dawidek 		return;
62585059016SPawel Jakub Dawidek 	}
626c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
627c58794deSPawel Jakub Dawidek 	pp = cp->provider;
628c58794deSPawel Jakub Dawidek 
629c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
630c58794deSPawel Jakub Dawidek 	if (error != 0) {
631c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
632c58794deSPawel Jakub Dawidek 		    name, error);
633c58794deSPawel Jakub Dawidek 		return;
634c58794deSPawel Jakub Dawidek 	}
635c58794deSPawel Jakub Dawidek 
636c58794deSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
637c58794deSPawel Jakub Dawidek 	if (valp == NULL) {
638c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keyno");
639c58794deSPawel Jakub Dawidek 		return;
640c58794deSPawel Jakub Dawidek 	}
641c58794deSPawel Jakub Dawidek 	if (*valp != -1)
642c58794deSPawel Jakub Dawidek 		nkey = *valp;
643c58794deSPawel Jakub Dawidek 	else
644c58794deSPawel Jakub Dawidek 		nkey = sc->sc_nkey;
645c58794deSPawel Jakub Dawidek 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
646c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keyno");
647c58794deSPawel Jakub Dawidek 		return;
648c58794deSPawel Jakub Dawidek 	}
649c58794deSPawel Jakub Dawidek 
6507a5c26fcSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
6517a5c26fcSPawel Jakub Dawidek 	if (valp == NULL) {
6527a5c26fcSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "iterations");
6537a5c26fcSPawel Jakub Dawidek 		return;
6547a5c26fcSPawel Jakub Dawidek 	}
6557a5c26fcSPawel Jakub Dawidek 	/* Check if iterations number should and can be changed. */
656d8880fd4SAlexander Motin 	if (*valp != -1 && md.md_iterations == -1) {
657d8880fd4SAlexander Motin 		md.md_iterations = *valp;
658d8880fd4SAlexander Motin 	} else if (*valp != -1 && *valp != md.md_iterations) {
6597a5c26fcSPawel Jakub Dawidek 		if (bitcount32(md.md_keys) != 1) {
6607a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "To be able to use '-i' option, only "
6617a5c26fcSPawel Jakub Dawidek 			    "one key can be defined.");
6627a5c26fcSPawel Jakub Dawidek 			return;
6637a5c26fcSPawel Jakub Dawidek 		}
6647a5c26fcSPawel Jakub Dawidek 		if (md.md_keys != (1 << nkey)) {
6657a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "Only already defined key can be "
6667a5c26fcSPawel Jakub Dawidek 			    "changed when '-i' option is used.");
6677a5c26fcSPawel Jakub Dawidek 			return;
6687a5c26fcSPawel Jakub Dawidek 		}
6697a5c26fcSPawel Jakub Dawidek 		md.md_iterations = *valp;
6707a5c26fcSPawel Jakub Dawidek 	}
6717a5c26fcSPawel Jakub Dawidek 
672c58794deSPawel Jakub Dawidek 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
673c58794deSPawel Jakub Dawidek 	md.md_keys |= (1 << nkey);
674c58794deSPawel Jakub Dawidek 
675eaa3b919SPawel Jakub Dawidek 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
676c58794deSPawel Jakub Dawidek 
677c58794deSPawel Jakub Dawidek 	/* Encrypt Master Key with the new key. */
678eaa3b919SPawel Jakub Dawidek 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
67939b7ca45SAllan Jude 	explicit_bzero(key, keysize);
680c58794deSPawel Jakub Dawidek 	if (error != 0) {
68139b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
682c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
683c58794deSPawel Jakub Dawidek 		return;
684c58794deSPawel Jakub Dawidek 	}
685c58794deSPawel Jakub Dawidek 
686c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
687c58794deSPawel Jakub Dawidek 	/* Store metadata with fresh key. */
688c58794deSPawel Jakub Dawidek 	eli_metadata_encode(&md, sector);
68939b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
690c58794deSPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
691c58794deSPawel Jakub Dawidek 	    pp->sectorsize);
69239b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
693c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
694c58794deSPawel Jakub Dawidek 	if (error != 0) {
695c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
696c58794deSPawel Jakub Dawidek 		    pp->name, error);
697c58794deSPawel Jakub Dawidek 		return;
698c58794deSPawel Jakub Dawidek 	}
699c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
700c58794deSPawel Jakub Dawidek }
701c58794deSPawel Jakub Dawidek 
702c58794deSPawel Jakub Dawidek static void
703c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
704c58794deSPawel Jakub Dawidek {
705c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
706c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
707c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
708c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
709c58794deSPawel Jakub Dawidek 	const char *name;
710c58794deSPawel Jakub Dawidek 	u_char *mkeydst, *sector;
711c58794deSPawel Jakub Dawidek 	intmax_t *valp;
712c58794deSPawel Jakub Dawidek 	size_t keysize;
713c58794deSPawel Jakub Dawidek 	int error, nkey, *all, *force;
714c58794deSPawel Jakub Dawidek 	u_int i;
715c58794deSPawel Jakub Dawidek 
716c58794deSPawel Jakub Dawidek 	g_topology_assert();
717c58794deSPawel Jakub Dawidek 
718c58794deSPawel Jakub Dawidek 	nkey = 0;	/* fixes causeless gcc warning */
719c58794deSPawel Jakub Dawidek 
720c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
721c58794deSPawel Jakub Dawidek 	if (name == NULL) {
722c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
723c58794deSPawel Jakub Dawidek 		return;
724c58794deSPawel Jakub Dawidek 	}
725c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
726c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
727c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
728c58794deSPawel Jakub Dawidek 		return;
729c58794deSPawel Jakub Dawidek 	}
73085059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
73185059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot delete keys for read-only provider.");
73285059016SPawel Jakub Dawidek 		return;
73385059016SPawel Jakub Dawidek 	}
734c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
735c58794deSPawel Jakub Dawidek 	pp = cp->provider;
736c58794deSPawel Jakub Dawidek 
737c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
738c58794deSPawel Jakub Dawidek 	if (error != 0) {
739c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
740c58794deSPawel Jakub Dawidek 		    name, error);
741c58794deSPawel Jakub Dawidek 		return;
742c58794deSPawel Jakub Dawidek 	}
743c58794deSPawel Jakub Dawidek 
744c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
745c58794deSPawel Jakub Dawidek 	if (all == NULL) {
746c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
747c58794deSPawel Jakub Dawidek 		return;
748c58794deSPawel Jakub Dawidek 	}
749c58794deSPawel Jakub Dawidek 
750c58794deSPawel Jakub Dawidek 	if (*all) {
751c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys;
752c58794deSPawel Jakub Dawidek 		keysize = sizeof(md.md_mkeys);
753c58794deSPawel Jakub Dawidek 	} else {
754c58794deSPawel Jakub Dawidek 		force = gctl_get_paraml(req, "force", sizeof(*force));
755c58794deSPawel Jakub Dawidek 		if (force == NULL) {
756c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "force");
757c58794deSPawel Jakub Dawidek 			return;
758c58794deSPawel Jakub Dawidek 		}
759c58794deSPawel Jakub Dawidek 
760c58794deSPawel Jakub Dawidek 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
761c58794deSPawel Jakub Dawidek 		if (valp == NULL) {
762c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "keyno");
763c58794deSPawel Jakub Dawidek 			return;
764c58794deSPawel Jakub Dawidek 		}
765c58794deSPawel Jakub Dawidek 		if (*valp != -1)
766c58794deSPawel Jakub Dawidek 			nkey = *valp;
767c58794deSPawel Jakub Dawidek 		else
768c58794deSPawel Jakub Dawidek 			nkey = sc->sc_nkey;
769c58794deSPawel Jakub Dawidek 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
770c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid '%s' argument.", "keyno");
771c58794deSPawel Jakub Dawidek 			return;
772c58794deSPawel Jakub Dawidek 		}
773c58794deSPawel Jakub Dawidek 		if (!(md.md_keys & (1 << nkey)) && !*force) {
774c58794deSPawel Jakub Dawidek 			gctl_error(req, "Master Key %u is not set.", nkey);
775c58794deSPawel Jakub Dawidek 			return;
776c58794deSPawel Jakub Dawidek 		}
777c58794deSPawel Jakub Dawidek 		md.md_keys &= ~(1 << nkey);
778c58794deSPawel Jakub Dawidek 		if (md.md_keys == 0 && !*force) {
779c58794deSPawel Jakub Dawidek 			gctl_error(req, "This is the last Master Key. Use '-f' "
780c58794deSPawel Jakub Dawidek 			    "flag if you really want to remove it.");
781c58794deSPawel Jakub Dawidek 			return;
782c58794deSPawel Jakub Dawidek 		}
783c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
784c58794deSPawel Jakub Dawidek 		keysize = G_ELI_MKEYLEN;
785c58794deSPawel Jakub Dawidek 	}
786c58794deSPawel Jakub Dawidek 
787c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
788c58794deSPawel Jakub Dawidek 	for (i = 0; i <= g_eli_overwrites; i++) {
789c58794deSPawel Jakub Dawidek 		if (i == g_eli_overwrites)
79039b7ca45SAllan Jude 			explicit_bzero(mkeydst, keysize);
791c58794deSPawel Jakub Dawidek 		else
792c58794deSPawel Jakub Dawidek 			arc4rand(mkeydst, keysize, 0);
793c58794deSPawel Jakub Dawidek 		/* Store metadata with destroyed key. */
794c58794deSPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
795c58794deSPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
796c58794deSPawel Jakub Dawidek 		    pp->sectorsize);
797c58794deSPawel Jakub Dawidek 		if (error != 0) {
798c58794deSPawel Jakub Dawidek 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
799c58794deSPawel Jakub Dawidek 			    "(error=%d).", pp->name, error);
800c58794deSPawel Jakub Dawidek 		}
801f0256e71SPawel Jakub Dawidek 		/*
802f0256e71SPawel Jakub Dawidek 		 * Flush write cache so we don't overwrite data N times in cache
803f0256e71SPawel Jakub Dawidek 		 * and only once on disk.
804f0256e71SPawel Jakub Dawidek 		 */
805350e8df8SPawel Jakub Dawidek 		(void)g_io_flush(cp);
806c58794deSPawel Jakub Dawidek 	}
80739b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
80839b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
809c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
810c58794deSPawel Jakub Dawidek 	if (*all)
811c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
812c58794deSPawel Jakub Dawidek 	else
813c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
814c58794deSPawel Jakub Dawidek }
815c58794deSPawel Jakub Dawidek 
8160d2f5a4eSPawel Jakub Dawidek static void
8170d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
8185ad4a7c7SPawel Jakub Dawidek {
8195ad4a7c7SPawel Jakub Dawidek 	struct g_eli_worker *wr;
8205ad4a7c7SPawel Jakub Dawidek 
8215ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8225ad4a7c7SPawel Jakub Dawidek 
8230d2f5a4eSPawel Jakub Dawidek 	KASSERT(sc != NULL, ("NULL sc"));
8240d2f5a4eSPawel Jakub Dawidek 
8250d2f5a4eSPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
8260d2f5a4eSPawel Jakub Dawidek 		gctl_error(req,
8270d2f5a4eSPawel Jakub Dawidek 		    "Device %s is using one-time key, suspend not supported.",
8280d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8290d2f5a4eSPawel Jakub Dawidek 		return;
8300d2f5a4eSPawel Jakub Dawidek 	}
8315ad4a7c7SPawel Jakub Dawidek 
8325ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
8335ad4a7c7SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
8345ad4a7c7SPawel Jakub Dawidek 		mtx_unlock(&sc->sc_queue_mtx);
8350d2f5a4eSPawel Jakub Dawidek 		gctl_error(req, "Device %s already suspended.",
8360d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8370d2f5a4eSPawel Jakub Dawidek 		return;
8385ad4a7c7SPawel Jakub Dawidek 	}
8395ad4a7c7SPawel Jakub Dawidek 	sc->sc_flags |= G_ELI_FLAG_SUSPEND;
8405ad4a7c7SPawel Jakub Dawidek 	wakeup(sc);
8415ad4a7c7SPawel Jakub Dawidek 	for (;;) {
8425ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH(wr, &sc->sc_workers, w_next) {
8435ad4a7c7SPawel Jakub Dawidek 			if (wr->w_active)
8445ad4a7c7SPawel Jakub Dawidek 				break;
8455ad4a7c7SPawel Jakub Dawidek 		}
8465ad4a7c7SPawel Jakub Dawidek 		if (wr == NULL)
8475ad4a7c7SPawel Jakub Dawidek 			break;
8485ad4a7c7SPawel Jakub Dawidek 		/* Not all threads suspended. */
8495ad4a7c7SPawel Jakub Dawidek 		msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
8505ad4a7c7SPawel Jakub Dawidek 		    "geli:suspend", 0);
8515ad4a7c7SPawel Jakub Dawidek 	}
8525ad4a7c7SPawel Jakub Dawidek 	/*
8535ad4a7c7SPawel Jakub Dawidek 	 * Clear sensitive data on suspend, they will be recovered on resume.
8545ad4a7c7SPawel Jakub Dawidek 	 */
85539b7ca45SAllan Jude 	explicit_bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
8561e09ff3dSPawel Jakub Dawidek 	g_eli_key_destroy(sc);
85739b7ca45SAllan Jude 	explicit_bzero(sc->sc_akey, sizeof(sc->sc_akey));
85839b7ca45SAllan Jude 	explicit_bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
85939b7ca45SAllan Jude 	explicit_bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
86039b7ca45SAllan Jude 	explicit_bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
8615ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
8620d2f5a4eSPawel Jakub Dawidek 	G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
8635ad4a7c7SPawel Jakub Dawidek }
8645ad4a7c7SPawel Jakub Dawidek 
8655ad4a7c7SPawel Jakub Dawidek static void
8665ad4a7c7SPawel Jakub Dawidek g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
8675ad4a7c7SPawel Jakub Dawidek {
8685ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
8695ad4a7c7SPawel Jakub Dawidek 	int *all, *nargs;
8705ad4a7c7SPawel Jakub Dawidek 
8715ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8725ad4a7c7SPawel Jakub Dawidek 
8735ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
8745ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
8755ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
8765ad4a7c7SPawel Jakub Dawidek 		return;
8775ad4a7c7SPawel Jakub Dawidek 	}
8785ad4a7c7SPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
8795ad4a7c7SPawel Jakub Dawidek 	if (all == NULL) {
8805ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
8815ad4a7c7SPawel Jakub Dawidek 		return;
8825ad4a7c7SPawel Jakub Dawidek 	}
8835ad4a7c7SPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
8845ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
8855ad4a7c7SPawel Jakub Dawidek 		return;
8865ad4a7c7SPawel Jakub Dawidek 	}
8875ad4a7c7SPawel Jakub Dawidek 
8885ad4a7c7SPawel Jakub Dawidek 	if (*all) {
8895ad4a7c7SPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
8905ad4a7c7SPawel Jakub Dawidek 
8915ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
8925ad4a7c7SPawel Jakub Dawidek 			sc = gp->softc;
8930d2f5a4eSPawel Jakub Dawidek 			if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
8940d2f5a4eSPawel Jakub Dawidek 				G_ELI_DEBUG(0,
8950d2f5a4eSPawel Jakub Dawidek 				    "Device %s is using one-time key, suspend not supported, skipping.",
8960d2f5a4eSPawel Jakub Dawidek 				    sc->sc_name);
8975ad4a7c7SPawel Jakub Dawidek 				continue;
8980d2f5a4eSPawel Jakub Dawidek 			}
8990d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9005ad4a7c7SPawel Jakub Dawidek 		}
9015ad4a7c7SPawel Jakub Dawidek 	} else {
9025ad4a7c7SPawel Jakub Dawidek 		const char *prov;
9035ad4a7c7SPawel Jakub Dawidek 		char param[16];
9045ad4a7c7SPawel Jakub Dawidek 		int i;
9055ad4a7c7SPawel Jakub Dawidek 
9065ad4a7c7SPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
9075ad4a7c7SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
9085ad4a7c7SPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
9095ad4a7c7SPawel Jakub Dawidek 			if (prov == NULL) {
9105ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
9115ad4a7c7SPawel Jakub Dawidek 				continue;
9125ad4a7c7SPawel Jakub Dawidek 			}
9135ad4a7c7SPawel Jakub Dawidek 
9145ad4a7c7SPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
9155ad4a7c7SPawel Jakub Dawidek 			if (sc == NULL) {
9165ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
9175ad4a7c7SPawel Jakub Dawidek 				continue;
9185ad4a7c7SPawel Jakub Dawidek 			}
9190d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9205ad4a7c7SPawel Jakub Dawidek 		}
9215ad4a7c7SPawel Jakub Dawidek 	}
9225ad4a7c7SPawel Jakub Dawidek }
9235ad4a7c7SPawel Jakub Dawidek 
9245ad4a7c7SPawel Jakub Dawidek static void
9255ad4a7c7SPawel Jakub Dawidek g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
9265ad4a7c7SPawel Jakub Dawidek {
9275ad4a7c7SPawel Jakub Dawidek 	struct g_eli_metadata md;
9285ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
9295ad4a7c7SPawel Jakub Dawidek 	struct g_provider *pp;
9305ad4a7c7SPawel Jakub Dawidek 	struct g_consumer *cp;
9315ad4a7c7SPawel Jakub Dawidek 	const char *name;
9325ad4a7c7SPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
9335ad4a7c7SPawel Jakub Dawidek 	int *nargs, keysize, error;
9345ad4a7c7SPawel Jakub Dawidek 	u_int nkey;
9355ad4a7c7SPawel Jakub Dawidek 
9365ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
9375ad4a7c7SPawel Jakub Dawidek 
9385ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
9395ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
9405ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
9415ad4a7c7SPawel Jakub Dawidek 		return;
9425ad4a7c7SPawel Jakub Dawidek 	}
9435ad4a7c7SPawel Jakub Dawidek 	if (*nargs != 1) {
9445ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
9455ad4a7c7SPawel Jakub Dawidek 		return;
9465ad4a7c7SPawel Jakub Dawidek 	}
9475ad4a7c7SPawel Jakub Dawidek 
9485ad4a7c7SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
9495ad4a7c7SPawel Jakub Dawidek 	if (name == NULL) {
9505ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
9515ad4a7c7SPawel Jakub Dawidek 		return;
9525ad4a7c7SPawel Jakub Dawidek 	}
95339b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
95439b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
95539b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
95639b7ca45SAllan Jude 		return;
95739b7ca45SAllan Jude 	}
9585ad4a7c7SPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
9595ad4a7c7SPawel Jakub Dawidek 	if (sc == NULL) {
9605ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
9615ad4a7c7SPawel Jakub Dawidek 		return;
9625ad4a7c7SPawel Jakub Dawidek 	}
9635ad4a7c7SPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
9645ad4a7c7SPawel Jakub Dawidek 	pp = cp->provider;
9655ad4a7c7SPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
9665ad4a7c7SPawel Jakub Dawidek 	if (error != 0) {
9675ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
9685ad4a7c7SPawel Jakub Dawidek 		    name, error);
9695ad4a7c7SPawel Jakub Dawidek 		return;
9705ad4a7c7SPawel Jakub Dawidek 	}
9715ad4a7c7SPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
97239b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9735ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
9745ad4a7c7SPawel Jakub Dawidek 		return;
9755ad4a7c7SPawel Jakub Dawidek 	}
9765ad4a7c7SPawel Jakub Dawidek 
9775ad4a7c7SPawel Jakub Dawidek 	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
97839b7ca45SAllan Jude 	explicit_bzero(key, keysize);
9795ad4a7c7SPawel Jakub Dawidek 	if (error == -1) {
98039b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9815ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
9825ad4a7c7SPawel Jakub Dawidek 		return;
9835ad4a7c7SPawel Jakub Dawidek 	} else if (error > 0) {
98439b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9855ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
9865ad4a7c7SPawel Jakub Dawidek 		    pp->name, error);
9875ad4a7c7SPawel Jakub Dawidek 		return;
9885ad4a7c7SPawel Jakub Dawidek 	}
9895ad4a7c7SPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
9905ad4a7c7SPawel Jakub Dawidek 
9915ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
9922f2d7830SPawel Jakub Dawidek 	if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
9932f2d7830SPawel Jakub Dawidek 		gctl_error(req, "Device %s is not suspended.", name);
9942f2d7830SPawel Jakub Dawidek 	else {
9955ad4a7c7SPawel Jakub Dawidek 		/* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
9965ad4a7c7SPawel Jakub Dawidek 		g_eli_mkey_propagate(sc, mkey);
9975ad4a7c7SPawel Jakub Dawidek 		sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
9982f2d7830SPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Resumed %s.", pp->name);
9992f2d7830SPawel Jakub Dawidek 		wakeup(sc);
10002f2d7830SPawel Jakub Dawidek 	}
10015ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
100239b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
100339b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
10045ad4a7c7SPawel Jakub Dawidek }
10055ad4a7c7SPawel Jakub Dawidek 
10065ad4a7c7SPawel Jakub Dawidek static int
1007c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc)
1008c58794deSPawel Jakub Dawidek {
1009c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
1010c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
101185059016SPawel Jakub Dawidek 	int error = 0;
1012c58794deSPawel Jakub Dawidek 
1013c58794deSPawel Jakub Dawidek 	g_topology_assert();
1014c58794deSPawel Jakub Dawidek 
1015c58794deSPawel Jakub Dawidek 	if (sc == NULL)
1016c58794deSPawel Jakub Dawidek 		return (ENOENT);
1017c58794deSPawel Jakub Dawidek 
1018c58794deSPawel Jakub Dawidek 	pp = LIST_FIRST(&sc->sc_geom->provider);
1019c58794deSPawel Jakub Dawidek 	g_error_provider(pp, ENXIO);
1020c58794deSPawel Jakub Dawidek 
1021c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
1022c58794deSPawel Jakub Dawidek 	pp = cp->provider;
1023c58794deSPawel Jakub Dawidek 
102485059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
102585059016SPawel Jakub Dawidek 		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
102685059016SPawel Jakub Dawidek 		    "provider: %s.", pp->name);
102785059016SPawel Jakub Dawidek 	} else {
102885059016SPawel Jakub Dawidek 		u_char *sector;
102985059016SPawel Jakub Dawidek 		u_int i;
103085059016SPawel Jakub Dawidek 		int err;
103185059016SPawel Jakub Dawidek 
1032c58794deSPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
1033c58794deSPawel Jakub Dawidek 		for (i = 0; i <= g_eli_overwrites; i++) {
1034c58794deSPawel Jakub Dawidek 			if (i == g_eli_overwrites)
1035c58794deSPawel Jakub Dawidek 				bzero(sector, pp->sectorsize);
1036c58794deSPawel Jakub Dawidek 			else
1037c58794deSPawel Jakub Dawidek 				arc4rand(sector, pp->sectorsize, 0);
103885059016SPawel Jakub Dawidek 			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
103985059016SPawel Jakub Dawidek 			    sector, pp->sectorsize);
1040c58794deSPawel Jakub Dawidek 			if (err != 0) {
1041c58794deSPawel Jakub Dawidek 				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
1042c58794deSPawel Jakub Dawidek 				    "(error=%d).", pp->name, err);
1043c58794deSPawel Jakub Dawidek 				if (error == 0)
1044c58794deSPawel Jakub Dawidek 					error = err;
1045c58794deSPawel Jakub Dawidek 			}
1046350e8df8SPawel Jakub Dawidek 			/*
1047350e8df8SPawel Jakub Dawidek 			 * Flush write cache so we don't overwrite data N times
1048350e8df8SPawel Jakub Dawidek 			 * in cache and only once on disk.
1049350e8df8SPawel Jakub Dawidek 			 */
1050350e8df8SPawel Jakub Dawidek 			(void)g_io_flush(cp);
1051c58794deSPawel Jakub Dawidek 		}
1052c58794deSPawel Jakub Dawidek 		free(sector, M_ELI);
105385059016SPawel Jakub Dawidek 	}
1054c58794deSPawel Jakub Dawidek 	if (error == 0)
1055c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
10565ad4a7c7SPawel Jakub Dawidek 	g_eli_destroy(sc, TRUE);
1057c58794deSPawel Jakub Dawidek 	return (error);
1058c58794deSPawel Jakub Dawidek }
1059c58794deSPawel Jakub Dawidek 
1060c58794deSPawel Jakub Dawidek static void
1061c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
1062c58794deSPawel Jakub Dawidek {
1063c58794deSPawel Jakub Dawidek 	int *all, *nargs;
1064c58794deSPawel Jakub Dawidek 	int error;
1065c58794deSPawel Jakub Dawidek 
1066c58794deSPawel Jakub Dawidek 	g_topology_assert();
1067c58794deSPawel Jakub Dawidek 
1068c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1069c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
1070c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
1071c58794deSPawel Jakub Dawidek 		return;
1072c58794deSPawel Jakub Dawidek 	}
1073c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
1074c58794deSPawel Jakub Dawidek 	if (all == NULL) {
1075c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
1076c58794deSPawel Jakub Dawidek 		return;
1077c58794deSPawel Jakub Dawidek 	}
1078c58794deSPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
1079c58794deSPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
1080c58794deSPawel Jakub Dawidek 		return;
1081c58794deSPawel Jakub Dawidek 	}
1082c58794deSPawel Jakub Dawidek 
1083c58794deSPawel Jakub Dawidek 	if (*all) {
1084c58794deSPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
1085c58794deSPawel Jakub Dawidek 
1086c58794deSPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
1087c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(gp->softc);
1088c58794deSPawel Jakub Dawidek 			if (error != 0)
1089c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1090c58794deSPawel Jakub Dawidek 		}
1091c58794deSPawel Jakub Dawidek 	} else {
1092c58794deSPawel Jakub Dawidek 		struct g_eli_softc *sc;
1093c58794deSPawel Jakub Dawidek 		const char *prov;
1094c58794deSPawel Jakub Dawidek 		char param[16];
1095c58794deSPawel Jakub Dawidek 		int i;
1096c58794deSPawel Jakub Dawidek 
1097c58794deSPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
10987d54b385SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
1099c58794deSPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
1100b5f30223SPawel Jakub Dawidek 			if (prov == NULL) {
1101b5f30223SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
1102b5f30223SPawel Jakub Dawidek 				continue;
1103b5f30223SPawel Jakub Dawidek 			}
1104c58794deSPawel Jakub Dawidek 
1105c58794deSPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
1106c58794deSPawel Jakub Dawidek 			if (sc == NULL) {
11077d54b385SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
1108c58794deSPawel Jakub Dawidek 				continue;
1109c58794deSPawel Jakub Dawidek 			}
1110c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(sc);
1111c58794deSPawel Jakub Dawidek 			if (error != 0)
1112c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1113c58794deSPawel Jakub Dawidek 		}
1114c58794deSPawel Jakub Dawidek 	}
1115c58794deSPawel Jakub Dawidek }
1116c58794deSPawel Jakub Dawidek 
1117c58794deSPawel Jakub Dawidek void
1118c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1119c58794deSPawel Jakub Dawidek {
1120c58794deSPawel Jakub Dawidek 	uint32_t *version;
1121c58794deSPawel Jakub Dawidek 
1122c58794deSPawel Jakub Dawidek 	g_topology_assert();
1123c58794deSPawel Jakub Dawidek 
1124c58794deSPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
1125c58794deSPawel Jakub Dawidek 	if (version == NULL) {
1126c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
1127c58794deSPawel Jakub Dawidek 		return;
1128c58794deSPawel Jakub Dawidek 	}
1129731adc86SPawel Jakub Dawidek 	while (*version != G_ELI_VERSION) {
1130731adc86SPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_06 &&
1131731adc86SPawel Jakub Dawidek 		    *version == G_ELI_VERSION_05) {
1132731adc86SPawel Jakub Dawidek 			/* Compatible. */
1133731adc86SPawel Jakub Dawidek 			break;
1134731adc86SPawel Jakub Dawidek 		}
1135457bbc4fSPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_07 &&
1136457bbc4fSPawel Jakub Dawidek 		    (*version == G_ELI_VERSION_05 ||
1137457bbc4fSPawel Jakub Dawidek 		     *version == G_ELI_VERSION_06)) {
1138457bbc4fSPawel Jakub Dawidek 			/* Compatible. */
1139457bbc4fSPawel Jakub Dawidek 			break;
1140457bbc4fSPawel Jakub Dawidek 		}
1141c58794deSPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
1142c58794deSPawel Jakub Dawidek 		return;
1143c58794deSPawel Jakub Dawidek 	}
1144c58794deSPawel Jakub Dawidek 
1145c58794deSPawel Jakub Dawidek 	if (strcmp(verb, "attach") == 0)
1146c58794deSPawel Jakub Dawidek 		g_eli_ctl_attach(req, mp);
1147c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
1148c58794deSPawel Jakub Dawidek 		g_eli_ctl_detach(req, mp);
1149c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "onetime") == 0)
1150c58794deSPawel Jakub Dawidek 		g_eli_ctl_onetime(req, mp);
11518abd1ad1SPawel Jakub Dawidek 	else if (strcmp(verb, "configure") == 0)
11528abd1ad1SPawel Jakub Dawidek 		g_eli_ctl_configure(req, mp);
1153c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "setkey") == 0)
1154c58794deSPawel Jakub Dawidek 		g_eli_ctl_setkey(req, mp);
1155c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "delkey") == 0)
1156c58794deSPawel Jakub Dawidek 		g_eli_ctl_delkey(req, mp);
11575ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "suspend") == 0)
11585ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_suspend(req, mp);
11595ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "resume") == 0)
11605ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_resume(req, mp);
1161c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "kill") == 0)
1162c58794deSPawel Jakub Dawidek 		g_eli_ctl_kill(req, mp);
1163c58794deSPawel Jakub Dawidek 	else
1164c58794deSPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
1165c58794deSPawel Jakub Dawidek }
1166