g_eli_ctl.c revision 212547
1211201Stakawata/*-
2211201Stakawata * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3211201Stakawata * All rights reserved.
4211201Stakawata *
5211201Stakawata * Redistribution and use in source and binary forms, with or without
6211201Stakawata * modification, are permitted provided that the following conditions
7211201Stakawata * are met:
8211201Stakawata * 1. Redistributions of source code must retain the above copyright
9211201Stakawata *    notice, this list of conditions and the following disclaimer.
10211201Stakawata * 2. Redistributions in binary form must reproduce the above copyright
11211201Stakawata *    notice, this list of conditions and the following disclaimer in the
12211201Stakawata *    documentation and/or other materials provided with the distribution.
13211201Stakawata *
14211201Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15211201Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16211201Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17211201Stakawata * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18211201Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19211201Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20211201Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21211201Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22211201Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23211201Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24211201Stakawata * SUCH DAMAGE.
25211201Stakawata */
26211201Stakawata
27211201Stakawata#include <sys/cdefs.h>
28211201Stakawata__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 212547 2010-09-13 08:56:07Z pjd $");
29211201Stakawata
30211201Stakawata#include <sys/param.h>
31211201Stakawata#include <sys/systm.h>
32211201Stakawata#include <sys/kernel.h>
33211201Stakawata#include <sys/module.h>
34211201Stakawata#include <sys/lock.h>
35211201Stakawata#include <sys/mutex.h>
36211201Stakawata#include <sys/bio.h>
37211201Stakawata#include <sys/sysctl.h>
38211201Stakawata#include <sys/malloc.h>
39211201Stakawata#include <sys/kthread.h>
40211201Stakawata#include <sys/proc.h>
41211201Stakawata#include <sys/sched.h>
42211201Stakawata#include <sys/uio.h>
43211201Stakawata
44211201Stakawata#include <vm/uma.h>
45211201Stakawata
46211201Stakawata#include <geom/geom.h>
47211201Stakawata#include <geom/eli/g_eli.h>
48211201Stakawata
49211201Stakawata
50211201StakawataMALLOC_DECLARE(M_ELI);
51211201Stakawata
52211201Stakawata
53211201Stakawatastatic void
54211201Stakawatag_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
55211201Stakawata{
56211201Stakawata	struct g_eli_metadata md;
57211201Stakawata	struct g_provider *pp;
58211201Stakawata	const char *name;
59211201Stakawata	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
60211201Stakawata	int *nargs, *detach, *readonly;
61211201Stakawata	int keysize, error;
62211201Stakawata	u_int nkey;
63211201Stakawata
64211201Stakawata	g_topology_assert();
65211201Stakawata
66211201Stakawata	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
67211201Stakawata	if (nargs == NULL) {
68211201Stakawata		gctl_error(req, "No '%s' argument.", "nargs");
69211201Stakawata		return;
70211201Stakawata	}
71211201Stakawata	if (*nargs != 1) {
72211201Stakawata		gctl_error(req, "Invalid number of arguments.");
73211201Stakawata		return;
74211201Stakawata	}
75211201Stakawata
76211201Stakawata	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
77211201Stakawata	if (detach == NULL) {
78211201Stakawata		gctl_error(req, "No '%s' argument.", "detach");
79211201Stakawata		return;
80211201Stakawata	}
81211201Stakawata
82211201Stakawata	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
83211201Stakawata	if (readonly == NULL) {
84211201Stakawata		gctl_error(req, "No '%s' argument.", "readonly");
85211201Stakawata		return;
86211201Stakawata	}
87211201Stakawata
88211201Stakawata	name = gctl_get_asciiparam(req, "arg0");
89211201Stakawata	if (name == NULL) {
90211201Stakawata		gctl_error(req, "No 'arg%u' argument.", 0);
91211201Stakawata		return;
92211201Stakawata	}
93211201Stakawata	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
94211201Stakawata		name += strlen("/dev/");
95211201Stakawata	pp = g_provider_by_name(name);
96211201Stakawata	if (pp == NULL) {
97211201Stakawata		gctl_error(req, "Provider %s is invalid.", name);
98211201Stakawata		return;
99211201Stakawata	}
100211201Stakawata	error = g_eli_read_metadata(mp, pp, &md);
101211201Stakawata	if (error != 0) {
102211201Stakawata		gctl_error(req, "Cannot read metadata from %s (error=%d).",
103211201Stakawata		    name, error);
104211201Stakawata		return;
105211201Stakawata	}
106211201Stakawata	if (md.md_keys == 0x00) {
107211201Stakawata		bzero(&md, sizeof(md));
108211201Stakawata		gctl_error(req, "No valid keys on %s.", pp->name);
109211201Stakawata		return;
110211201Stakawata	}
111211201Stakawata
112211201Stakawata	key = gctl_get_param(req, "key", &keysize);
113211201Stakawata	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
114211201Stakawata		bzero(&md, sizeof(md));
115211201Stakawata		gctl_error(req, "No '%s' argument.", "key");
116211201Stakawata		return;
117211201Stakawata	}
118211201Stakawata
119211201Stakawata	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
120211201Stakawata	bzero(key, keysize);
121211201Stakawata	if (error == -1) {
122211201Stakawata		bzero(&md, sizeof(md));
123211201Stakawata		gctl_error(req, "Wrong key for %s.", pp->name);
124211201Stakawata		return;
125211201Stakawata	} else if (error > 0) {
126211201Stakawata		bzero(&md, sizeof(md));
127211201Stakawata		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
128211201Stakawata		    pp->name, error);
129211201Stakawata		return;
130211201Stakawata	}
131211201Stakawata	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
132211201Stakawata
133211201Stakawata	if (*detach && *readonly) {
134211201Stakawata		bzero(&md, sizeof(md));
135211201Stakawata		gctl_error(req, "Options -d and -r are mutually exclusive.");
136211201Stakawata		return;
137211201Stakawata	}
138211201Stakawata	if (*detach)
139211201Stakawata		md.md_flags |= G_ELI_FLAG_WO_DETACH;
140211201Stakawata	if (*readonly)
141211201Stakawata		md.md_flags |= G_ELI_FLAG_RO;
142211201Stakawata	g_eli_create(req, mp, pp, &md, mkey, nkey);
143211201Stakawata	bzero(mkey, sizeof(mkey));
144211201Stakawata	bzero(&md, sizeof(md));
145211201Stakawata}
146211201Stakawata
147211201Stakawatastatic struct g_eli_softc *
148211201Stakawatag_eli_find_device(struct g_class *mp, const char *prov)
149211201Stakawata{
150211201Stakawata	struct g_eli_softc *sc;
151211201Stakawata	struct g_geom *gp;
152211201Stakawata	struct g_provider *pp;
153211201Stakawata	struct g_consumer *cp;
154211201Stakawata
155211201Stakawata	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
156211201Stakawata		prov += strlen("/dev/");
157211201Stakawata	LIST_FOREACH(gp, &mp->geom, geom) {
158211201Stakawata		sc = gp->softc;
159211201Stakawata		if (sc == NULL)
160211201Stakawata			continue;
161211201Stakawata		pp = LIST_FIRST(&gp->provider);
162211201Stakawata		if (pp != NULL && strcmp(pp->name, prov) == 0)
163211201Stakawata			return (sc);
164211201Stakawata		cp = LIST_FIRST(&gp->consumer);
165211201Stakawata		if (cp != NULL && cp->provider != NULL &&
166211201Stakawata		    strcmp(cp->provider->name, prov) == 0) {
167211201Stakawata			return (sc);
168211201Stakawata		}
169211201Stakawata	}
170211201Stakawata	return (NULL);
171211201Stakawata}
172211201Stakawata
173211201Stakawatastatic void
174211201Stakawatag_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
175211201Stakawata{
176211201Stakawata	struct g_eli_softc *sc;
177211201Stakawata	int *force, *last, *nargs, error;
178211201Stakawata	const char *prov;
179211201Stakawata	char param[16];
180211201Stakawata	int i;
181211201Stakawata
182211201Stakawata	g_topology_assert();
183211201Stakawata
184211201Stakawata	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
185211201Stakawata	if (nargs == NULL) {
186211201Stakawata		gctl_error(req, "No '%s' argument.", "nargs");
187211201Stakawata		return;
188211201Stakawata	}
189211201Stakawata	if (*nargs <= 0) {
190211201Stakawata		gctl_error(req, "Missing device(s).");
191211201Stakawata		return;
192211201Stakawata	}
193211201Stakawata	force = gctl_get_paraml(req, "force", sizeof(*force));
194211201Stakawata	if (force == NULL) {
195211201Stakawata		gctl_error(req, "No '%s' argument.", "force");
196211201Stakawata		return;
197211201Stakawata	}
198211201Stakawata	last = gctl_get_paraml(req, "last", sizeof(*last));
199211201Stakawata	if (last == NULL) {
200211201Stakawata		gctl_error(req, "No '%s' argument.", "last");
201211201Stakawata		return;
202211201Stakawata	}
203211201Stakawata
204211201Stakawata	for (i = 0; i < *nargs; i++) {
205211201Stakawata		snprintf(param, sizeof(param), "arg%d", i);
206211201Stakawata		prov = gctl_get_asciiparam(req, param);
207211201Stakawata		if (prov == NULL) {
208211201Stakawata			gctl_error(req, "No 'arg%d' argument.", i);
209211201Stakawata			return;
210211201Stakawata		}
211211201Stakawata		sc = g_eli_find_device(mp, prov);
212211201Stakawata		if (sc == NULL) {
213211201Stakawata			gctl_error(req, "No such device: %s.", prov);
214211201Stakawata			return;
215211201Stakawata		}
216211201Stakawata		if (*last) {
217211201Stakawata			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
218211201Stakawata			sc->sc_geom->access = g_eli_access;
219211201Stakawata		} else {
220211201Stakawata			error = g_eli_destroy(sc, *force);
221211201Stakawata			if (error != 0) {
222211201Stakawata				gctl_error(req,
223211201Stakawata				    "Cannot destroy device %s (error=%d).",
224211201Stakawata				    sc->sc_name, error);
225211201Stakawata				return;
226211201Stakawata			}
227211201Stakawata		}
228211201Stakawata	}
229211201Stakawata}
230211201Stakawata
231211201Stakawatastatic void
232211201Stakawatag_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
233211201Stakawata{
234211201Stakawata	struct g_eli_metadata md;
235211201Stakawata	struct g_provider *pp;
236211201Stakawata	const char *name;
237211201Stakawata	intmax_t *keylen, *sectorsize;
238211201Stakawata	u_char mkey[G_ELI_DATAIVKEYLEN];
239211201Stakawata	int *nargs, *detach;
240211201Stakawata
241211201Stakawata	g_topology_assert();
242211201Stakawata	bzero(&md, sizeof(md));
243211201Stakawata
244211201Stakawata	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
245211201Stakawata	if (nargs == NULL) {
246211201Stakawata		gctl_error(req, "No '%s' argument.", "nargs");
247211201Stakawata		return;
248211201Stakawata	}
249211201Stakawata	if (*nargs != 1) {
250211201Stakawata		gctl_error(req, "Invalid number of arguments.");
251211201Stakawata		return;
252211201Stakawata	}
253211201Stakawata
254211201Stakawata	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
255211201Stakawata	if (detach == NULL) {
256211201Stakawata		gctl_error(req, "No '%s' argument.", "detach");
257211201Stakawata		return;
258211201Stakawata	}
259211201Stakawata
260211201Stakawata	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
261211201Stakawata	md.md_version = G_ELI_VERSION;
262211201Stakawata	md.md_flags |= G_ELI_FLAG_ONETIME;
263211201Stakawata	if (*detach)
264211201Stakawata		md.md_flags |= G_ELI_FLAG_WO_DETACH;
265211201Stakawata
266211201Stakawata	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
267211201Stakawata	name = gctl_get_asciiparam(req, "aalgo");
268211201Stakawata	if (name == NULL) {
269211201Stakawata		gctl_error(req, "No '%s' argument.", "aalgo");
270211201Stakawata		return;
271211201Stakawata	}
272211201Stakawata	if (*name != '\0') {
273211201Stakawata		md.md_aalgo = g_eli_str2aalgo(name);
274211201Stakawata		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
275211201Stakawata		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
276211201Stakawata			md.md_flags |= G_ELI_FLAG_AUTH;
277211201Stakawata		} else {
278211201Stakawata			/*
279211201Stakawata			 * For backward compatibility, check if the -a option
280211201Stakawata			 * was used to provide encryption algorithm.
281211201Stakawata			 */
282211201Stakawata			md.md_ealgo = g_eli_str2ealgo(name);
283211201Stakawata			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
284211201Stakawata			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
285211201Stakawata				gctl_error(req,
286211201Stakawata				    "Invalid authentication algorithm.");
287211201Stakawata				return;
288211201Stakawata			} else {
289211201Stakawata				gctl_error(req, "warning: The -e option, not "
290211201Stakawata				    "the -a option is now used to specify "
291211201Stakawata				    "encryption algorithm to use.");
292211201Stakawata			}
293211201Stakawata		}
294211201Stakawata	}
295211201Stakawata
296211201Stakawata	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
297211201Stakawata	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
298211201Stakawata		name = gctl_get_asciiparam(req, "ealgo");
299211201Stakawata		if (name == NULL) {
300211201Stakawata			gctl_error(req, "No '%s' argument.", "ealgo");
301211201Stakawata			return;
302211201Stakawata		}
303211201Stakawata		md.md_ealgo = g_eli_str2ealgo(name);
304211201Stakawata		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
305211201Stakawata		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
306211201Stakawata			gctl_error(req, "Invalid encryption algorithm.");
307211201Stakawata			return;
308211201Stakawata		}
309211201Stakawata	}
310211201Stakawata
311211201Stakawata	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
312211201Stakawata	if (keylen == NULL) {
313211201Stakawata		gctl_error(req, "No '%s' argument.", "keylen");
314211201Stakawata		return;
315211201Stakawata	}
316211201Stakawata	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
317211201Stakawata	if (md.md_keylen == 0) {
318211201Stakawata		gctl_error(req, "Invalid '%s' argument.", "keylen");
319211201Stakawata		return;
320211201Stakawata	}
321211201Stakawata
322211201Stakawata	/* Not important here. */
323211201Stakawata	md.md_provsize = 0;
324211201Stakawata	/* Not important here. */
325211201Stakawata	bzero(md.md_salt, sizeof(md.md_salt));
326211201Stakawata
327211201Stakawata	md.md_keys = 0x01;
328211201Stakawata	arc4rand(mkey, sizeof(mkey), 0);
329211201Stakawata
330211201Stakawata	/* Not important here. */
331211201Stakawata	bzero(md.md_hash, sizeof(md.md_hash));
332211201Stakawata
333211201Stakawata	name = gctl_get_asciiparam(req, "arg0");
334211201Stakawata	if (name == NULL) {
335211201Stakawata		gctl_error(req, "No 'arg%u' argument.", 0);
336211201Stakawata		return;
337211201Stakawata	}
338211201Stakawata	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
339211201Stakawata		name += strlen("/dev/");
340211201Stakawata	pp = g_provider_by_name(name);
341211201Stakawata	if (pp == NULL) {
342211201Stakawata		gctl_error(req, "Provider %s is invalid.", name);
343211201Stakawata		return;
344211201Stakawata	}
345211201Stakawata
346211201Stakawata	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
347211201Stakawata	if (sectorsize == NULL) {
348211201Stakawata		gctl_error(req, "No '%s' argument.", "sectorsize");
349211201Stakawata		return;
350211201Stakawata	}
351211201Stakawata	if (*sectorsize == 0)
352211201Stakawata		md.md_sectorsize = pp->sectorsize;
353211201Stakawata	else {
354211201Stakawata		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
355211201Stakawata			gctl_error(req, "Invalid sector size.");
356211201Stakawata			return;
357211201Stakawata		}
358211201Stakawata		if (*sectorsize > PAGE_SIZE) {
359211201Stakawata			gctl_error(req, "warning: Using sectorsize bigger than "
360211201Stakawata			    "the page size!");
361211201Stakawata		}
362211201Stakawata		md.md_sectorsize = *sectorsize;
363211201Stakawata	}
364211201Stakawata
365211201Stakawata	g_eli_create(req, mp, pp, &md, mkey, -1);
366211201Stakawata	bzero(mkey, sizeof(mkey));
367211201Stakawata	bzero(&md, sizeof(md));
368211201Stakawata}
369211201Stakawata
370211201Stakawatastatic void
371211201Stakawatag_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
372211201Stakawata{
373211201Stakawata	struct g_eli_softc *sc;
374211201Stakawata	struct g_eli_metadata md;
375211201Stakawata	struct g_provider *pp;
376211201Stakawata	struct g_consumer *cp;
377211201Stakawata	char param[16];
378211201Stakawata	const char *prov;
379211201Stakawata	u_char *sector;
380211201Stakawata	int *nargs, *boot, *noboot;
381211201Stakawata	int error;
382211201Stakawata	u_int i;
383211201Stakawata
384211201Stakawata	g_topology_assert();
385211201Stakawata
386211201Stakawata	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
387211201Stakawata	if (nargs == NULL) {
388211201Stakawata		gctl_error(req, "No '%s' argument.", "nargs");
389211201Stakawata		return;
390211201Stakawata	}
391211201Stakawata	if (*nargs <= 0) {
392211201Stakawata		gctl_error(req, "Missing device(s).");
393211201Stakawata		return;
394211201Stakawata	}
395211201Stakawata
396211201Stakawata	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
397211201Stakawata	if (boot == NULL) {
398211201Stakawata		gctl_error(req, "No '%s' argument.", "boot");
399211201Stakawata		return;
400211201Stakawata	}
401211201Stakawata	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
402211201Stakawata	if (noboot == NULL) {
403211201Stakawata		gctl_error(req, "No '%s' argument.", "noboot");
404211201Stakawata		return;
405211201Stakawata	}
406211201Stakawata	if (*boot && *noboot) {
407211201Stakawata		gctl_error(req, "Options -b and -B are mutually exclusive.");
408211201Stakawata		return;
409211201Stakawata	}
410211201Stakawata	if (!*boot && !*noboot) {
411211201Stakawata		gctl_error(req, "No option given.");
412211201Stakawata		return;
413211201Stakawata	}
414211201Stakawata
415211201Stakawata	for (i = 0; i < *nargs; i++) {
416211201Stakawata		snprintf(param, sizeof(param), "arg%d", i);
417211201Stakawata		prov = gctl_get_asciiparam(req, param);
418211201Stakawata		if (prov == NULL) {
419211201Stakawata			gctl_error(req, "No 'arg%d' argument.", i);
420211201Stakawata			return;
421211201Stakawata		}
422211201Stakawata		sc = g_eli_find_device(mp, prov);
423211201Stakawata		if (sc == NULL) {
424211201Stakawata			/*
425211201Stakawata			 * We ignore not attached providers, userland part will
426211201Stakawata			 * take care of them.
427211201Stakawata			 */
428211201Stakawata			G_ELI_DEBUG(1, "Skipping configuration of not attached "
429211201Stakawata			    "provider %s.", prov);
430211201Stakawata			continue;
431211201Stakawata		}
432211201Stakawata		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
433211201Stakawata			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
434211201Stakawata			    prov);
435211201Stakawata			continue;
436211201Stakawata		} else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
437211201Stakawata			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
438211201Stakawata			    prov);
439211201Stakawata			continue;
440211201Stakawata		}
441211201Stakawata		if (sc->sc_flags & G_ELI_FLAG_RO) {
442211201Stakawata			gctl_error(req, "Cannot change configuration of "
443211201Stakawata			    "read-only provider %s.", prov);
444211201Stakawata			continue;
445211201Stakawata		}
446211201Stakawata		cp = LIST_FIRST(&sc->sc_geom->consumer);
447211201Stakawata		pp = cp->provider;
448211201Stakawata		error = g_eli_read_metadata(mp, pp, &md);
449211201Stakawata		if (error != 0) {
450211201Stakawata			gctl_error(req,
451211201Stakawata			    "Cannot read metadata from %s (error=%d).",
452211201Stakawata			    prov, error);
453211201Stakawata			continue;
454211201Stakawata		}
455211201Stakawata
456211201Stakawata		if (*boot) {
457211201Stakawata			md.md_flags |= G_ELI_FLAG_BOOT;
458211201Stakawata			sc->sc_flags |= G_ELI_FLAG_BOOT;
459211201Stakawata		} else {
460211201Stakawata			md.md_flags &= ~G_ELI_FLAG_BOOT;
461211201Stakawata			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
462211201Stakawata		}
463211201Stakawata
464211201Stakawata		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
465211201Stakawata		eli_metadata_encode(&md, sector);
466211201Stakawata		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
467211201Stakawata		    pp->sectorsize);
468211201Stakawata		if (error != 0) {
469211201Stakawata			gctl_error(req,
470211201Stakawata			    "Cannot store metadata on %s (error=%d).",
471211201Stakawata			    prov, error);
472211201Stakawata		}
473211201Stakawata		bzero(&md, sizeof(md));
474211201Stakawata		bzero(sector, sizeof(sector));
475211201Stakawata		free(sector, M_ELI);
476211201Stakawata	}
477211201Stakawata}
478211201Stakawata
479211201Stakawatastatic void
480211201Stakawatag_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
481211201Stakawata{
482211201Stakawata	struct g_eli_softc *sc;
483211201Stakawata	struct g_eli_metadata md;
484211201Stakawata	struct g_provider *pp;
485211201Stakawata	struct g_consumer *cp;
486211201Stakawata	const char *name;
487211201Stakawata	u_char *key, *mkeydst, *sector;
488211201Stakawata	intmax_t *valp;
489211201Stakawata	int keysize, nkey, error;
490211201Stakawata
491211201Stakawata	g_topology_assert();
492211201Stakawata
493211201Stakawata	name = gctl_get_asciiparam(req, "arg0");
494211201Stakawata	if (name == NULL) {
495211201Stakawata		gctl_error(req, "No 'arg%u' argument.", 0);
496211201Stakawata		return;
497211201Stakawata	}
498211201Stakawata	sc = g_eli_find_device(mp, name);
499211201Stakawata	if (sc == NULL) {
500211201Stakawata		gctl_error(req, "Provider %s is invalid.", name);
501211201Stakawata		return;
502211201Stakawata	}
503211201Stakawata	if (sc->sc_flags & G_ELI_FLAG_RO) {
504211201Stakawata		gctl_error(req, "Cannot change keys for read-only provider.");
505211201Stakawata		return;
506211201Stakawata	}
507211201Stakawata	cp = LIST_FIRST(&sc->sc_geom->consumer);
508211201Stakawata	pp = cp->provider;
509211201Stakawata
510211201Stakawata	error = g_eli_read_metadata(mp, pp, &md);
511211201Stakawata	if (error != 0) {
512211201Stakawata		gctl_error(req, "Cannot read metadata from %s (error=%d).",
513211201Stakawata		    name, error);
514211201Stakawata		return;
515211201Stakawata	}
516211201Stakawata
517211201Stakawata	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
518211201Stakawata	if (valp == NULL) {
519211201Stakawata		gctl_error(req, "No '%s' argument.", "keyno");
520211201Stakawata		return;
521211201Stakawata	}
522211201Stakawata	if (*valp != -1)
523211201Stakawata		nkey = *valp;
524211201Stakawata	else
525211201Stakawata		nkey = sc->sc_nkey;
526211201Stakawata	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
527211201Stakawata		gctl_error(req, "Invalid '%s' argument.", "keyno");
528211201Stakawata		return;
529211201Stakawata	}
530211201Stakawata
531211201Stakawata	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
532211201Stakawata	if (valp == NULL) {
533211201Stakawata		gctl_error(req, "No '%s' argument.", "iterations");
534211201Stakawata		return;
535211201Stakawata	}
536211201Stakawata	/* Check if iterations number should and can be changed. */
537211201Stakawata	if (*valp != -1) {
538211201Stakawata		if (bitcount32(md.md_keys) != 1) {
539211201Stakawata			gctl_error(req, "To be able to use '-i' option, only "
540211201Stakawata			    "one key can be defined.");
541211201Stakawata			return;
542211201Stakawata		}
543211201Stakawata		if (md.md_keys != (1 << nkey)) {
544211201Stakawata			gctl_error(req, "Only already defined key can be "
545211201Stakawata			    "changed when '-i' option is used.");
546211201Stakawata			return;
547211201Stakawata		}
548211201Stakawata		md.md_iterations = *valp;
549211201Stakawata	}
550211201Stakawata
551211201Stakawata	key = gctl_get_param(req, "key", &keysize);
552211201Stakawata	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
553211201Stakawata		bzero(&md, sizeof(md));
554211201Stakawata		gctl_error(req, "No '%s' argument.", "key");
555211201Stakawata		return;
556211201Stakawata	}
557211201Stakawata
558211201Stakawata	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
559211201Stakawata	md.md_keys |= (1 << nkey);
560211201Stakawata
561211201Stakawata	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
562211201Stakawata
563211201Stakawata	/* Encrypt Master Key with the new key. */
564211201Stakawata	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
565211201Stakawata	bzero(key, sizeof(key));
566211201Stakawata	if (error != 0) {
567211201Stakawata		bzero(&md, sizeof(md));
568211201Stakawata		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
569211201Stakawata		return;
570211201Stakawata	}
571211201Stakawata
572211201Stakawata	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
573211201Stakawata	/* Store metadata with fresh key. */
574211201Stakawata	eli_metadata_encode(&md, sector);
575211201Stakawata	bzero(&md, sizeof(md));
576211201Stakawata	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
577211201Stakawata	    pp->sectorsize);
578211201Stakawata	bzero(sector, sizeof(sector));
579211201Stakawata	free(sector, M_ELI);
580211201Stakawata	if (error != 0) {
581211201Stakawata		gctl_error(req, "Cannot store metadata on %s (error=%d).",
582211201Stakawata		    pp->name, error);
583211201Stakawata		return;
584211201Stakawata	}
585211201Stakawata	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
586211201Stakawata}
587211201Stakawata
588211201Stakawatastatic void
589211201Stakawatag_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
590211201Stakawata{
591211201Stakawata	struct g_eli_softc *sc;
592211201Stakawata	struct g_eli_metadata md;
593211201Stakawata	struct g_provider *pp;
594211201Stakawata	struct g_consumer *cp;
595211201Stakawata	const char *name;
596211201Stakawata	u_char *mkeydst, *sector;
597211201Stakawata	intmax_t *valp;
598211201Stakawata	size_t keysize;
599211201Stakawata	int error, nkey, *all, *force;
600211201Stakawata	u_int i;
601211201Stakawata
602211201Stakawata	g_topology_assert();
603211201Stakawata
604211201Stakawata	nkey = 0;	/* fixes causeless gcc warning */
605211201Stakawata
606211201Stakawata	name = gctl_get_asciiparam(req, "arg0");
607211201Stakawata	if (name == NULL) {
608211201Stakawata		gctl_error(req, "No 'arg%u' argument.", 0);
609211201Stakawata		return;
610211201Stakawata	}
611211201Stakawata	sc = g_eli_find_device(mp, name);
612211201Stakawata	if (sc == NULL) {
613211201Stakawata		gctl_error(req, "Provider %s is invalid.", name);
614211201Stakawata		return;
615211201Stakawata	}
616211201Stakawata	if (sc->sc_flags & G_ELI_FLAG_RO) {
617211201Stakawata		gctl_error(req, "Cannot delete keys for read-only provider.");
618211201Stakawata		return;
619211201Stakawata	}
620211201Stakawata	cp = LIST_FIRST(&sc->sc_geom->consumer);
621211201Stakawata	pp = cp->provider;
622211201Stakawata
623211201Stakawata	error = g_eli_read_metadata(mp, pp, &md);
624211201Stakawata	if (error != 0) {
625211201Stakawata		gctl_error(req, "Cannot read metadata from %s (error=%d).",
626211201Stakawata		    name, error);
627211201Stakawata		return;
628211201Stakawata	}
629211201Stakawata
630211201Stakawata	all = gctl_get_paraml(req, "all", sizeof(*all));
631211201Stakawata	if (all == NULL) {
632211201Stakawata		gctl_error(req, "No '%s' argument.", "all");
633211201Stakawata		return;
634211201Stakawata	}
635211201Stakawata
636211201Stakawata	if (*all) {
637211201Stakawata		mkeydst = md.md_mkeys;
638211201Stakawata		keysize = sizeof(md.md_mkeys);
639211201Stakawata	} else {
640211201Stakawata		force = gctl_get_paraml(req, "force", sizeof(*force));
641211201Stakawata		if (force == NULL) {
642211201Stakawata			gctl_error(req, "No '%s' argument.", "force");
643211201Stakawata			return;
644211201Stakawata		}
645211201Stakawata
646211201Stakawata		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
647211201Stakawata		if (valp == NULL) {
648211201Stakawata			gctl_error(req, "No '%s' argument.", "keyno");
649211201Stakawata			return;
650211201Stakawata		}
651211201Stakawata		if (*valp != -1)
652211201Stakawata			nkey = *valp;
653211201Stakawata		else
654211201Stakawata			nkey = sc->sc_nkey;
655211201Stakawata		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
656211201Stakawata			gctl_error(req, "Invalid '%s' argument.", "keyno");
657211201Stakawata			return;
658211201Stakawata		}
659211201Stakawata		if (!(md.md_keys & (1 << nkey)) && !*force) {
660211201Stakawata			gctl_error(req, "Master Key %u is not set.", nkey);
661211201Stakawata			return;
662211201Stakawata		}
663211201Stakawata		md.md_keys &= ~(1 << nkey);
664211201Stakawata		if (md.md_keys == 0 && !*force) {
665211201Stakawata			gctl_error(req, "This is the last Master Key. Use '-f' "
666211201Stakawata			    "flag if you really want to remove it.");
667211201Stakawata			return;
668211201Stakawata		}
669211201Stakawata		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
670211201Stakawata		keysize = G_ELI_MKEYLEN;
671211201Stakawata	}
672211201Stakawata
673211201Stakawata	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
674211201Stakawata	for (i = 0; i <= g_eli_overwrites; i++) {
675211201Stakawata		if (i == g_eli_overwrites)
676211201Stakawata			bzero(mkeydst, keysize);
677211201Stakawata		else
678211201Stakawata			arc4rand(mkeydst, keysize, 0);
679211201Stakawata		/* Store metadata with destroyed key. */
680211201Stakawata		eli_metadata_encode(&md, sector);
681211201Stakawata		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
682211201Stakawata		    pp->sectorsize);
683211201Stakawata		if (error != 0) {
684211201Stakawata			G_ELI_DEBUG(0, "Cannot store metadata on %s "
685211201Stakawata			    "(error=%d).", pp->name, error);
686211201Stakawata		}
687211201Stakawata		/*
688211201Stakawata		 * Flush write cache so we don't overwrite data N times in cache
689211201Stakawata		 * and only once on disk.
690211201Stakawata		 */
691211201Stakawata		g_io_flush(cp);
692211201Stakawata	}
693211201Stakawata	bzero(&md, sizeof(md));
694211201Stakawata	bzero(sector, sizeof(sector));
695211201Stakawata	free(sector, M_ELI);
696211201Stakawata	if (*all)
697211201Stakawata		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
698211201Stakawata	else
699211201Stakawata		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
700211201Stakawata}
701211201Stakawata
702211201Stakawatastatic int
703211201Stakawatag_eli_kill_one(struct g_eli_softc *sc)
704211201Stakawata{
705211201Stakawata	struct g_provider *pp;
706211201Stakawata	struct g_consumer *cp;
707211201Stakawata	int error = 0;
708211201Stakawata
709211201Stakawata	g_topology_assert();
710211201Stakawata
711211201Stakawata	if (sc == NULL)
712211201Stakawata		return (ENOENT);
713211201Stakawata
714211201Stakawata	pp = LIST_FIRST(&sc->sc_geom->provider);
715211201Stakawata	g_error_provider(pp, ENXIO);
716211201Stakawata
717211201Stakawata	cp = LIST_FIRST(&sc->sc_geom->consumer);
718211201Stakawata	pp = cp->provider;
719211201Stakawata
720211201Stakawata	if (sc->sc_flags & G_ELI_FLAG_RO) {
721211201Stakawata		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
722211201Stakawata		    "provider: %s.", pp->name);
723211201Stakawata	} else {
724211201Stakawata		u_char *sector;
725211201Stakawata		u_int i;
726211201Stakawata		int err;
727211201Stakawata
728211201Stakawata		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
729211201Stakawata		for (i = 0; i <= g_eli_overwrites; i++) {
730211201Stakawata			if (i == g_eli_overwrites)
731211201Stakawata				bzero(sector, pp->sectorsize);
732211201Stakawata			else
733211201Stakawata				arc4rand(sector, pp->sectorsize, 0);
734211201Stakawata			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
735211201Stakawata			    sector, pp->sectorsize);
736211201Stakawata			if (err != 0) {
737211201Stakawata				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
738211201Stakawata				    "(error=%d).", pp->name, err);
739211201Stakawata				if (error == 0)
740211201Stakawata					error = err;
741211201Stakawata			}
742211201Stakawata		}
743211201Stakawata		free(sector, M_ELI);
744211201Stakawata	}
745211201Stakawata	if (error == 0)
746211201Stakawata		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
747211201Stakawata	g_eli_destroy(sc, 1);
748211201Stakawata	return (error);
749211201Stakawata}
750211201Stakawata
751211201Stakawatastatic void
752211201Stakawatag_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
753211201Stakawata{
754211201Stakawata	int *all, *nargs;
755211201Stakawata	int error;
756211201Stakawata
757211201Stakawata	g_topology_assert();
758211201Stakawata
759211201Stakawata	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
760211201Stakawata	if (nargs == NULL) {
761211201Stakawata		gctl_error(req, "No '%s' argument.", "nargs");
762211201Stakawata		return;
763211201Stakawata	}
764211201Stakawata	all = gctl_get_paraml(req, "all", sizeof(*all));
765211201Stakawata	if (all == NULL) {
766211201Stakawata		gctl_error(req, "No '%s' argument.", "all");
767211201Stakawata		return;
768211201Stakawata	}
769211201Stakawata	if (!*all && *nargs == 0) {
770211201Stakawata		gctl_error(req, "Too few arguments.");
771211201Stakawata		return;
772211201Stakawata	}
773211201Stakawata
774211201Stakawata	if (*all) {
775211201Stakawata		struct g_geom *gp, *gp2;
776211201Stakawata
777211201Stakawata		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
778211201Stakawata			error = g_eli_kill_one(gp->softc);
779211201Stakawata			if (error != 0)
780211201Stakawata				gctl_error(req, "Not fully done.");
781211201Stakawata		}
782211201Stakawata	} else {
783211201Stakawata		struct g_eli_softc *sc;
784211201Stakawata		const char *prov;
785211201Stakawata		char param[16];
786211201Stakawata		int i;
787211201Stakawata
788211201Stakawata		for (i = 0; i < *nargs; i++) {
789211201Stakawata			snprintf(param, sizeof(param), "arg%d", i);
790211201Stakawata			prov = gctl_get_asciiparam(req, param);
791211201Stakawata			if (prov == NULL) {
792211201Stakawata				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
793211201Stakawata				continue;
794211201Stakawata			}
795211201Stakawata
796211201Stakawata			sc = g_eli_find_device(mp, prov);
797211201Stakawata			if (sc == NULL) {
798211201Stakawata				G_ELI_DEBUG(0, "No such provider: %s.", prov);
799211201Stakawata				continue;
800211201Stakawata			}
801211201Stakawata			error = g_eli_kill_one(sc);
802211201Stakawata			if (error != 0)
803211201Stakawata				gctl_error(req, "Not fully done.");
804211201Stakawata		}
805211201Stakawata	}
806211201Stakawata}
807211201Stakawata
808211201Stakawatavoid
809211201Stakawatag_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
810211201Stakawata{
811211201Stakawata	uint32_t *version;
812211201Stakawata
813211201Stakawata	g_topology_assert();
814211201Stakawata
815211201Stakawata	version = gctl_get_paraml(req, "version", sizeof(*version));
816211201Stakawata	if (version == NULL) {
817211201Stakawata		gctl_error(req, "No '%s' argument.", "version");
818211201Stakawata		return;
819211201Stakawata	}
820211201Stakawata	if (*version != G_ELI_VERSION) {
821211201Stakawata		gctl_error(req, "Userland and kernel parts are out of sync.");
822211201Stakawata		return;
823211201Stakawata	}
824211201Stakawata
825211201Stakawata	if (strcmp(verb, "attach") == 0)
826211201Stakawata		g_eli_ctl_attach(req, mp);
827211201Stakawata	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
828211201Stakawata		g_eli_ctl_detach(req, mp);
829211201Stakawata	else if (strcmp(verb, "onetime") == 0)
830211201Stakawata		g_eli_ctl_onetime(req, mp);
831211201Stakawata	else if (strcmp(verb, "configure") == 0)
832211201Stakawata		g_eli_ctl_configure(req, mp);
833211201Stakawata	else if (strcmp(verb, "setkey") == 0)
834211201Stakawata		g_eli_ctl_setkey(req, mp);
835211201Stakawata	else if (strcmp(verb, "delkey") == 0)
836211201Stakawata		g_eli_ctl_delkey(req, mp);
837211201Stakawata	else if (strcmp(verb, "kill") == 0)
838211201Stakawata		g_eli_ctl_kill(req, mp);
839211201Stakawata	else
840211201Stakawata		gctl_error(req, "Unknown verb.");
841211201Stakawata}
842211201Stakawata