xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision d87366259473c73ec259d5072f429a85e1b7c63d)
1c58794deSPawel Jakub Dawidek /*-
21e09ff3dSPawel Jakub Dawidek  * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
3c58794deSPawel Jakub Dawidek  * All rights reserved.
4c58794deSPawel Jakub Dawidek  *
5c58794deSPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
6c58794deSPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
7c58794deSPawel Jakub Dawidek  * are met:
8c58794deSPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
9c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
10c58794deSPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
11c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
12c58794deSPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
13c58794deSPawel Jakub Dawidek  *
14c58794deSPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15c58794deSPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c58794deSPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c58794deSPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18c58794deSPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c58794deSPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c58794deSPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c58794deSPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c58794deSPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c58794deSPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c58794deSPawel Jakub Dawidek  * SUCH DAMAGE.
25c58794deSPawel Jakub Dawidek  */
26c58794deSPawel Jakub Dawidek 
27c58794deSPawel Jakub Dawidek #include <sys/cdefs.h>
28c58794deSPawel Jakub Dawidek __FBSDID("$FreeBSD$");
29c58794deSPawel Jakub Dawidek 
30c58794deSPawel Jakub Dawidek #include <sys/param.h>
31c58794deSPawel Jakub Dawidek #include <sys/systm.h>
32c58794deSPawel Jakub Dawidek #include <sys/kernel.h>
33c58794deSPawel Jakub Dawidek #include <sys/module.h>
34c58794deSPawel Jakub Dawidek #include <sys/lock.h>
35c58794deSPawel Jakub Dawidek #include <sys/mutex.h>
36c58794deSPawel Jakub Dawidek #include <sys/bio.h>
37c58794deSPawel Jakub Dawidek #include <sys/sysctl.h>
38c58794deSPawel Jakub Dawidek #include <sys/malloc.h>
39c58794deSPawel Jakub Dawidek #include <sys/kthread.h>
40c58794deSPawel Jakub Dawidek #include <sys/proc.h>
41c58794deSPawel Jakub Dawidek #include <sys/sched.h>
42c58794deSPawel Jakub Dawidek #include <sys/uio.h>
43c58794deSPawel Jakub Dawidek 
44c58794deSPawel Jakub Dawidek #include <vm/uma.h>
45c58794deSPawel Jakub Dawidek 
46c58794deSPawel Jakub Dawidek #include <geom/geom.h>
47c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h>
48c58794deSPawel Jakub Dawidek 
49c58794deSPawel Jakub Dawidek 
50c58794deSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI);
51c58794deSPawel Jakub Dawidek 
52c58794deSPawel Jakub Dawidek 
53c58794deSPawel Jakub Dawidek static void
54c58794deSPawel Jakub Dawidek g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
55c58794deSPawel Jakub Dawidek {
56c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
57c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
58c58794deSPawel Jakub Dawidek 	const char *name;
59c58794deSPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
6085059016SPawel Jakub Dawidek 	int *nargs, *detach, *readonly;
61c58794deSPawel Jakub Dawidek 	int keysize, error;
62c58794deSPawel Jakub Dawidek 	u_int nkey;
63c58794deSPawel Jakub Dawidek 
64c58794deSPawel Jakub Dawidek 	g_topology_assert();
65c58794deSPawel Jakub Dawidek 
66c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
67c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
68c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
69c58794deSPawel Jakub Dawidek 		return;
70c58794deSPawel Jakub Dawidek 	}
71c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
72c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
73c58794deSPawel Jakub Dawidek 		return;
74c58794deSPawel Jakub Dawidek 	}
75c58794deSPawel Jakub Dawidek 
76c58794deSPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
77c58794deSPawel Jakub Dawidek 	if (detach == NULL) {
78c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "detach");
79c58794deSPawel Jakub Dawidek 		return;
80c58794deSPawel Jakub Dawidek 	}
81c58794deSPawel Jakub Dawidek 
8285059016SPawel Jakub Dawidek 	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
8385059016SPawel Jakub Dawidek 	if (readonly == NULL) {
8485059016SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "readonly");
8585059016SPawel Jakub Dawidek 		return;
8685059016SPawel Jakub Dawidek 	}
8785059016SPawel Jakub Dawidek 
88c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
89c58794deSPawel Jakub Dawidek 	if (name == NULL) {
90c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
91c58794deSPawel Jakub Dawidek 		return;
92c58794deSPawel Jakub Dawidek 	}
93c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
94c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
95c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
96c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
97c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
98c58794deSPawel Jakub Dawidek 		return;
99c58794deSPawel Jakub Dawidek 	}
100c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
101c58794deSPawel Jakub Dawidek 	if (error != 0) {
102c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
103c58794deSPawel Jakub Dawidek 		    name, error);
104c58794deSPawel Jakub Dawidek 		return;
105c58794deSPawel Jakub Dawidek 	}
106c58794deSPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
107c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
108c58794deSPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
109c58794deSPawel Jakub Dawidek 		return;
110c58794deSPawel Jakub Dawidek 	}
111c58794deSPawel Jakub Dawidek 
112c58794deSPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
113c58794deSPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
114c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
115c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
116c58794deSPawel Jakub Dawidek 		return;
117c58794deSPawel Jakub Dawidek 	}
118c58794deSPawel Jakub Dawidek 
119c58794deSPawel Jakub Dawidek 	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
120c58794deSPawel Jakub Dawidek 	bzero(key, keysize);
121c58794deSPawel Jakub Dawidek 	if (error == -1) {
122c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
123c58794deSPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
124c58794deSPawel Jakub Dawidek 		return;
125c58794deSPawel Jakub Dawidek 	} else if (error > 0) {
126c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
127c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
128c58794deSPawel Jakub Dawidek 		    pp->name, error);
129c58794deSPawel Jakub Dawidek 		return;
130c58794deSPawel Jakub Dawidek 	}
131c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
132c58794deSPawel Jakub Dawidek 
13385059016SPawel Jakub Dawidek 	if (*detach && *readonly) {
13485059016SPawel Jakub Dawidek 		bzero(&md, sizeof(md));
135dec53cddSPawel Jakub Dawidek 		gctl_error(req, "Options -d and -r are mutually exclusive.");
13685059016SPawel Jakub Dawidek 		return;
13785059016SPawel Jakub Dawidek 	}
138c58794deSPawel Jakub Dawidek 	if (*detach)
139c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
14085059016SPawel Jakub Dawidek 	if (*readonly)
14185059016SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_RO;
142c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, nkey);
143c58794deSPawel Jakub Dawidek 	bzero(mkey, sizeof(mkey));
144c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
145c58794deSPawel Jakub Dawidek }
146c58794deSPawel Jakub Dawidek 
147c58794deSPawel Jakub Dawidek static struct g_eli_softc *
148c58794deSPawel Jakub Dawidek g_eli_find_device(struct g_class *mp, const char *prov)
149c58794deSPawel Jakub Dawidek {
150c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
151c58794deSPawel Jakub Dawidek 	struct g_geom *gp;
152c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
153c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
154c58794deSPawel Jakub Dawidek 
155c58794deSPawel Jakub Dawidek 	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
156c58794deSPawel Jakub Dawidek 		prov += strlen("/dev/");
157c58794deSPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
158c58794deSPawel Jakub Dawidek 		sc = gp->softc;
159c58794deSPawel Jakub Dawidek 		if (sc == NULL)
160c58794deSPawel Jakub Dawidek 			continue;
161c58794deSPawel Jakub Dawidek 		pp = LIST_FIRST(&gp->provider);
162c58794deSPawel Jakub Dawidek 		if (pp != NULL && strcmp(pp->name, prov) == 0)
163c58794deSPawel Jakub Dawidek 			return (sc);
164c58794deSPawel Jakub Dawidek 		cp = LIST_FIRST(&gp->consumer);
165c58794deSPawel Jakub Dawidek 		if (cp != NULL && cp->provider != NULL &&
166c58794deSPawel Jakub Dawidek 		    strcmp(cp->provider->name, prov) == 0) {
167c58794deSPawel Jakub Dawidek 			return (sc);
168c58794deSPawel Jakub Dawidek 		}
169c58794deSPawel Jakub Dawidek 	}
170c58794deSPawel Jakub Dawidek 	return (NULL);
171c58794deSPawel Jakub Dawidek }
172c58794deSPawel Jakub Dawidek 
173c58794deSPawel Jakub Dawidek static void
174c58794deSPawel Jakub Dawidek g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
175c58794deSPawel Jakub Dawidek {
176c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
177c58794deSPawel Jakub Dawidek 	int *force, *last, *nargs, error;
178c58794deSPawel Jakub Dawidek 	const char *prov;
179c58794deSPawel Jakub Dawidek 	char param[16];
1807d54b385SPawel Jakub Dawidek 	int i;
181c58794deSPawel Jakub Dawidek 
182c58794deSPawel Jakub Dawidek 	g_topology_assert();
183c58794deSPawel Jakub Dawidek 
184c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
185c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
186c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
187c58794deSPawel Jakub Dawidek 		return;
188c58794deSPawel Jakub Dawidek 	}
189c58794deSPawel Jakub Dawidek 	if (*nargs <= 0) {
190c58794deSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
191c58794deSPawel Jakub Dawidek 		return;
192c58794deSPawel Jakub Dawidek 	}
193c58794deSPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
194c58794deSPawel Jakub Dawidek 	if (force == NULL) {
195c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "force");
196c58794deSPawel Jakub Dawidek 		return;
197c58794deSPawel Jakub Dawidek 	}
198c58794deSPawel Jakub Dawidek 	last = gctl_get_paraml(req, "last", sizeof(*last));
199c58794deSPawel Jakub Dawidek 	if (last == NULL) {
200c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "last");
201c58794deSPawel Jakub Dawidek 		return;
202c58794deSPawel Jakub Dawidek 	}
203c58794deSPawel Jakub Dawidek 
2047d54b385SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
2057d54b385SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
206c58794deSPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
207c58794deSPawel Jakub Dawidek 		if (prov == NULL) {
2087d54b385SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
209c58794deSPawel Jakub Dawidek 			return;
210c58794deSPawel Jakub Dawidek 		}
211c58794deSPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
212c58794deSPawel Jakub Dawidek 		if (sc == NULL) {
213c58794deSPawel Jakub Dawidek 			gctl_error(req, "No such device: %s.", prov);
214c58794deSPawel Jakub Dawidek 			return;
215c58794deSPawel Jakub Dawidek 		}
216c58794deSPawel Jakub Dawidek 		if (*last) {
217c58794deSPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
218c58794deSPawel Jakub Dawidek 			sc->sc_geom->access = g_eli_access;
219c58794deSPawel Jakub Dawidek 		} else {
2205ad4a7c7SPawel Jakub Dawidek 			error = g_eli_destroy(sc, *force ? TRUE : FALSE);
221c58794deSPawel Jakub Dawidek 			if (error != 0) {
222c58794deSPawel Jakub Dawidek 				gctl_error(req,
223c58794deSPawel Jakub Dawidek 				    "Cannot destroy device %s (error=%d).",
224c58794deSPawel Jakub Dawidek 				    sc->sc_name, error);
225c58794deSPawel Jakub Dawidek 				return;
226c58794deSPawel Jakub Dawidek 			}
227c58794deSPawel Jakub Dawidek 		}
228c58794deSPawel Jakub Dawidek 	}
229c58794deSPawel Jakub Dawidek }
230c58794deSPawel Jakub Dawidek 
231c58794deSPawel Jakub Dawidek static void
232c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
233c58794deSPawel Jakub Dawidek {
234c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
235c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
236c58794deSPawel Jakub Dawidek 	const char *name;
237c58794deSPawel Jakub Dawidek 	intmax_t *keylen, *sectorsize;
238c58794deSPawel Jakub Dawidek 	u_char mkey[G_ELI_DATAIVKEYLEN];
23946e34470SPawel Jakub Dawidek 	int *nargs, *detach, *notrim;
240c58794deSPawel Jakub Dawidek 
241c58794deSPawel Jakub Dawidek 	g_topology_assert();
242c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
243c58794deSPawel Jakub Dawidek 
244c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
245c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
246c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
247c58794deSPawel Jakub Dawidek 		return;
248c58794deSPawel Jakub Dawidek 	}
249c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
250c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
251c58794deSPawel Jakub Dawidek 		return;
252c58794deSPawel Jakub Dawidek 	}
253c58794deSPawel Jakub Dawidek 
254c58794deSPawel Jakub Dawidek 	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
255c58794deSPawel Jakub Dawidek 	md.md_version = G_ELI_VERSION;
256c58794deSPawel Jakub Dawidek 	md.md_flags |= G_ELI_FLAG_ONETIME;
25746e34470SPawel Jakub Dawidek 
25846e34470SPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
25946e34470SPawel Jakub Dawidek 	if (detach != NULL && *detach)
260c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
26146e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
26246e34470SPawel Jakub Dawidek 	if (notrim != NULL && *notrim)
26346e34470SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_NODELETE;
264c58794deSPawel Jakub Dawidek 
265c84efdcaSPawel Jakub Dawidek 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
266eaa3b919SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "aalgo");
267c58794deSPawel Jakub Dawidek 	if (name == NULL) {
268eaa3b919SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "aalgo");
269c58794deSPawel Jakub Dawidek 		return;
270c58794deSPawel Jakub Dawidek 	}
271a478ea74SPawel Jakub Dawidek 	if (*name != '\0') {
272eaa3b919SPawel Jakub Dawidek 		md.md_aalgo = g_eli_str2aalgo(name);
273c84efdcaSPawel Jakub Dawidek 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
274c84efdcaSPawel Jakub Dawidek 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
275eaa3b919SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_AUTH;
276c84efdcaSPawel Jakub Dawidek 		} else {
277c84efdcaSPawel Jakub Dawidek 			/*
278c84efdcaSPawel Jakub Dawidek 			 * For backward compatibility, check if the -a option
279c84efdcaSPawel Jakub Dawidek 			 * was used to provide encryption algorithm.
280c84efdcaSPawel Jakub Dawidek 			 */
281c84efdcaSPawel Jakub Dawidek 			md.md_ealgo = g_eli_str2ealgo(name);
282c84efdcaSPawel Jakub Dawidek 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
283c84efdcaSPawel Jakub Dawidek 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
284c84efdcaSPawel Jakub Dawidek 				gctl_error(req,
285c84efdcaSPawel Jakub Dawidek 				    "Invalid authentication algorithm.");
286c84efdcaSPawel Jakub Dawidek 				return;
287c84efdcaSPawel Jakub Dawidek 			} else {
288c84efdcaSPawel Jakub Dawidek 				gctl_error(req, "warning: The -e option, not "
289c84efdcaSPawel Jakub Dawidek 				    "the -a option is now used to specify "
290c84efdcaSPawel Jakub Dawidek 				    "encryption algorithm to use.");
291c84efdcaSPawel Jakub Dawidek 			}
292c84efdcaSPawel Jakub Dawidek 		}
293eaa3b919SPawel Jakub Dawidek 	}
294eaa3b919SPawel Jakub Dawidek 
295c84efdcaSPawel Jakub Dawidek 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
296c84efdcaSPawel Jakub Dawidek 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
297eaa3b919SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, "ealgo");
298eaa3b919SPawel Jakub Dawidek 		if (name == NULL) {
299eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "ealgo");
300eaa3b919SPawel Jakub Dawidek 			return;
301eaa3b919SPawel Jakub Dawidek 		}
302eaa3b919SPawel Jakub Dawidek 		md.md_ealgo = g_eli_str2ealgo(name);
303eaa3b919SPawel Jakub Dawidek 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
304eaa3b919SPawel Jakub Dawidek 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
305eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "Invalid encryption algorithm.");
306c58794deSPawel Jakub Dawidek 			return;
307c58794deSPawel Jakub Dawidek 		}
308c84efdcaSPawel Jakub Dawidek 	}
309c58794deSPawel Jakub Dawidek 
310c58794deSPawel Jakub Dawidek 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
311c58794deSPawel Jakub Dawidek 	if (keylen == NULL) {
312c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keylen");
313c58794deSPawel Jakub Dawidek 		return;
314c58794deSPawel Jakub Dawidek 	}
315eaa3b919SPawel Jakub Dawidek 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
316c58794deSPawel Jakub Dawidek 	if (md.md_keylen == 0) {
317c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keylen");
318c58794deSPawel Jakub Dawidek 		return;
319c58794deSPawel Jakub Dawidek 	}
320c58794deSPawel Jakub Dawidek 
321c58794deSPawel Jakub Dawidek 	/* Not important here. */
322c58794deSPawel Jakub Dawidek 	md.md_provsize = 0;
323c58794deSPawel Jakub Dawidek 	/* Not important here. */
324c58794deSPawel Jakub Dawidek 	bzero(md.md_salt, sizeof(md.md_salt));
325c58794deSPawel Jakub Dawidek 
326c58794deSPawel Jakub Dawidek 	md.md_keys = 0x01;
327c58794deSPawel Jakub Dawidek 	arc4rand(mkey, sizeof(mkey), 0);
328c58794deSPawel Jakub Dawidek 
329c58794deSPawel Jakub Dawidek 	/* Not important here. */
330c58794deSPawel Jakub Dawidek 	bzero(md.md_hash, sizeof(md.md_hash));
331c58794deSPawel Jakub Dawidek 
332c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
333c58794deSPawel Jakub Dawidek 	if (name == NULL) {
334c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
335c58794deSPawel Jakub Dawidek 		return;
336c58794deSPawel Jakub Dawidek 	}
337c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
338c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
339c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
340c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
341c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
342c58794deSPawel Jakub Dawidek 		return;
343c58794deSPawel Jakub Dawidek 	}
344c58794deSPawel Jakub Dawidek 
345c58794deSPawel Jakub Dawidek 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
346c58794deSPawel Jakub Dawidek 	if (sectorsize == NULL) {
347c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "sectorsize");
348c58794deSPawel Jakub Dawidek 		return;
349c58794deSPawel Jakub Dawidek 	}
350c58794deSPawel Jakub Dawidek 	if (*sectorsize == 0)
351c58794deSPawel Jakub Dawidek 		md.md_sectorsize = pp->sectorsize;
352c58794deSPawel Jakub Dawidek 	else {
353c58794deSPawel Jakub Dawidek 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
354c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid sector size.");
355c58794deSPawel Jakub Dawidek 			return;
356c58794deSPawel Jakub Dawidek 		}
35797a669a3SPawel Jakub Dawidek 		if (*sectorsize > PAGE_SIZE) {
35897a669a3SPawel Jakub Dawidek 			gctl_error(req, "warning: Using sectorsize bigger than "
35997a669a3SPawel Jakub Dawidek 			    "the page size!");
36097a669a3SPawel Jakub Dawidek 		}
361c58794deSPawel Jakub Dawidek 		md.md_sectorsize = *sectorsize;
362c58794deSPawel Jakub Dawidek 	}
363c58794deSPawel Jakub Dawidek 
364c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, -1);
365c58794deSPawel Jakub Dawidek 	bzero(mkey, sizeof(mkey));
366c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
367c58794deSPawel Jakub Dawidek }
368c58794deSPawel Jakub Dawidek 
369c58794deSPawel Jakub Dawidek static void
3708abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
3718abd1ad1SPawel Jakub Dawidek {
3728abd1ad1SPawel Jakub Dawidek 	struct g_eli_softc *sc;
3738abd1ad1SPawel Jakub Dawidek 	struct g_eli_metadata md;
3748abd1ad1SPawel Jakub Dawidek 	struct g_provider *pp;
3758abd1ad1SPawel Jakub Dawidek 	struct g_consumer *cp;
3768abd1ad1SPawel Jakub Dawidek 	char param[16];
3778abd1ad1SPawel Jakub Dawidek 	const char *prov;
3788abd1ad1SPawel Jakub Dawidek 	u_char *sector;
379*d8736625SAllan Jude 	int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot;
38046e34470SPawel Jakub Dawidek 	int zero, error, changed;
3818abd1ad1SPawel Jakub Dawidek 	u_int i;
3828abd1ad1SPawel Jakub Dawidek 
3838abd1ad1SPawel Jakub Dawidek 	g_topology_assert();
3848abd1ad1SPawel Jakub Dawidek 
38546e34470SPawel Jakub Dawidek 	changed = 0;
38646e34470SPawel Jakub Dawidek 	zero = 0;
38746e34470SPawel Jakub Dawidek 
3888abd1ad1SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
3898abd1ad1SPawel Jakub Dawidek 	if (nargs == NULL) {
3908abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
3918abd1ad1SPawel Jakub Dawidek 		return;
3928abd1ad1SPawel Jakub Dawidek 	}
3938abd1ad1SPawel Jakub Dawidek 	if (*nargs <= 0) {
3948abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
3958abd1ad1SPawel Jakub Dawidek 		return;
3968abd1ad1SPawel Jakub Dawidek 	}
3978abd1ad1SPawel Jakub Dawidek 
3988abd1ad1SPawel Jakub Dawidek 	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
39946e34470SPawel Jakub Dawidek 	if (boot == NULL)
40046e34470SPawel Jakub Dawidek 		boot = &zero;
4018abd1ad1SPawel Jakub Dawidek 	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
40246e34470SPawel Jakub Dawidek 	if (noboot == NULL)
40346e34470SPawel Jakub Dawidek 		noboot = &zero;
4048abd1ad1SPawel Jakub Dawidek 	if (*boot && *noboot) {
4058abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Options -b and -B are mutually exclusive.");
4068abd1ad1SPawel Jakub Dawidek 		return;
4078abd1ad1SPawel Jakub Dawidek 	}
40846e34470SPawel Jakub Dawidek 	if (*boot || *noboot)
40946e34470SPawel Jakub Dawidek 		changed = 1;
41046e34470SPawel Jakub Dawidek 
41146e34470SPawel Jakub Dawidek 	trim = gctl_get_paraml(req, "trim", sizeof(*trim));
41246e34470SPawel Jakub Dawidek 	if (trim == NULL)
41346e34470SPawel Jakub Dawidek 		trim = &zero;
41446e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
41546e34470SPawel Jakub Dawidek 	if (notrim == NULL)
41646e34470SPawel Jakub Dawidek 		notrim = &zero;
41746e34470SPawel Jakub Dawidek 	if (*trim && *notrim) {
41846e34470SPawel Jakub Dawidek 		gctl_error(req, "Options -t and -T are mutually exclusive.");
41946e34470SPawel Jakub Dawidek 		return;
42046e34470SPawel Jakub Dawidek 	}
42146e34470SPawel Jakub Dawidek 	if (*trim || *notrim)
42246e34470SPawel Jakub Dawidek 		changed = 1;
42346e34470SPawel Jakub Dawidek 
424*d8736625SAllan Jude 	geliboot = gctl_get_paraml(req, "geliboot", sizeof(*geliboot));
425*d8736625SAllan Jude 	if (geliboot == NULL)
426*d8736625SAllan Jude 		geliboot = &zero;
427*d8736625SAllan Jude 	nogeliboot = gctl_get_paraml(req, "nogeliboot", sizeof(*nogeliboot));
428*d8736625SAllan Jude 	if (nogeliboot == NULL)
429*d8736625SAllan Jude 		nogeliboot = &zero;
430*d8736625SAllan Jude 	if (*geliboot && *nogeliboot) {
431*d8736625SAllan Jude 		gctl_error(req, "Options -g and -G are mutually exclusive.");
432*d8736625SAllan Jude 		return;
433*d8736625SAllan Jude 	}
434*d8736625SAllan Jude 	if (*geliboot || *nogeliboot)
435*d8736625SAllan Jude 		changed = 1;
436*d8736625SAllan Jude 
43746e34470SPawel Jakub Dawidek 	if (!changed) {
4388abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No option given.");
4398abd1ad1SPawel Jakub Dawidek 		return;
4408abd1ad1SPawel Jakub Dawidek 	}
4418abd1ad1SPawel Jakub Dawidek 
4428abd1ad1SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
4438abd1ad1SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
4448abd1ad1SPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
4458abd1ad1SPawel Jakub Dawidek 		if (prov == NULL) {
4468abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
4478abd1ad1SPawel Jakub Dawidek 			return;
4488abd1ad1SPawel Jakub Dawidek 		}
4498abd1ad1SPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
4508abd1ad1SPawel Jakub Dawidek 		if (sc == NULL) {
4518abd1ad1SPawel Jakub Dawidek 			/*
4528abd1ad1SPawel Jakub Dawidek 			 * We ignore not attached providers, userland part will
4538abd1ad1SPawel Jakub Dawidek 			 * take care of them.
4548abd1ad1SPawel Jakub Dawidek 			 */
4558abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "Skipping configuration of not attached "
4568abd1ad1SPawel Jakub Dawidek 			    "provider %s.", prov);
4578abd1ad1SPawel Jakub Dawidek 			continue;
4588abd1ad1SPawel Jakub Dawidek 		}
4598abd1ad1SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_RO) {
4608abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "Cannot change configuration of "
4618abd1ad1SPawel Jakub Dawidek 			    "read-only provider %s.", prov);
4628abd1ad1SPawel Jakub Dawidek 			continue;
4638abd1ad1SPawel Jakub Dawidek 		}
46446e34470SPawel Jakub Dawidek 
46546e34470SPawel Jakub Dawidek 		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
46646e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
46746e34470SPawel Jakub Dawidek 			    prov);
46846e34470SPawel Jakub Dawidek 			continue;
46946e34470SPawel Jakub Dawidek 		} else if (*noboot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
47046e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
47146e34470SPawel Jakub Dawidek 			    prov);
47246e34470SPawel Jakub Dawidek 			continue;
47346e34470SPawel Jakub Dawidek 		}
47446e34470SPawel Jakub Dawidek 
47546e34470SPawel Jakub Dawidek 		if (*notrim && (sc->sc_flags & G_ELI_FLAG_NODELETE)) {
47646e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag already configured for %s.",
47746e34470SPawel Jakub Dawidek 			    prov);
47846e34470SPawel Jakub Dawidek 			continue;
47946e34470SPawel Jakub Dawidek 		} else if (*trim && !(sc->sc_flags & G_ELI_FLAG_NODELETE)) {
48046e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag not configured for %s.",
48146e34470SPawel Jakub Dawidek 			    prov);
48246e34470SPawel Jakub Dawidek 			continue;
48346e34470SPawel Jakub Dawidek 		}
48446e34470SPawel Jakub Dawidek 
485*d8736625SAllan Jude 		if (*geliboot && (sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
486*d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag already configured for %s.",
487*d8736625SAllan Jude 			    prov);
488*d8736625SAllan Jude 			continue;
489*d8736625SAllan Jude 		} else if (*nogeliboot && !(sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
490*d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag not configured for %s.",
491*d8736625SAllan Jude 			    prov);
492*d8736625SAllan Jude 			continue;
493*d8736625SAllan Jude 		}
494*d8736625SAllan Jude 
49546e34470SPawel Jakub Dawidek 		if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
49646e34470SPawel Jakub Dawidek 			/*
49746e34470SPawel Jakub Dawidek 			 * ONETIME providers don't write metadata to
49846e34470SPawel Jakub Dawidek 			 * disk, so don't try reading it.  This means
49946e34470SPawel Jakub Dawidek 			 * we're bit-flipping uninitialized memory in md
50046e34470SPawel Jakub Dawidek 			 * below, but that's OK; we don't do anything
50146e34470SPawel Jakub Dawidek 			 * with it later.
50246e34470SPawel Jakub Dawidek 			 */
5038abd1ad1SPawel Jakub Dawidek 			cp = LIST_FIRST(&sc->sc_geom->consumer);
5048abd1ad1SPawel Jakub Dawidek 			pp = cp->provider;
5058abd1ad1SPawel Jakub Dawidek 			error = g_eli_read_metadata(mp, pp, &md);
5068abd1ad1SPawel Jakub Dawidek 			if (error != 0) {
5078abd1ad1SPawel Jakub Dawidek 			    gctl_error(req,
5088abd1ad1SPawel Jakub Dawidek 				"Cannot read metadata from %s (error=%d).",
5098abd1ad1SPawel Jakub Dawidek 				prov, error);
5108abd1ad1SPawel Jakub Dawidek 			    continue;
5118abd1ad1SPawel Jakub Dawidek 			}
51246e34470SPawel Jakub Dawidek 		}
5138abd1ad1SPawel Jakub Dawidek 
5148abd1ad1SPawel Jakub Dawidek 		if (*boot) {
5158abd1ad1SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_BOOT;
5168abd1ad1SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_BOOT;
51746e34470SPawel Jakub Dawidek 		} else if (*noboot) {
5188abd1ad1SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_BOOT;
5198abd1ad1SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
5208abd1ad1SPawel Jakub Dawidek 		}
5218abd1ad1SPawel Jakub Dawidek 
52246e34470SPawel Jakub Dawidek 		if (*notrim) {
52346e34470SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_NODELETE;
52446e34470SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_NODELETE;
52546e34470SPawel Jakub Dawidek 		} else if (*trim) {
52646e34470SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_NODELETE;
52746e34470SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_NODELETE;
52846e34470SPawel Jakub Dawidek 		}
52946e34470SPawel Jakub Dawidek 
530*d8736625SAllan Jude 		if (*geliboot) {
531*d8736625SAllan Jude 			md.md_flags |= G_ELI_FLAG_GELIBOOT;
532*d8736625SAllan Jude 			sc->sc_flags |= G_ELI_FLAG_GELIBOOT;
533*d8736625SAllan Jude 		} else if (*nogeliboot) {
534*d8736625SAllan Jude 			md.md_flags &= ~G_ELI_FLAG_GELIBOOT;
535*d8736625SAllan Jude 			sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT;
536*d8736625SAllan Jude 		}
537*d8736625SAllan Jude 
53846e34470SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
53946e34470SPawel Jakub Dawidek 			/* There's no metadata on disk so we are done here. */
54046e34470SPawel Jakub Dawidek 			continue;
54146e34470SPawel Jakub Dawidek 		}
54246e34470SPawel Jakub Dawidek 
5438abd1ad1SPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
5448abd1ad1SPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
5458abd1ad1SPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
5468abd1ad1SPawel Jakub Dawidek 		    pp->sectorsize);
5478abd1ad1SPawel Jakub Dawidek 		if (error != 0) {
5488abd1ad1SPawel Jakub Dawidek 			gctl_error(req,
5498abd1ad1SPawel Jakub Dawidek 			    "Cannot store metadata on %s (error=%d).",
5508abd1ad1SPawel Jakub Dawidek 			    prov, error);
5518abd1ad1SPawel Jakub Dawidek 		}
5528abd1ad1SPawel Jakub Dawidek 		bzero(&md, sizeof(md));
5537ac2e588SXin LI 		bzero(sector, pp->sectorsize);
5548abd1ad1SPawel Jakub Dawidek 		free(sector, M_ELI);
5558abd1ad1SPawel Jakub Dawidek 	}
5568abd1ad1SPawel Jakub Dawidek }
5578abd1ad1SPawel Jakub Dawidek 
5588abd1ad1SPawel Jakub Dawidek static void
559c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
560c58794deSPawel Jakub Dawidek {
561c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
562c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
563c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
564c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
565c58794deSPawel Jakub Dawidek 	const char *name;
566c58794deSPawel Jakub Dawidek 	u_char *key, *mkeydst, *sector;
567c58794deSPawel Jakub Dawidek 	intmax_t *valp;
5687a5c26fcSPawel Jakub Dawidek 	int keysize, nkey, error;
569c58794deSPawel Jakub Dawidek 
570c58794deSPawel Jakub Dawidek 	g_topology_assert();
571c58794deSPawel Jakub Dawidek 
572c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
573c58794deSPawel Jakub Dawidek 	if (name == NULL) {
574c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
575c58794deSPawel Jakub Dawidek 		return;
576c58794deSPawel Jakub Dawidek 	}
577c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
578c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
579c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
580c58794deSPawel Jakub Dawidek 		return;
581c58794deSPawel Jakub Dawidek 	}
58285059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
58385059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot change keys for read-only provider.");
58485059016SPawel Jakub Dawidek 		return;
58585059016SPawel Jakub Dawidek 	}
586c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
587c58794deSPawel Jakub Dawidek 	pp = cp->provider;
588c58794deSPawel Jakub Dawidek 
589c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
590c58794deSPawel Jakub Dawidek 	if (error != 0) {
591c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
592c58794deSPawel Jakub Dawidek 		    name, error);
593c58794deSPawel Jakub Dawidek 		return;
594c58794deSPawel Jakub Dawidek 	}
595c58794deSPawel Jakub Dawidek 
596c58794deSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
597c58794deSPawel Jakub Dawidek 	if (valp == NULL) {
598c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keyno");
599c58794deSPawel Jakub Dawidek 		return;
600c58794deSPawel Jakub Dawidek 	}
601c58794deSPawel Jakub Dawidek 	if (*valp != -1)
602c58794deSPawel Jakub Dawidek 		nkey = *valp;
603c58794deSPawel Jakub Dawidek 	else
604c58794deSPawel Jakub Dawidek 		nkey = sc->sc_nkey;
605c58794deSPawel Jakub Dawidek 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
606c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keyno");
607c58794deSPawel Jakub Dawidek 		return;
608c58794deSPawel Jakub Dawidek 	}
609c58794deSPawel Jakub Dawidek 
6107a5c26fcSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
6117a5c26fcSPawel Jakub Dawidek 	if (valp == NULL) {
6127a5c26fcSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "iterations");
6137a5c26fcSPawel Jakub Dawidek 		return;
6147a5c26fcSPawel Jakub Dawidek 	}
6157a5c26fcSPawel Jakub Dawidek 	/* Check if iterations number should and can be changed. */
6167a5c26fcSPawel Jakub Dawidek 	if (*valp != -1) {
6177a5c26fcSPawel Jakub Dawidek 		if (bitcount32(md.md_keys) != 1) {
6187a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "To be able to use '-i' option, only "
6197a5c26fcSPawel Jakub Dawidek 			    "one key can be defined.");
6207a5c26fcSPawel Jakub Dawidek 			return;
6217a5c26fcSPawel Jakub Dawidek 		}
6227a5c26fcSPawel Jakub Dawidek 		if (md.md_keys != (1 << nkey)) {
6237a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "Only already defined key can be "
6247a5c26fcSPawel Jakub Dawidek 			    "changed when '-i' option is used.");
6257a5c26fcSPawel Jakub Dawidek 			return;
6267a5c26fcSPawel Jakub Dawidek 		}
6277a5c26fcSPawel Jakub Dawidek 		md.md_iterations = *valp;
6287a5c26fcSPawel Jakub Dawidek 	}
6297a5c26fcSPawel Jakub Dawidek 
630c58794deSPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
631c58794deSPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
632c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
633c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
634c58794deSPawel Jakub Dawidek 		return;
635c58794deSPawel Jakub Dawidek 	}
636c58794deSPawel Jakub Dawidek 
637c58794deSPawel Jakub Dawidek 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
638c58794deSPawel Jakub Dawidek 	md.md_keys |= (1 << nkey);
639c58794deSPawel Jakub Dawidek 
640eaa3b919SPawel Jakub Dawidek 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
641c58794deSPawel Jakub Dawidek 
642c58794deSPawel Jakub Dawidek 	/* Encrypt Master Key with the new key. */
643eaa3b919SPawel Jakub Dawidek 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
6447ac2e588SXin LI 	bzero(key, keysize);
645c58794deSPawel Jakub Dawidek 	if (error != 0) {
646c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
647c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
648c58794deSPawel Jakub Dawidek 		return;
649c58794deSPawel Jakub Dawidek 	}
650c58794deSPawel Jakub Dawidek 
651c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
652c58794deSPawel Jakub Dawidek 	/* Store metadata with fresh key. */
653c58794deSPawel Jakub Dawidek 	eli_metadata_encode(&md, sector);
654c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
655c58794deSPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
656c58794deSPawel Jakub Dawidek 	    pp->sectorsize);
6577ac2e588SXin LI 	bzero(sector, pp->sectorsize);
658c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
659c58794deSPawel Jakub Dawidek 	if (error != 0) {
660c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
661c58794deSPawel Jakub Dawidek 		    pp->name, error);
662c58794deSPawel Jakub Dawidek 		return;
663c58794deSPawel Jakub Dawidek 	}
664c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
665c58794deSPawel Jakub Dawidek }
666c58794deSPawel Jakub Dawidek 
667c58794deSPawel Jakub Dawidek static void
668c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
669c58794deSPawel Jakub Dawidek {
670c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
671c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
672c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
673c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
674c58794deSPawel Jakub Dawidek 	const char *name;
675c58794deSPawel Jakub Dawidek 	u_char *mkeydst, *sector;
676c58794deSPawel Jakub Dawidek 	intmax_t *valp;
677c58794deSPawel Jakub Dawidek 	size_t keysize;
678c58794deSPawel Jakub Dawidek 	int error, nkey, *all, *force;
679c58794deSPawel Jakub Dawidek 	u_int i;
680c58794deSPawel Jakub Dawidek 
681c58794deSPawel Jakub Dawidek 	g_topology_assert();
682c58794deSPawel Jakub Dawidek 
683c58794deSPawel Jakub Dawidek 	nkey = 0;	/* fixes causeless gcc warning */
684c58794deSPawel Jakub Dawidek 
685c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
686c58794deSPawel Jakub Dawidek 	if (name == NULL) {
687c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
688c58794deSPawel Jakub Dawidek 		return;
689c58794deSPawel Jakub Dawidek 	}
690c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
691c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
692c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
693c58794deSPawel Jakub Dawidek 		return;
694c58794deSPawel Jakub Dawidek 	}
69585059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
69685059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot delete keys for read-only provider.");
69785059016SPawel Jakub Dawidek 		return;
69885059016SPawel Jakub Dawidek 	}
699c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
700c58794deSPawel Jakub Dawidek 	pp = cp->provider;
701c58794deSPawel Jakub Dawidek 
702c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
703c58794deSPawel Jakub Dawidek 	if (error != 0) {
704c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
705c58794deSPawel Jakub Dawidek 		    name, error);
706c58794deSPawel Jakub Dawidek 		return;
707c58794deSPawel Jakub Dawidek 	}
708c58794deSPawel Jakub Dawidek 
709c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
710c58794deSPawel Jakub Dawidek 	if (all == NULL) {
711c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
712c58794deSPawel Jakub Dawidek 		return;
713c58794deSPawel Jakub Dawidek 	}
714c58794deSPawel Jakub Dawidek 
715c58794deSPawel Jakub Dawidek 	if (*all) {
716c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys;
717c58794deSPawel Jakub Dawidek 		keysize = sizeof(md.md_mkeys);
718c58794deSPawel Jakub Dawidek 	} else {
719c58794deSPawel Jakub Dawidek 		force = gctl_get_paraml(req, "force", sizeof(*force));
720c58794deSPawel Jakub Dawidek 		if (force == NULL) {
721c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "force");
722c58794deSPawel Jakub Dawidek 			return;
723c58794deSPawel Jakub Dawidek 		}
724c58794deSPawel Jakub Dawidek 
725c58794deSPawel Jakub Dawidek 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
726c58794deSPawel Jakub Dawidek 		if (valp == NULL) {
727c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "keyno");
728c58794deSPawel Jakub Dawidek 			return;
729c58794deSPawel Jakub Dawidek 		}
730c58794deSPawel Jakub Dawidek 		if (*valp != -1)
731c58794deSPawel Jakub Dawidek 			nkey = *valp;
732c58794deSPawel Jakub Dawidek 		else
733c58794deSPawel Jakub Dawidek 			nkey = sc->sc_nkey;
734c58794deSPawel Jakub Dawidek 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
735c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid '%s' argument.", "keyno");
736c58794deSPawel Jakub Dawidek 			return;
737c58794deSPawel Jakub Dawidek 		}
738c58794deSPawel Jakub Dawidek 		if (!(md.md_keys & (1 << nkey)) && !*force) {
739c58794deSPawel Jakub Dawidek 			gctl_error(req, "Master Key %u is not set.", nkey);
740c58794deSPawel Jakub Dawidek 			return;
741c58794deSPawel Jakub Dawidek 		}
742c58794deSPawel Jakub Dawidek 		md.md_keys &= ~(1 << nkey);
743c58794deSPawel Jakub Dawidek 		if (md.md_keys == 0 && !*force) {
744c58794deSPawel Jakub Dawidek 			gctl_error(req, "This is the last Master Key. Use '-f' "
745c58794deSPawel Jakub Dawidek 			    "flag if you really want to remove it.");
746c58794deSPawel Jakub Dawidek 			return;
747c58794deSPawel Jakub Dawidek 		}
748c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
749c58794deSPawel Jakub Dawidek 		keysize = G_ELI_MKEYLEN;
750c58794deSPawel Jakub Dawidek 	}
751c58794deSPawel Jakub Dawidek 
752c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
753c58794deSPawel Jakub Dawidek 	for (i = 0; i <= g_eli_overwrites; i++) {
754c58794deSPawel Jakub Dawidek 		if (i == g_eli_overwrites)
755c58794deSPawel Jakub Dawidek 			bzero(mkeydst, keysize);
756c58794deSPawel Jakub Dawidek 		else
757c58794deSPawel Jakub Dawidek 			arc4rand(mkeydst, keysize, 0);
758c58794deSPawel Jakub Dawidek 		/* Store metadata with destroyed key. */
759c58794deSPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
760c58794deSPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
761c58794deSPawel Jakub Dawidek 		    pp->sectorsize);
762c58794deSPawel Jakub Dawidek 		if (error != 0) {
763c58794deSPawel Jakub Dawidek 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
764c58794deSPawel Jakub Dawidek 			    "(error=%d).", pp->name, error);
765c58794deSPawel Jakub Dawidek 		}
766f0256e71SPawel Jakub Dawidek 		/*
767f0256e71SPawel Jakub Dawidek 		 * Flush write cache so we don't overwrite data N times in cache
768f0256e71SPawel Jakub Dawidek 		 * and only once on disk.
769f0256e71SPawel Jakub Dawidek 		 */
770350e8df8SPawel Jakub Dawidek 		(void)g_io_flush(cp);
771c58794deSPawel Jakub Dawidek 	}
772c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
7737ac2e588SXin LI 	bzero(sector, pp->sectorsize);
774c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
775c58794deSPawel Jakub Dawidek 	if (*all)
776c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
777c58794deSPawel Jakub Dawidek 	else
778c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
779c58794deSPawel Jakub Dawidek }
780c58794deSPawel Jakub Dawidek 
7810d2f5a4eSPawel Jakub Dawidek static void
7820d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
7835ad4a7c7SPawel Jakub Dawidek {
7845ad4a7c7SPawel Jakub Dawidek 	struct g_eli_worker *wr;
7855ad4a7c7SPawel Jakub Dawidek 
7865ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
7875ad4a7c7SPawel Jakub Dawidek 
7880d2f5a4eSPawel Jakub Dawidek 	KASSERT(sc != NULL, ("NULL sc"));
7890d2f5a4eSPawel Jakub Dawidek 
7900d2f5a4eSPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
7910d2f5a4eSPawel Jakub Dawidek 		gctl_error(req,
7920d2f5a4eSPawel Jakub Dawidek 		    "Device %s is using one-time key, suspend not supported.",
7930d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
7940d2f5a4eSPawel Jakub Dawidek 		return;
7950d2f5a4eSPawel Jakub Dawidek 	}
7965ad4a7c7SPawel Jakub Dawidek 
7975ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
7985ad4a7c7SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
7995ad4a7c7SPawel Jakub Dawidek 		mtx_unlock(&sc->sc_queue_mtx);
8000d2f5a4eSPawel Jakub Dawidek 		gctl_error(req, "Device %s already suspended.",
8010d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8020d2f5a4eSPawel Jakub Dawidek 		return;
8035ad4a7c7SPawel Jakub Dawidek 	}
8045ad4a7c7SPawel Jakub Dawidek 	sc->sc_flags |= G_ELI_FLAG_SUSPEND;
8055ad4a7c7SPawel Jakub Dawidek 	wakeup(sc);
8065ad4a7c7SPawel Jakub Dawidek 	for (;;) {
8075ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH(wr, &sc->sc_workers, w_next) {
8085ad4a7c7SPawel Jakub Dawidek 			if (wr->w_active)
8095ad4a7c7SPawel Jakub Dawidek 				break;
8105ad4a7c7SPawel Jakub Dawidek 		}
8115ad4a7c7SPawel Jakub Dawidek 		if (wr == NULL)
8125ad4a7c7SPawel Jakub Dawidek 			break;
8135ad4a7c7SPawel Jakub Dawidek 		/* Not all threads suspended. */
8145ad4a7c7SPawel Jakub Dawidek 		msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
8155ad4a7c7SPawel Jakub Dawidek 		    "geli:suspend", 0);
8165ad4a7c7SPawel Jakub Dawidek 	}
8175ad4a7c7SPawel Jakub Dawidek 	/*
8185ad4a7c7SPawel Jakub Dawidek 	 * Clear sensitive data on suspend, they will be recovered on resume.
8195ad4a7c7SPawel Jakub Dawidek 	 */
8205ad4a7c7SPawel Jakub Dawidek 	bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
8211e09ff3dSPawel Jakub Dawidek 	g_eli_key_destroy(sc);
8225ad4a7c7SPawel Jakub Dawidek 	bzero(sc->sc_akey, sizeof(sc->sc_akey));
8235ad4a7c7SPawel Jakub Dawidek 	bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
8245ad4a7c7SPawel Jakub Dawidek 	bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
8255ad4a7c7SPawel Jakub Dawidek 	bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
8265ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
8270d2f5a4eSPawel Jakub Dawidek 	G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
8285ad4a7c7SPawel Jakub Dawidek }
8295ad4a7c7SPawel Jakub Dawidek 
8305ad4a7c7SPawel Jakub Dawidek static void
8315ad4a7c7SPawel Jakub Dawidek g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
8325ad4a7c7SPawel Jakub Dawidek {
8335ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
8345ad4a7c7SPawel Jakub Dawidek 	int *all, *nargs;
8355ad4a7c7SPawel Jakub Dawidek 
8365ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8375ad4a7c7SPawel Jakub Dawidek 
8385ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
8395ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
8405ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
8415ad4a7c7SPawel Jakub Dawidek 		return;
8425ad4a7c7SPawel Jakub Dawidek 	}
8435ad4a7c7SPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
8445ad4a7c7SPawel Jakub Dawidek 	if (all == NULL) {
8455ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
8465ad4a7c7SPawel Jakub Dawidek 		return;
8475ad4a7c7SPawel Jakub Dawidek 	}
8485ad4a7c7SPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
8495ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
8505ad4a7c7SPawel Jakub Dawidek 		return;
8515ad4a7c7SPawel Jakub Dawidek 	}
8525ad4a7c7SPawel Jakub Dawidek 
8535ad4a7c7SPawel Jakub Dawidek 	if (*all) {
8545ad4a7c7SPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
8555ad4a7c7SPawel Jakub Dawidek 
8565ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
8575ad4a7c7SPawel Jakub Dawidek 			sc = gp->softc;
8580d2f5a4eSPawel Jakub Dawidek 			if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
8590d2f5a4eSPawel Jakub Dawidek 				G_ELI_DEBUG(0,
8600d2f5a4eSPawel Jakub Dawidek 				    "Device %s is using one-time key, suspend not supported, skipping.",
8610d2f5a4eSPawel Jakub Dawidek 				    sc->sc_name);
8625ad4a7c7SPawel Jakub Dawidek 				continue;
8630d2f5a4eSPawel Jakub Dawidek 			}
8640d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
8655ad4a7c7SPawel Jakub Dawidek 		}
8665ad4a7c7SPawel Jakub Dawidek 	} else {
8675ad4a7c7SPawel Jakub Dawidek 		const char *prov;
8685ad4a7c7SPawel Jakub Dawidek 		char param[16];
8695ad4a7c7SPawel Jakub Dawidek 		int i;
8705ad4a7c7SPawel Jakub Dawidek 
8715ad4a7c7SPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
8725ad4a7c7SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
8735ad4a7c7SPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
8745ad4a7c7SPawel Jakub Dawidek 			if (prov == NULL) {
8755ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
8765ad4a7c7SPawel Jakub Dawidek 				continue;
8775ad4a7c7SPawel Jakub Dawidek 			}
8785ad4a7c7SPawel Jakub Dawidek 
8795ad4a7c7SPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
8805ad4a7c7SPawel Jakub Dawidek 			if (sc == NULL) {
8815ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
8825ad4a7c7SPawel Jakub Dawidek 				continue;
8835ad4a7c7SPawel Jakub Dawidek 			}
8840d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
8855ad4a7c7SPawel Jakub Dawidek 		}
8865ad4a7c7SPawel Jakub Dawidek 	}
8875ad4a7c7SPawel Jakub Dawidek }
8885ad4a7c7SPawel Jakub Dawidek 
8895ad4a7c7SPawel Jakub Dawidek static void
8905ad4a7c7SPawel Jakub Dawidek g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
8915ad4a7c7SPawel Jakub Dawidek {
8925ad4a7c7SPawel Jakub Dawidek 	struct g_eli_metadata md;
8935ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
8945ad4a7c7SPawel Jakub Dawidek 	struct g_provider *pp;
8955ad4a7c7SPawel Jakub Dawidek 	struct g_consumer *cp;
8965ad4a7c7SPawel Jakub Dawidek 	const char *name;
8975ad4a7c7SPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
8985ad4a7c7SPawel Jakub Dawidek 	int *nargs, keysize, error;
8995ad4a7c7SPawel Jakub Dawidek 	u_int nkey;
9005ad4a7c7SPawel Jakub Dawidek 
9015ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
9025ad4a7c7SPawel Jakub Dawidek 
9035ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
9045ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
9055ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
9065ad4a7c7SPawel Jakub Dawidek 		return;
9075ad4a7c7SPawel Jakub Dawidek 	}
9085ad4a7c7SPawel Jakub Dawidek 	if (*nargs != 1) {
9095ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
9105ad4a7c7SPawel Jakub Dawidek 		return;
9115ad4a7c7SPawel Jakub Dawidek 	}
9125ad4a7c7SPawel Jakub Dawidek 
9135ad4a7c7SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
9145ad4a7c7SPawel Jakub Dawidek 	if (name == NULL) {
9155ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
9165ad4a7c7SPawel Jakub Dawidek 		return;
9175ad4a7c7SPawel Jakub Dawidek 	}
9185ad4a7c7SPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
9195ad4a7c7SPawel Jakub Dawidek 	if (sc == NULL) {
9205ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
9215ad4a7c7SPawel Jakub Dawidek 		return;
9225ad4a7c7SPawel Jakub Dawidek 	}
9235ad4a7c7SPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
9245ad4a7c7SPawel Jakub Dawidek 	pp = cp->provider;
9255ad4a7c7SPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
9265ad4a7c7SPawel Jakub Dawidek 	if (error != 0) {
9275ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
9285ad4a7c7SPawel Jakub Dawidek 		    name, error);
9295ad4a7c7SPawel Jakub Dawidek 		return;
9305ad4a7c7SPawel Jakub Dawidek 	}
9315ad4a7c7SPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
9325ad4a7c7SPawel Jakub Dawidek 		bzero(&md, sizeof(md));
9335ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
9345ad4a7c7SPawel Jakub Dawidek 		return;
9355ad4a7c7SPawel Jakub Dawidek 	}
9365ad4a7c7SPawel Jakub Dawidek 
9375ad4a7c7SPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
9385ad4a7c7SPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
9395ad4a7c7SPawel Jakub Dawidek 		bzero(&md, sizeof(md));
9405ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
9415ad4a7c7SPawel Jakub Dawidek 		return;
9425ad4a7c7SPawel Jakub Dawidek 	}
9435ad4a7c7SPawel Jakub Dawidek 
9445ad4a7c7SPawel Jakub Dawidek 	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
9455ad4a7c7SPawel Jakub Dawidek 	bzero(key, keysize);
9465ad4a7c7SPawel Jakub Dawidek 	if (error == -1) {
9475ad4a7c7SPawel Jakub Dawidek 		bzero(&md, sizeof(md));
9485ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
9495ad4a7c7SPawel Jakub Dawidek 		return;
9505ad4a7c7SPawel Jakub Dawidek 	} else if (error > 0) {
9515ad4a7c7SPawel Jakub Dawidek 		bzero(&md, sizeof(md));
9525ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
9535ad4a7c7SPawel Jakub Dawidek 		    pp->name, error);
9545ad4a7c7SPawel Jakub Dawidek 		return;
9555ad4a7c7SPawel Jakub Dawidek 	}
9565ad4a7c7SPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
9575ad4a7c7SPawel Jakub Dawidek 
9585ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
9592f2d7830SPawel Jakub Dawidek 	if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
9602f2d7830SPawel Jakub Dawidek 		gctl_error(req, "Device %s is not suspended.", name);
9612f2d7830SPawel Jakub Dawidek 	else {
9625ad4a7c7SPawel Jakub Dawidek 		/* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
9635ad4a7c7SPawel Jakub Dawidek 		g_eli_mkey_propagate(sc, mkey);
9645ad4a7c7SPawel Jakub Dawidek 		sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
9652f2d7830SPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Resumed %s.", pp->name);
9662f2d7830SPawel Jakub Dawidek 		wakeup(sc);
9672f2d7830SPawel Jakub Dawidek 	}
9685ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
9691d021441SPawel Jakub Dawidek 	bzero(mkey, sizeof(mkey));
9701d021441SPawel Jakub Dawidek 	bzero(&md, sizeof(md));
9715ad4a7c7SPawel Jakub Dawidek }
9725ad4a7c7SPawel Jakub Dawidek 
9735ad4a7c7SPawel Jakub Dawidek static int
974c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc)
975c58794deSPawel Jakub Dawidek {
976c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
977c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
97885059016SPawel Jakub Dawidek 	int error = 0;
979c58794deSPawel Jakub Dawidek 
980c58794deSPawel Jakub Dawidek 	g_topology_assert();
981c58794deSPawel Jakub Dawidek 
982c58794deSPawel Jakub Dawidek 	if (sc == NULL)
983c58794deSPawel Jakub Dawidek 		return (ENOENT);
984c58794deSPawel Jakub Dawidek 
985c58794deSPawel Jakub Dawidek 	pp = LIST_FIRST(&sc->sc_geom->provider);
986c58794deSPawel Jakub Dawidek 	g_error_provider(pp, ENXIO);
987c58794deSPawel Jakub Dawidek 
988c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
989c58794deSPawel Jakub Dawidek 	pp = cp->provider;
990c58794deSPawel Jakub Dawidek 
99185059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
99285059016SPawel Jakub Dawidek 		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
99385059016SPawel Jakub Dawidek 		    "provider: %s.", pp->name);
99485059016SPawel Jakub Dawidek 	} else {
99585059016SPawel Jakub Dawidek 		u_char *sector;
99685059016SPawel Jakub Dawidek 		u_int i;
99785059016SPawel Jakub Dawidek 		int err;
99885059016SPawel Jakub Dawidek 
999c58794deSPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
1000c58794deSPawel Jakub Dawidek 		for (i = 0; i <= g_eli_overwrites; i++) {
1001c58794deSPawel Jakub Dawidek 			if (i == g_eli_overwrites)
1002c58794deSPawel Jakub Dawidek 				bzero(sector, pp->sectorsize);
1003c58794deSPawel Jakub Dawidek 			else
1004c58794deSPawel Jakub Dawidek 				arc4rand(sector, pp->sectorsize, 0);
100585059016SPawel Jakub Dawidek 			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
100685059016SPawel Jakub Dawidek 			    sector, pp->sectorsize);
1007c58794deSPawel Jakub Dawidek 			if (err != 0) {
1008c58794deSPawel Jakub Dawidek 				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
1009c58794deSPawel Jakub Dawidek 				    "(error=%d).", pp->name, err);
1010c58794deSPawel Jakub Dawidek 				if (error == 0)
1011c58794deSPawel Jakub Dawidek 					error = err;
1012c58794deSPawel Jakub Dawidek 			}
1013350e8df8SPawel Jakub Dawidek 			/*
1014350e8df8SPawel Jakub Dawidek 			 * Flush write cache so we don't overwrite data N times
1015350e8df8SPawel Jakub Dawidek 			 * in cache and only once on disk.
1016350e8df8SPawel Jakub Dawidek 			 */
1017350e8df8SPawel Jakub Dawidek 			(void)g_io_flush(cp);
1018c58794deSPawel Jakub Dawidek 		}
1019c58794deSPawel Jakub Dawidek 		free(sector, M_ELI);
102085059016SPawel Jakub Dawidek 	}
1021c58794deSPawel Jakub Dawidek 	if (error == 0)
1022c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
10235ad4a7c7SPawel Jakub Dawidek 	g_eli_destroy(sc, TRUE);
1024c58794deSPawel Jakub Dawidek 	return (error);
1025c58794deSPawel Jakub Dawidek }
1026c58794deSPawel Jakub Dawidek 
1027c58794deSPawel Jakub Dawidek static void
1028c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
1029c58794deSPawel Jakub Dawidek {
1030c58794deSPawel Jakub Dawidek 	int *all, *nargs;
1031c58794deSPawel Jakub Dawidek 	int error;
1032c58794deSPawel Jakub Dawidek 
1033c58794deSPawel Jakub Dawidek 	g_topology_assert();
1034c58794deSPawel Jakub Dawidek 
1035c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1036c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
1037c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
1038c58794deSPawel Jakub Dawidek 		return;
1039c58794deSPawel Jakub Dawidek 	}
1040c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
1041c58794deSPawel Jakub Dawidek 	if (all == NULL) {
1042c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
1043c58794deSPawel Jakub Dawidek 		return;
1044c58794deSPawel Jakub Dawidek 	}
1045c58794deSPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
1046c58794deSPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
1047c58794deSPawel Jakub Dawidek 		return;
1048c58794deSPawel Jakub Dawidek 	}
1049c58794deSPawel Jakub Dawidek 
1050c58794deSPawel Jakub Dawidek 	if (*all) {
1051c58794deSPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
1052c58794deSPawel Jakub Dawidek 
1053c58794deSPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
1054c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(gp->softc);
1055c58794deSPawel Jakub Dawidek 			if (error != 0)
1056c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1057c58794deSPawel Jakub Dawidek 		}
1058c58794deSPawel Jakub Dawidek 	} else {
1059c58794deSPawel Jakub Dawidek 		struct g_eli_softc *sc;
1060c58794deSPawel Jakub Dawidek 		const char *prov;
1061c58794deSPawel Jakub Dawidek 		char param[16];
1062c58794deSPawel Jakub Dawidek 		int i;
1063c58794deSPawel Jakub Dawidek 
1064c58794deSPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
10657d54b385SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
1066c58794deSPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
1067b5f30223SPawel Jakub Dawidek 			if (prov == NULL) {
1068b5f30223SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
1069b5f30223SPawel Jakub Dawidek 				continue;
1070b5f30223SPawel Jakub Dawidek 			}
1071c58794deSPawel Jakub Dawidek 
1072c58794deSPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
1073c58794deSPawel Jakub Dawidek 			if (sc == NULL) {
10747d54b385SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
1075c58794deSPawel Jakub Dawidek 				continue;
1076c58794deSPawel Jakub Dawidek 			}
1077c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(sc);
1078c58794deSPawel Jakub Dawidek 			if (error != 0)
1079c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1080c58794deSPawel Jakub Dawidek 		}
1081c58794deSPawel Jakub Dawidek 	}
1082c58794deSPawel Jakub Dawidek }
1083c58794deSPawel Jakub Dawidek 
1084c58794deSPawel Jakub Dawidek void
1085c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1086c58794deSPawel Jakub Dawidek {
1087c58794deSPawel Jakub Dawidek 	uint32_t *version;
1088c58794deSPawel Jakub Dawidek 
1089c58794deSPawel Jakub Dawidek 	g_topology_assert();
1090c58794deSPawel Jakub Dawidek 
1091c58794deSPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
1092c58794deSPawel Jakub Dawidek 	if (version == NULL) {
1093c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
1094c58794deSPawel Jakub Dawidek 		return;
1095c58794deSPawel Jakub Dawidek 	}
1096731adc86SPawel Jakub Dawidek 	while (*version != G_ELI_VERSION) {
1097731adc86SPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_06 &&
1098731adc86SPawel Jakub Dawidek 		    *version == G_ELI_VERSION_05) {
1099731adc86SPawel Jakub Dawidek 			/* Compatible. */
1100731adc86SPawel Jakub Dawidek 			break;
1101731adc86SPawel Jakub Dawidek 		}
1102457bbc4fSPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_07 &&
1103457bbc4fSPawel Jakub Dawidek 		    (*version == G_ELI_VERSION_05 ||
1104457bbc4fSPawel Jakub Dawidek 		     *version == G_ELI_VERSION_06)) {
1105457bbc4fSPawel Jakub Dawidek 			/* Compatible. */
1106457bbc4fSPawel Jakub Dawidek 			break;
1107457bbc4fSPawel Jakub Dawidek 		}
1108c58794deSPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
1109c58794deSPawel Jakub Dawidek 		return;
1110c58794deSPawel Jakub Dawidek 	}
1111c58794deSPawel Jakub Dawidek 
1112c58794deSPawel Jakub Dawidek 	if (strcmp(verb, "attach") == 0)
1113c58794deSPawel Jakub Dawidek 		g_eli_ctl_attach(req, mp);
1114c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
1115c58794deSPawel Jakub Dawidek 		g_eli_ctl_detach(req, mp);
1116c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "onetime") == 0)
1117c58794deSPawel Jakub Dawidek 		g_eli_ctl_onetime(req, mp);
11188abd1ad1SPawel Jakub Dawidek 	else if (strcmp(verb, "configure") == 0)
11198abd1ad1SPawel Jakub Dawidek 		g_eli_ctl_configure(req, mp);
1120c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "setkey") == 0)
1121c58794deSPawel Jakub Dawidek 		g_eli_ctl_setkey(req, mp);
1122c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "delkey") == 0)
1123c58794deSPawel Jakub Dawidek 		g_eli_ctl_delkey(req, mp);
11245ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "suspend") == 0)
11255ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_suspend(req, mp);
11265ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "resume") == 0)
11275ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_resume(req, mp);
1128c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "kill") == 0)
1129c58794deSPawel Jakub Dawidek 		g_eli_ctl_kill(req, mp);
1130c58794deSPawel Jakub Dawidek 	else
1131c58794deSPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
1132c58794deSPawel Jakub Dawidek }
1133