xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision a478ea74908024df80e60a025777d0aa23e23a2c)
1c58794deSPawel Jakub Dawidek /*-
2c58794deSPawel Jakub Dawidek  * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
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 {
220c58794deSPawel Jakub Dawidek 			error = g_eli_destroy(sc, *force);
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];
239c58794deSPawel Jakub Dawidek 	int *nargs, *detach;
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 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
255c58794deSPawel Jakub Dawidek 	if (detach == NULL) {
256c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "detach");
257c58794deSPawel Jakub Dawidek 		return;
258c58794deSPawel Jakub Dawidek 	}
259c58794deSPawel Jakub Dawidek 
260c58794deSPawel Jakub Dawidek 	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
261c58794deSPawel Jakub Dawidek 	md.md_version = G_ELI_VERSION;
262c58794deSPawel Jakub Dawidek 	md.md_flags |= G_ELI_FLAG_ONETIME;
263c58794deSPawel Jakub Dawidek 	if (*detach)
264c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
265c58794deSPawel Jakub Dawidek 
266c84efdcaSPawel Jakub Dawidek 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
267eaa3b919SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "aalgo");
268c58794deSPawel Jakub Dawidek 	if (name == NULL) {
269eaa3b919SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "aalgo");
270c58794deSPawel Jakub Dawidek 		return;
271c58794deSPawel Jakub Dawidek 	}
272*a478ea74SPawel Jakub Dawidek 	if (*name != '\0') {
273eaa3b919SPawel Jakub Dawidek 		md.md_aalgo = g_eli_str2aalgo(name);
274c84efdcaSPawel Jakub Dawidek 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
275c84efdcaSPawel Jakub Dawidek 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
276eaa3b919SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_AUTH;
277c84efdcaSPawel Jakub Dawidek 		} else {
278c84efdcaSPawel Jakub Dawidek 			/*
279c84efdcaSPawel Jakub Dawidek 			 * For backward compatibility, check if the -a option
280c84efdcaSPawel Jakub Dawidek 			 * was used to provide encryption algorithm.
281c84efdcaSPawel Jakub Dawidek 			 */
282c84efdcaSPawel Jakub Dawidek 			md.md_ealgo = g_eli_str2ealgo(name);
283c84efdcaSPawel Jakub Dawidek 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
284c84efdcaSPawel Jakub Dawidek 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
285c84efdcaSPawel Jakub Dawidek 				gctl_error(req,
286c84efdcaSPawel Jakub Dawidek 				    "Invalid authentication algorithm.");
287c84efdcaSPawel Jakub Dawidek 				return;
288c84efdcaSPawel Jakub Dawidek 			} else {
289c84efdcaSPawel Jakub Dawidek 				gctl_error(req, "warning: The -e option, not "
290c84efdcaSPawel Jakub Dawidek 				    "the -a option is now used to specify "
291c84efdcaSPawel Jakub Dawidek 				    "encryption algorithm to use.");
292c84efdcaSPawel Jakub Dawidek 			}
293c84efdcaSPawel Jakub Dawidek 		}
294eaa3b919SPawel Jakub Dawidek 	}
295eaa3b919SPawel Jakub Dawidek 
296c84efdcaSPawel Jakub Dawidek 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
297c84efdcaSPawel Jakub Dawidek 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
298eaa3b919SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, "ealgo");
299eaa3b919SPawel Jakub Dawidek 		if (name == NULL) {
300eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "ealgo");
301eaa3b919SPawel Jakub Dawidek 			return;
302eaa3b919SPawel Jakub Dawidek 		}
303eaa3b919SPawel Jakub Dawidek 		md.md_ealgo = g_eli_str2ealgo(name);
304eaa3b919SPawel Jakub Dawidek 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
305eaa3b919SPawel Jakub Dawidek 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
306eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "Invalid encryption algorithm.");
307c58794deSPawel Jakub Dawidek 			return;
308c58794deSPawel Jakub Dawidek 		}
309c84efdcaSPawel Jakub Dawidek 	}
310c58794deSPawel Jakub Dawidek 
311c58794deSPawel Jakub Dawidek 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
312c58794deSPawel Jakub Dawidek 	if (keylen == NULL) {
313c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keylen");
314c58794deSPawel Jakub Dawidek 		return;
315c58794deSPawel Jakub Dawidek 	}
316eaa3b919SPawel Jakub Dawidek 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
317c58794deSPawel Jakub Dawidek 	if (md.md_keylen == 0) {
318c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keylen");
319c58794deSPawel Jakub Dawidek 		return;
320c58794deSPawel Jakub Dawidek 	}
321c58794deSPawel Jakub Dawidek 
322c58794deSPawel Jakub Dawidek 	/* Not important here. */
323c58794deSPawel Jakub Dawidek 	md.md_provsize = 0;
324c58794deSPawel Jakub Dawidek 	/* Not important here. */
325c58794deSPawel Jakub Dawidek 	bzero(md.md_salt, sizeof(md.md_salt));
326c58794deSPawel Jakub Dawidek 
327c58794deSPawel Jakub Dawidek 	md.md_keys = 0x01;
328c58794deSPawel Jakub Dawidek 	arc4rand(mkey, sizeof(mkey), 0);
329c58794deSPawel Jakub Dawidek 
330c58794deSPawel Jakub Dawidek 	/* Not important here. */
331c58794deSPawel Jakub Dawidek 	bzero(md.md_hash, sizeof(md.md_hash));
332c58794deSPawel Jakub Dawidek 
333c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
334c58794deSPawel Jakub Dawidek 	if (name == NULL) {
335c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
336c58794deSPawel Jakub Dawidek 		return;
337c58794deSPawel Jakub Dawidek 	}
338c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
339c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
340c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
341c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
342c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
343c58794deSPawel Jakub Dawidek 		return;
344c58794deSPawel Jakub Dawidek 	}
345c58794deSPawel Jakub Dawidek 
346c58794deSPawel Jakub Dawidek 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
347c58794deSPawel Jakub Dawidek 	if (sectorsize == NULL) {
348c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "sectorsize");
349c58794deSPawel Jakub Dawidek 		return;
350c58794deSPawel Jakub Dawidek 	}
351c58794deSPawel Jakub Dawidek 	if (*sectorsize == 0)
352c58794deSPawel Jakub Dawidek 		md.md_sectorsize = pp->sectorsize;
353c58794deSPawel Jakub Dawidek 	else {
354c58794deSPawel Jakub Dawidek 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
355c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid sector size.");
356c58794deSPawel Jakub Dawidek 			return;
357c58794deSPawel Jakub Dawidek 		}
35897a669a3SPawel Jakub Dawidek 		if (*sectorsize > PAGE_SIZE) {
35997a669a3SPawel Jakub Dawidek 			gctl_error(req, "warning: Using sectorsize bigger than "
36097a669a3SPawel Jakub Dawidek 			    "the page size!");
36197a669a3SPawel Jakub Dawidek 		}
362c58794deSPawel Jakub Dawidek 		md.md_sectorsize = *sectorsize;
363c58794deSPawel Jakub Dawidek 	}
364c58794deSPawel Jakub Dawidek 
365c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, -1);
366c58794deSPawel Jakub Dawidek 	bzero(mkey, sizeof(mkey));
367c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
368c58794deSPawel Jakub Dawidek }
369c58794deSPawel Jakub Dawidek 
370c58794deSPawel Jakub Dawidek static void
3718abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
3728abd1ad1SPawel Jakub Dawidek {
3738abd1ad1SPawel Jakub Dawidek 	struct g_eli_softc *sc;
3748abd1ad1SPawel Jakub Dawidek 	struct g_eli_metadata md;
3758abd1ad1SPawel Jakub Dawidek 	struct g_provider *pp;
3768abd1ad1SPawel Jakub Dawidek 	struct g_consumer *cp;
3778abd1ad1SPawel Jakub Dawidek 	char param[16];
3788abd1ad1SPawel Jakub Dawidek 	const char *prov;
3798abd1ad1SPawel Jakub Dawidek 	u_char *sector;
3808abd1ad1SPawel Jakub Dawidek 	int *nargs, *boot, *noboot;
3818abd1ad1SPawel Jakub Dawidek 	int error;
3828abd1ad1SPawel Jakub Dawidek 	u_int i;
3838abd1ad1SPawel Jakub Dawidek 
3848abd1ad1SPawel Jakub Dawidek 	g_topology_assert();
3858abd1ad1SPawel Jakub Dawidek 
3868abd1ad1SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
3878abd1ad1SPawel Jakub Dawidek 	if (nargs == NULL) {
3888abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
3898abd1ad1SPawel Jakub Dawidek 		return;
3908abd1ad1SPawel Jakub Dawidek 	}
3918abd1ad1SPawel Jakub Dawidek 	if (*nargs <= 0) {
3928abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
3938abd1ad1SPawel Jakub Dawidek 		return;
3948abd1ad1SPawel Jakub Dawidek 	}
3958abd1ad1SPawel Jakub Dawidek 
3968abd1ad1SPawel Jakub Dawidek 	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
3978abd1ad1SPawel Jakub Dawidek 	if (boot == NULL) {
3988abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "boot");
3998abd1ad1SPawel Jakub Dawidek 		return;
4008abd1ad1SPawel Jakub Dawidek 	}
4018abd1ad1SPawel Jakub Dawidek 	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
4028abd1ad1SPawel Jakub Dawidek 	if (noboot == NULL) {
4038abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "noboot");
4048abd1ad1SPawel Jakub Dawidek 		return;
4058abd1ad1SPawel Jakub Dawidek 	}
4068abd1ad1SPawel Jakub Dawidek 	if (*boot && *noboot) {
4078abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Options -b and -B are mutually exclusive.");
4088abd1ad1SPawel Jakub Dawidek 		return;
4098abd1ad1SPawel Jakub Dawidek 	}
4108abd1ad1SPawel Jakub Dawidek 	if (!*boot && !*noboot) {
4118abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No option given.");
4128abd1ad1SPawel Jakub Dawidek 		return;
4138abd1ad1SPawel Jakub Dawidek 	}
4148abd1ad1SPawel Jakub Dawidek 
4158abd1ad1SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
4168abd1ad1SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
4178abd1ad1SPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
4188abd1ad1SPawel Jakub Dawidek 		if (prov == NULL) {
4198abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
4208abd1ad1SPawel Jakub Dawidek 			return;
4218abd1ad1SPawel Jakub Dawidek 		}
4228abd1ad1SPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
4238abd1ad1SPawel Jakub Dawidek 		if (sc == NULL) {
4248abd1ad1SPawel Jakub Dawidek 			/*
4258abd1ad1SPawel Jakub Dawidek 			 * We ignore not attached providers, userland part will
4268abd1ad1SPawel Jakub Dawidek 			 * take care of them.
4278abd1ad1SPawel Jakub Dawidek 			 */
4288abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "Skipping configuration of not attached "
4298abd1ad1SPawel Jakub Dawidek 			    "provider %s.", prov);
4308abd1ad1SPawel Jakub Dawidek 			continue;
4318abd1ad1SPawel Jakub Dawidek 		}
4328abd1ad1SPawel Jakub Dawidek 		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
4338abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
4348abd1ad1SPawel Jakub Dawidek 			    prov);
4358abd1ad1SPawel Jakub Dawidek 			continue;
4368abd1ad1SPawel Jakub Dawidek 		} else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
4378abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
4388abd1ad1SPawel Jakub Dawidek 			    prov);
4398abd1ad1SPawel Jakub Dawidek 			continue;
4408abd1ad1SPawel Jakub Dawidek 		}
4418abd1ad1SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_RO) {
4428abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "Cannot change configuration of "
4438abd1ad1SPawel Jakub Dawidek 			    "read-only provider %s.", prov);
4448abd1ad1SPawel Jakub Dawidek 			continue;
4458abd1ad1SPawel Jakub Dawidek 		}
4468abd1ad1SPawel Jakub Dawidek 		cp = LIST_FIRST(&sc->sc_geom->consumer);
4478abd1ad1SPawel Jakub Dawidek 		pp = cp->provider;
4488abd1ad1SPawel Jakub Dawidek 		error = g_eli_read_metadata(mp, pp, &md);
4498abd1ad1SPawel Jakub Dawidek 		if (error != 0) {
4508abd1ad1SPawel Jakub Dawidek 			gctl_error(req,
4518abd1ad1SPawel Jakub Dawidek 			    "Cannot read metadata from %s (error=%d).",
4528abd1ad1SPawel Jakub Dawidek 			    prov, error);
4538abd1ad1SPawel Jakub Dawidek 			continue;
4548abd1ad1SPawel Jakub Dawidek 		}
4558abd1ad1SPawel Jakub Dawidek 
4568abd1ad1SPawel Jakub Dawidek 		if (*boot) {
4578abd1ad1SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_BOOT;
4588abd1ad1SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_BOOT;
4598abd1ad1SPawel Jakub Dawidek 		} else {
4608abd1ad1SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_BOOT;
4618abd1ad1SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
4628abd1ad1SPawel Jakub Dawidek 		}
4638abd1ad1SPawel Jakub Dawidek 
4648abd1ad1SPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
4658abd1ad1SPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
4668abd1ad1SPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
4678abd1ad1SPawel Jakub Dawidek 		    pp->sectorsize);
4688abd1ad1SPawel Jakub Dawidek 		if (error != 0) {
4698abd1ad1SPawel Jakub Dawidek 			gctl_error(req,
4708abd1ad1SPawel Jakub Dawidek 			    "Cannot store metadata on %s (error=%d).",
4718abd1ad1SPawel Jakub Dawidek 			    prov, error);
4728abd1ad1SPawel Jakub Dawidek 		}
4738abd1ad1SPawel Jakub Dawidek 		bzero(&md, sizeof(md));
4748abd1ad1SPawel Jakub Dawidek 		bzero(sector, sizeof(sector));
4758abd1ad1SPawel Jakub Dawidek 		free(sector, M_ELI);
4768abd1ad1SPawel Jakub Dawidek 	}
4778abd1ad1SPawel Jakub Dawidek }
4788abd1ad1SPawel Jakub Dawidek 
4798abd1ad1SPawel Jakub Dawidek static void
480c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
481c58794deSPawel Jakub Dawidek {
482c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
483c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
484c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
485c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
486c58794deSPawel Jakub Dawidek 	const char *name;
487c58794deSPawel Jakub Dawidek 	u_char *key, *mkeydst, *sector;
488c58794deSPawel Jakub Dawidek 	intmax_t *valp;
4897a5c26fcSPawel Jakub Dawidek 	int keysize, nkey, error;
490c58794deSPawel Jakub Dawidek 
491c58794deSPawel Jakub Dawidek 	g_topology_assert();
492c58794deSPawel Jakub Dawidek 
493c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
494c58794deSPawel Jakub Dawidek 	if (name == NULL) {
495c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
496c58794deSPawel Jakub Dawidek 		return;
497c58794deSPawel Jakub Dawidek 	}
498c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
499c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
500c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
501c58794deSPawel Jakub Dawidek 		return;
502c58794deSPawel Jakub Dawidek 	}
50385059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
50485059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot change keys for read-only provider.");
50585059016SPawel Jakub Dawidek 		return;
50685059016SPawel Jakub Dawidek 	}
507c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
508c58794deSPawel Jakub Dawidek 	pp = cp->provider;
509c58794deSPawel Jakub Dawidek 
510c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
511c58794deSPawel Jakub Dawidek 	if (error != 0) {
512c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
513c58794deSPawel Jakub Dawidek 		    name, error);
514c58794deSPawel Jakub Dawidek 		return;
515c58794deSPawel Jakub Dawidek 	}
516c58794deSPawel Jakub Dawidek 
517c58794deSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
518c58794deSPawel Jakub Dawidek 	if (valp == NULL) {
519c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keyno");
520c58794deSPawel Jakub Dawidek 		return;
521c58794deSPawel Jakub Dawidek 	}
522c58794deSPawel Jakub Dawidek 	if (*valp != -1)
523c58794deSPawel Jakub Dawidek 		nkey = *valp;
524c58794deSPawel Jakub Dawidek 	else
525c58794deSPawel Jakub Dawidek 		nkey = sc->sc_nkey;
526c58794deSPawel Jakub Dawidek 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
527c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keyno");
528c58794deSPawel Jakub Dawidek 		return;
529c58794deSPawel Jakub Dawidek 	}
530c58794deSPawel Jakub Dawidek 
5317a5c26fcSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
5327a5c26fcSPawel Jakub Dawidek 	if (valp == NULL) {
5337a5c26fcSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "iterations");
5347a5c26fcSPawel Jakub Dawidek 		return;
5357a5c26fcSPawel Jakub Dawidek 	}
5367a5c26fcSPawel Jakub Dawidek 	/* Check if iterations number should and can be changed. */
5377a5c26fcSPawel Jakub Dawidek 	if (*valp != -1) {
5387a5c26fcSPawel Jakub Dawidek 		if (bitcount32(md.md_keys) != 1) {
5397a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "To be able to use '-i' option, only "
5407a5c26fcSPawel Jakub Dawidek 			    "one key can be defined.");
5417a5c26fcSPawel Jakub Dawidek 			return;
5427a5c26fcSPawel Jakub Dawidek 		}
5437a5c26fcSPawel Jakub Dawidek 		if (md.md_keys != (1 << nkey)) {
5447a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "Only already defined key can be "
5457a5c26fcSPawel Jakub Dawidek 			    "changed when '-i' option is used.");
5467a5c26fcSPawel Jakub Dawidek 			return;
5477a5c26fcSPawel Jakub Dawidek 		}
5487a5c26fcSPawel Jakub Dawidek 		md.md_iterations = *valp;
5497a5c26fcSPawel Jakub Dawidek 	}
5507a5c26fcSPawel Jakub Dawidek 
551c58794deSPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
552c58794deSPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
553c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
554c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
555c58794deSPawel Jakub Dawidek 		return;
556c58794deSPawel Jakub Dawidek 	}
557c58794deSPawel Jakub Dawidek 
558c58794deSPawel Jakub Dawidek 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
559c58794deSPawel Jakub Dawidek 	md.md_keys |= (1 << nkey);
560c58794deSPawel Jakub Dawidek 
561eaa3b919SPawel Jakub Dawidek 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
562c58794deSPawel Jakub Dawidek 
563c58794deSPawel Jakub Dawidek 	/* Encrypt Master Key with the new key. */
564eaa3b919SPawel Jakub Dawidek 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
565c58794deSPawel Jakub Dawidek 	bzero(key, sizeof(key));
566c58794deSPawel Jakub Dawidek 	if (error != 0) {
567c58794deSPawel Jakub Dawidek 		bzero(&md, sizeof(md));
568c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
569c58794deSPawel Jakub Dawidek 		return;
570c58794deSPawel Jakub Dawidek 	}
571c58794deSPawel Jakub Dawidek 
572c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
573c58794deSPawel Jakub Dawidek 	/* Store metadata with fresh key. */
574c58794deSPawel Jakub Dawidek 	eli_metadata_encode(&md, sector);
575c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
576c58794deSPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
577c58794deSPawel Jakub Dawidek 	    pp->sectorsize);
578c58794deSPawel Jakub Dawidek 	bzero(sector, sizeof(sector));
579c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
580c58794deSPawel Jakub Dawidek 	if (error != 0) {
581c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
582c58794deSPawel Jakub Dawidek 		    pp->name, error);
583c58794deSPawel Jakub Dawidek 		return;
584c58794deSPawel Jakub Dawidek 	}
585c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
586c58794deSPawel Jakub Dawidek }
587c58794deSPawel Jakub Dawidek 
588c58794deSPawel Jakub Dawidek static void
589c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
590c58794deSPawel Jakub Dawidek {
591c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
592c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
593c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
594c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
595c58794deSPawel Jakub Dawidek 	const char *name;
596c58794deSPawel Jakub Dawidek 	u_char *mkeydst, *sector;
597c58794deSPawel Jakub Dawidek 	intmax_t *valp;
598c58794deSPawel Jakub Dawidek 	size_t keysize;
599c58794deSPawel Jakub Dawidek 	int error, nkey, *all, *force;
600c58794deSPawel Jakub Dawidek 	u_int i;
601c58794deSPawel Jakub Dawidek 
602c58794deSPawel Jakub Dawidek 	g_topology_assert();
603c58794deSPawel Jakub Dawidek 
604c58794deSPawel Jakub Dawidek 	nkey = 0;	/* fixes causeless gcc warning */
605c58794deSPawel Jakub Dawidek 
606c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
607c58794deSPawel Jakub Dawidek 	if (name == NULL) {
608c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
609c58794deSPawel Jakub Dawidek 		return;
610c58794deSPawel Jakub Dawidek 	}
611c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
612c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
613c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
614c58794deSPawel Jakub Dawidek 		return;
615c58794deSPawel Jakub Dawidek 	}
61685059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
61785059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot delete keys for read-only provider.");
61885059016SPawel Jakub Dawidek 		return;
61985059016SPawel Jakub Dawidek 	}
620c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
621c58794deSPawel Jakub Dawidek 	pp = cp->provider;
622c58794deSPawel Jakub Dawidek 
623c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
624c58794deSPawel Jakub Dawidek 	if (error != 0) {
625c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
626c58794deSPawel Jakub Dawidek 		    name, error);
627c58794deSPawel Jakub Dawidek 		return;
628c58794deSPawel Jakub Dawidek 	}
629c58794deSPawel Jakub Dawidek 
630c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
631c58794deSPawel Jakub Dawidek 	if (all == NULL) {
632c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
633c58794deSPawel Jakub Dawidek 		return;
634c58794deSPawel Jakub Dawidek 	}
635c58794deSPawel Jakub Dawidek 
636c58794deSPawel Jakub Dawidek 	if (*all) {
637c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys;
638c58794deSPawel Jakub Dawidek 		keysize = sizeof(md.md_mkeys);
639c58794deSPawel Jakub Dawidek 	} else {
640c58794deSPawel Jakub Dawidek 		force = gctl_get_paraml(req, "force", sizeof(*force));
641c58794deSPawel Jakub Dawidek 		if (force == NULL) {
642c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "force");
643c58794deSPawel Jakub Dawidek 			return;
644c58794deSPawel Jakub Dawidek 		}
645c58794deSPawel Jakub Dawidek 
646c58794deSPawel Jakub Dawidek 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
647c58794deSPawel Jakub Dawidek 		if (valp == NULL) {
648c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "keyno");
649c58794deSPawel Jakub Dawidek 			return;
650c58794deSPawel Jakub Dawidek 		}
651c58794deSPawel Jakub Dawidek 		if (*valp != -1)
652c58794deSPawel Jakub Dawidek 			nkey = *valp;
653c58794deSPawel Jakub Dawidek 		else
654c58794deSPawel Jakub Dawidek 			nkey = sc->sc_nkey;
655c58794deSPawel Jakub Dawidek 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
656c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid '%s' argument.", "keyno");
657c58794deSPawel Jakub Dawidek 			return;
658c58794deSPawel Jakub Dawidek 		}
659c58794deSPawel Jakub Dawidek 		if (!(md.md_keys & (1 << nkey)) && !*force) {
660c58794deSPawel Jakub Dawidek 			gctl_error(req, "Master Key %u is not set.", nkey);
661c58794deSPawel Jakub Dawidek 			return;
662c58794deSPawel Jakub Dawidek 		}
663c58794deSPawel Jakub Dawidek 		md.md_keys &= ~(1 << nkey);
664c58794deSPawel Jakub Dawidek 		if (md.md_keys == 0 && !*force) {
665c58794deSPawel Jakub Dawidek 			gctl_error(req, "This is the last Master Key. Use '-f' "
666c58794deSPawel Jakub Dawidek 			    "flag if you really want to remove it.");
667c58794deSPawel Jakub Dawidek 			return;
668c58794deSPawel Jakub Dawidek 		}
669c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
670c58794deSPawel Jakub Dawidek 		keysize = G_ELI_MKEYLEN;
671c58794deSPawel Jakub Dawidek 	}
672c58794deSPawel Jakub Dawidek 
673c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
674c58794deSPawel Jakub Dawidek 	for (i = 0; i <= g_eli_overwrites; i++) {
675c58794deSPawel Jakub Dawidek 		if (i == g_eli_overwrites)
676c58794deSPawel Jakub Dawidek 			bzero(mkeydst, keysize);
677c58794deSPawel Jakub Dawidek 		else
678c58794deSPawel Jakub Dawidek 			arc4rand(mkeydst, keysize, 0);
679c58794deSPawel Jakub Dawidek 		/* Store metadata with destroyed key. */
680c58794deSPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
681c58794deSPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
682c58794deSPawel Jakub Dawidek 		    pp->sectorsize);
683c58794deSPawel Jakub Dawidek 		if (error != 0) {
684c58794deSPawel Jakub Dawidek 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
685c58794deSPawel Jakub Dawidek 			    "(error=%d).", pp->name, error);
686c58794deSPawel Jakub Dawidek 		}
687f0256e71SPawel Jakub Dawidek 		/*
688f0256e71SPawel Jakub Dawidek 		 * Flush write cache so we don't overwrite data N times in cache
689f0256e71SPawel Jakub Dawidek 		 * and only once on disk.
690f0256e71SPawel Jakub Dawidek 		 */
691f0256e71SPawel Jakub Dawidek 		g_io_flush(cp);
692c58794deSPawel Jakub Dawidek 	}
693c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
694c58794deSPawel Jakub Dawidek 	bzero(sector, sizeof(sector));
695c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
696c58794deSPawel Jakub Dawidek 	if (*all)
697c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
698c58794deSPawel Jakub Dawidek 	else
699c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
700c58794deSPawel Jakub Dawidek }
701c58794deSPawel Jakub Dawidek 
702c58794deSPawel Jakub Dawidek static int
703c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc)
704c58794deSPawel Jakub Dawidek {
705c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
706c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
70785059016SPawel Jakub Dawidek 	int error = 0;
708c58794deSPawel Jakub Dawidek 
709c58794deSPawel Jakub Dawidek 	g_topology_assert();
710c58794deSPawel Jakub Dawidek 
711c58794deSPawel Jakub Dawidek 	if (sc == NULL)
712c58794deSPawel Jakub Dawidek 		return (ENOENT);
713c58794deSPawel Jakub Dawidek 
714c58794deSPawel Jakub Dawidek 	pp = LIST_FIRST(&sc->sc_geom->provider);
715c58794deSPawel Jakub Dawidek 	g_error_provider(pp, ENXIO);
716c58794deSPawel Jakub Dawidek 
717c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
718c58794deSPawel Jakub Dawidek 	pp = cp->provider;
719c58794deSPawel Jakub Dawidek 
72085059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
72185059016SPawel Jakub Dawidek 		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
72285059016SPawel Jakub Dawidek 		    "provider: %s.", pp->name);
72385059016SPawel Jakub Dawidek 	} else {
72485059016SPawel Jakub Dawidek 		u_char *sector;
72585059016SPawel Jakub Dawidek 		u_int i;
72685059016SPawel Jakub Dawidek 		int err;
72785059016SPawel Jakub Dawidek 
728c58794deSPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
729c58794deSPawel Jakub Dawidek 		for (i = 0; i <= g_eli_overwrites; i++) {
730c58794deSPawel Jakub Dawidek 			if (i == g_eli_overwrites)
731c58794deSPawel Jakub Dawidek 				bzero(sector, pp->sectorsize);
732c58794deSPawel Jakub Dawidek 			else
733c58794deSPawel Jakub Dawidek 				arc4rand(sector, pp->sectorsize, 0);
73485059016SPawel Jakub Dawidek 			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
73585059016SPawel Jakub Dawidek 			    sector, pp->sectorsize);
736c58794deSPawel Jakub Dawidek 			if (err != 0) {
737c58794deSPawel Jakub Dawidek 				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
738c58794deSPawel Jakub Dawidek 				    "(error=%d).", pp->name, err);
739c58794deSPawel Jakub Dawidek 				if (error == 0)
740c58794deSPawel Jakub Dawidek 					error = err;
741c58794deSPawel Jakub Dawidek 			}
742c58794deSPawel Jakub Dawidek 		}
743c58794deSPawel Jakub Dawidek 		free(sector, M_ELI);
74485059016SPawel Jakub Dawidek 	}
745c58794deSPawel Jakub Dawidek 	if (error == 0)
746c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
747c58794deSPawel Jakub Dawidek 	g_eli_destroy(sc, 1);
748c58794deSPawel Jakub Dawidek 	return (error);
749c58794deSPawel Jakub Dawidek }
750c58794deSPawel Jakub Dawidek 
751c58794deSPawel Jakub Dawidek static void
752c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
753c58794deSPawel Jakub Dawidek {
754c58794deSPawel Jakub Dawidek 	int *all, *nargs;
755c58794deSPawel Jakub Dawidek 	int error;
756c58794deSPawel Jakub Dawidek 
757c58794deSPawel Jakub Dawidek 	g_topology_assert();
758c58794deSPawel Jakub Dawidek 
759c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
760c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
761c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
762c58794deSPawel Jakub Dawidek 		return;
763c58794deSPawel Jakub Dawidek 	}
764c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
765c58794deSPawel Jakub Dawidek 	if (all == NULL) {
766c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
767c58794deSPawel Jakub Dawidek 		return;
768c58794deSPawel Jakub Dawidek 	}
769c58794deSPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
770c58794deSPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
771c58794deSPawel Jakub Dawidek 		return;
772c58794deSPawel Jakub Dawidek 	}
773c58794deSPawel Jakub Dawidek 
774c58794deSPawel Jakub Dawidek 	if (*all) {
775c58794deSPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
776c58794deSPawel Jakub Dawidek 
777c58794deSPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
778c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(gp->softc);
779c58794deSPawel Jakub Dawidek 			if (error != 0)
780c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
781c58794deSPawel Jakub Dawidek 		}
782c58794deSPawel Jakub Dawidek 	} else {
783c58794deSPawel Jakub Dawidek 		struct g_eli_softc *sc;
784c58794deSPawel Jakub Dawidek 		const char *prov;
785c58794deSPawel Jakub Dawidek 		char param[16];
786c58794deSPawel Jakub Dawidek 		int i;
787c58794deSPawel Jakub Dawidek 
788c58794deSPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
7897d54b385SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
790c58794deSPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
791b5f30223SPawel Jakub Dawidek 			if (prov == NULL) {
792b5f30223SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
793b5f30223SPawel Jakub Dawidek 				continue;
794b5f30223SPawel Jakub Dawidek 			}
795c58794deSPawel Jakub Dawidek 
796c58794deSPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
797c58794deSPawel Jakub Dawidek 			if (sc == NULL) {
7987d54b385SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
799c58794deSPawel Jakub Dawidek 				continue;
800c58794deSPawel Jakub Dawidek 			}
801c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(sc);
802c58794deSPawel Jakub Dawidek 			if (error != 0)
803c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
804c58794deSPawel Jakub Dawidek 		}
805c58794deSPawel Jakub Dawidek 	}
806c58794deSPawel Jakub Dawidek }
807c58794deSPawel Jakub Dawidek 
808c58794deSPawel Jakub Dawidek void
809c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
810c58794deSPawel Jakub Dawidek {
811c58794deSPawel Jakub Dawidek 	uint32_t *version;
812c58794deSPawel Jakub Dawidek 
813c58794deSPawel Jakub Dawidek 	g_topology_assert();
814c58794deSPawel Jakub Dawidek 
815c58794deSPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
816c58794deSPawel Jakub Dawidek 	if (version == NULL) {
817c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
818c58794deSPawel Jakub Dawidek 		return;
819c58794deSPawel Jakub Dawidek 	}
820c58794deSPawel Jakub Dawidek 	if (*version != G_ELI_VERSION) {
821c58794deSPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
822c58794deSPawel Jakub Dawidek 		return;
823c58794deSPawel Jakub Dawidek 	}
824c58794deSPawel Jakub Dawidek 
825c58794deSPawel Jakub Dawidek 	if (strcmp(verb, "attach") == 0)
826c58794deSPawel Jakub Dawidek 		g_eli_ctl_attach(req, mp);
827c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
828c58794deSPawel Jakub Dawidek 		g_eli_ctl_detach(req, mp);
829c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "onetime") == 0)
830c58794deSPawel Jakub Dawidek 		g_eli_ctl_onetime(req, mp);
8318abd1ad1SPawel Jakub Dawidek 	else if (strcmp(verb, "configure") == 0)
8328abd1ad1SPawel Jakub Dawidek 		g_eli_ctl_configure(req, mp);
833c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "setkey") == 0)
834c58794deSPawel Jakub Dawidek 		g_eli_ctl_setkey(req, mp);
835c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "delkey") == 0)
836c58794deSPawel Jakub Dawidek 		g_eli_ctl_delkey(req, mp);
837c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "kill") == 0)
838c58794deSPawel Jakub Dawidek 		g_eli_ctl_kill(req, mp);
839c58794deSPawel Jakub Dawidek 	else
840c58794deSPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
841c58794deSPawel Jakub Dawidek }
842