g_eli_ctl.c revision 162345
1148456Spjd/*-
2148456Spjd * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3148456Spjd * All rights reserved.
4148456Spjd *
5148456Spjd * Redistribution and use in source and binary forms, with or without
6148456Spjd * modification, are permitted provided that the following conditions
7148456Spjd * are met:
8148456Spjd * 1. Redistributions of source code must retain the above copyright
9148456Spjd *    notice, this list of conditions and the following disclaimer.
10148456Spjd * 2. Redistributions in binary form must reproduce the above copyright
11148456Spjd *    notice, this list of conditions and the following disclaimer in the
12148456Spjd *    documentation and/or other materials provided with the distribution.
13155174Spjd *
14148456Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15148456Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16148456Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17148456Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18148456Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19148456Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148456Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148456Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22148456Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23148456Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24148456Spjd * SUCH DAMAGE.
25148456Spjd */
26148456Spjd
27148456Spjd#include <sys/cdefs.h>
28148456Spjd__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 162345 2006-09-16 07:47:57Z pjd $");
29148456Spjd
30148456Spjd#include <sys/param.h>
31148456Spjd#include <sys/systm.h>
32148456Spjd#include <sys/kernel.h>
33148456Spjd#include <sys/module.h>
34148456Spjd#include <sys/lock.h>
35148456Spjd#include <sys/mutex.h>
36148456Spjd#include <sys/bio.h>
37148456Spjd#include <sys/sysctl.h>
38148456Spjd#include <sys/malloc.h>
39148456Spjd#include <sys/kthread.h>
40148456Spjd#include <sys/proc.h>
41148456Spjd#include <sys/sched.h>
42148456Spjd#include <sys/uio.h>
43148456Spjd
44148456Spjd#include <vm/uma.h>
45148456Spjd
46148456Spjd#include <geom/geom.h>
47148456Spjd#include <geom/eli/g_eli.h>
48148456Spjd
49148456Spjd
50148456SpjdMALLOC_DECLARE(M_ELI);
51148456Spjd
52148456Spjd
53148456Spjdstatic void
54148456Spjdg_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
55148456Spjd{
56148456Spjd	struct g_eli_metadata md;
57148456Spjd	struct g_provider *pp;
58148456Spjd	const char *name;
59148456Spjd	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
60161127Spjd	int *nargs, *detach, *readonly;
61148456Spjd	int keysize, error;
62148456Spjd	u_int nkey;
63148456Spjd
64148456Spjd	g_topology_assert();
65148456Spjd
66148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
67148456Spjd	if (nargs == NULL) {
68148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
69148456Spjd		return;
70148456Spjd	}
71148456Spjd	if (*nargs != 1) {
72148456Spjd		gctl_error(req, "Invalid number of arguments.");
73148456Spjd		return;
74148456Spjd	}
75148456Spjd
76148456Spjd	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
77148456Spjd	if (detach == NULL) {
78148456Spjd		gctl_error(req, "No '%s' argument.", "detach");
79148456Spjd		return;
80148456Spjd	}
81148456Spjd
82161127Spjd	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
83161127Spjd	if (readonly == NULL) {
84161127Spjd		gctl_error(req, "No '%s' argument.", "readonly");
85161127Spjd		return;
86161127Spjd	}
87161127Spjd
88148456Spjd	name = gctl_get_asciiparam(req, "arg0");
89148456Spjd	if (name == NULL) {
90148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
91148456Spjd		return;
92148456Spjd	}
93148456Spjd	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
94148456Spjd		name += strlen("/dev/");
95148456Spjd	pp = g_provider_by_name(name);
96148456Spjd	if (pp == NULL) {
97148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
98148456Spjd		return;
99148456Spjd	}
100148456Spjd	error = g_eli_read_metadata(mp, pp, &md);
101148456Spjd	if (error != 0) {
102148456Spjd		gctl_error(req, "Cannot read metadata from %s (error=%d).",
103148456Spjd		    name, error);
104148456Spjd		return;
105148456Spjd	}
106148456Spjd	if (md.md_keys == 0x00) {
107148456Spjd		bzero(&md, sizeof(md));
108148456Spjd		gctl_error(req, "No valid keys on %s.", pp->name);
109148456Spjd		return;
110148456Spjd	}
111148456Spjd
112148456Spjd	key = gctl_get_param(req, "key", &keysize);
113148456Spjd	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
114148456Spjd		bzero(&md, sizeof(md));
115148456Spjd		gctl_error(req, "No '%s' argument.", "key");
116148456Spjd		return;
117148456Spjd	}
118148456Spjd
119148456Spjd	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
120148456Spjd	bzero(key, keysize);
121148456Spjd	if (error == -1) {
122148456Spjd		bzero(&md, sizeof(md));
123148456Spjd		gctl_error(req, "Wrong key for %s.", pp->name);
124148456Spjd		return;
125148456Spjd	} else if (error > 0) {
126148456Spjd		bzero(&md, sizeof(md));
127148456Spjd		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
128148456Spjd		    pp->name, error);
129148456Spjd		return;
130148456Spjd	}
131148456Spjd	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
132148456Spjd
133161127Spjd	if (*detach && *readonly) {
134161127Spjd		bzero(&md, sizeof(md));
135162345Spjd		gctl_error(req, "Options -d and -r are mutually exclusive.");
136161127Spjd		return;
137161127Spjd	}
138148456Spjd	if (*detach)
139148456Spjd		md.md_flags |= G_ELI_FLAG_WO_DETACH;
140161127Spjd	if (*readonly)
141161127Spjd		md.md_flags |= G_ELI_FLAG_RO;
142148456Spjd	g_eli_create(req, mp, pp, &md, mkey, nkey);
143148456Spjd	bzero(mkey, sizeof(mkey));
144148456Spjd	bzero(&md, sizeof(md));
145148456Spjd}
146148456Spjd
147148456Spjdstatic struct g_eli_softc *
148148456Spjdg_eli_find_device(struct g_class *mp, const char *prov)
149148456Spjd{
150148456Spjd	struct g_eli_softc *sc;
151148456Spjd	struct g_geom *gp;
152148456Spjd	struct g_provider *pp;
153148456Spjd	struct g_consumer *cp;
154148456Spjd
155148456Spjd	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
156148456Spjd		prov += strlen("/dev/");
157148456Spjd	LIST_FOREACH(gp, &mp->geom, geom) {
158148456Spjd		sc = gp->softc;
159148456Spjd		if (sc == NULL)
160148456Spjd			continue;
161148456Spjd		pp = LIST_FIRST(&gp->provider);
162148456Spjd		if (pp != NULL && strcmp(pp->name, prov) == 0)
163148456Spjd			return (sc);
164148456Spjd		cp = LIST_FIRST(&gp->consumer);
165148456Spjd		if (cp != NULL && cp->provider != NULL &&
166148456Spjd		    strcmp(cp->provider->name, prov) == 0) {
167148456Spjd			return (sc);
168148456Spjd		}
169148456Spjd	}
170148456Spjd	return (NULL);
171148456Spjd}
172148456Spjd
173148456Spjdstatic void
174148456Spjdg_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
175148456Spjd{
176148456Spjd	struct g_eli_softc *sc;
177148456Spjd	int *force, *last, *nargs, error;
178148456Spjd	const char *prov;
179148456Spjd	char param[16];
180154463Spjd	int i;
181148456Spjd
182148456Spjd	g_topology_assert();
183148456Spjd
184148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
185148456Spjd	if (nargs == NULL) {
186148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
187148456Spjd		return;
188148456Spjd	}
189148456Spjd	if (*nargs <= 0) {
190148456Spjd		gctl_error(req, "Missing device(s).");
191148456Spjd		return;
192148456Spjd	}
193148456Spjd	force = gctl_get_paraml(req, "force", sizeof(*force));
194148456Spjd	if (force == NULL) {
195148456Spjd		gctl_error(req, "No '%s' argument.", "force");
196148456Spjd		return;
197148456Spjd	}
198148456Spjd	last = gctl_get_paraml(req, "last", sizeof(*last));
199148456Spjd	if (last == NULL) {
200148456Spjd		gctl_error(req, "No '%s' argument.", "last");
201148456Spjd		return;
202148456Spjd	}
203148456Spjd
204154463Spjd	for (i = 0; i < *nargs; i++) {
205154463Spjd		snprintf(param, sizeof(param), "arg%d", i);
206148456Spjd		prov = gctl_get_asciiparam(req, param);
207148456Spjd		if (prov == NULL) {
208154463Spjd			gctl_error(req, "No 'arg%d' argument.", i);
209148456Spjd			return;
210148456Spjd		}
211148456Spjd		sc = g_eli_find_device(mp, prov);
212148456Spjd		if (sc == NULL) {
213148456Spjd			gctl_error(req, "No such device: %s.", prov);
214148456Spjd			return;
215148456Spjd		}
216148456Spjd		if (*last) {
217148456Spjd			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
218148456Spjd			sc->sc_geom->access = g_eli_access;
219148456Spjd		} else {
220148456Spjd			error = g_eli_destroy(sc, *force);
221148456Spjd			if (error != 0) {
222148456Spjd				gctl_error(req,
223148456Spjd				    "Cannot destroy device %s (error=%d).",
224148456Spjd				    sc->sc_name, error);
225148456Spjd				return;
226148456Spjd			}
227148456Spjd		}
228148456Spjd	}
229148456Spjd}
230148456Spjd
231148456Spjdstatic void
232148456Spjdg_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
233148456Spjd{
234148456Spjd	struct g_eli_metadata md;
235148456Spjd	struct g_provider *pp;
236148456Spjd	const char *name;
237148456Spjd	intmax_t *keylen, *sectorsize;
238148456Spjd	u_char mkey[G_ELI_DATAIVKEYLEN];
239148456Spjd	int *nargs, *detach;
240148456Spjd
241148456Spjd	g_topology_assert();
242148456Spjd	bzero(&md, sizeof(md));
243148456Spjd
244148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
245148456Spjd	if (nargs == NULL) {
246148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
247148456Spjd		return;
248148456Spjd	}
249148456Spjd	if (*nargs != 1) {
250148456Spjd		gctl_error(req, "Invalid number of arguments.");
251148456Spjd		return;
252148456Spjd	}
253148456Spjd
254148456Spjd	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
255148456Spjd	if (detach == NULL) {
256148456Spjd		gctl_error(req, "No '%s' argument.", "detach");
257148456Spjd		return;
258148456Spjd	}
259148456Spjd
260148456Spjd	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
261148456Spjd	md.md_version = G_ELI_VERSION;
262148456Spjd	md.md_flags |= G_ELI_FLAG_ONETIME;
263148456Spjd	if (*detach)
264148456Spjd		md.md_flags |= G_ELI_FLAG_WO_DETACH;
265148456Spjd
266159361Spjd	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
267159307Spjd	name = gctl_get_asciiparam(req, "aalgo");
268148456Spjd	if (name == NULL) {
269159307Spjd		gctl_error(req, "No '%s' argument.", "aalgo");
270148456Spjd		return;
271148456Spjd	}
272159307Spjd	if (strcmp(name, "none") != 0) {
273159307Spjd		md.md_aalgo = g_eli_str2aalgo(name);
274159361Spjd		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
275159361Spjd		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
276159361Spjd			md.md_flags |= G_ELI_FLAG_AUTH;
277159361Spjd		} else {
278159361Spjd			/*
279159361Spjd			 * For backward compatibility, check if the -a option
280159361Spjd			 * was used to provide encryption algorithm.
281159361Spjd			 */
282159361Spjd			md.md_ealgo = g_eli_str2ealgo(name);
283159361Spjd			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
284159361Spjd			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
285159361Spjd				gctl_error(req,
286159361Spjd				    "Invalid authentication algorithm.");
287159361Spjd				return;
288159361Spjd			} else {
289159361Spjd				gctl_error(req, "warning: The -e option, not "
290159361Spjd				    "the -a option is now used to specify "
291159361Spjd				    "encryption algorithm to use.");
292159361Spjd			}
293159307Spjd		}
294159307Spjd	}
295159307Spjd
296159307Spjd	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
297159307Spjd	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
298159361Spjd		name = gctl_get_asciiparam(req, "ealgo");
299159361Spjd		if (name == NULL) {
300159361Spjd			gctl_error(req, "No '%s' argument.", "ealgo");
301159361Spjd			return;
302159361Spjd		}
303159361Spjd		md.md_ealgo = g_eli_str2ealgo(name);
304159361Spjd		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
305159361Spjd		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
306159361Spjd			gctl_error(req, "Invalid encryption algorithm.");
307159361Spjd			return;
308159361Spjd		}
309159307Spjd	}
310148456Spjd
311148456Spjd	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
312148456Spjd	if (keylen == NULL) {
313148456Spjd		gctl_error(req, "No '%s' argument.", "keylen");
314148456Spjd		return;
315148456Spjd	}
316159307Spjd	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
317148456Spjd	if (md.md_keylen == 0) {
318148456Spjd		gctl_error(req, "Invalid '%s' argument.", "keylen");
319148456Spjd		return;
320148456Spjd	}
321148456Spjd
322148456Spjd	/* Not important here. */
323148456Spjd	md.md_provsize = 0;
324148456Spjd	/* Not important here. */
325148456Spjd	bzero(md.md_salt, sizeof(md.md_salt));
326148456Spjd
327148456Spjd	md.md_keys = 0x01;
328148456Spjd	arc4rand(mkey, sizeof(mkey), 0);
329148456Spjd
330148456Spjd	/* Not important here. */
331148456Spjd	bzero(md.md_hash, sizeof(md.md_hash));
332148456Spjd
333148456Spjd	name = gctl_get_asciiparam(req, "arg0");
334148456Spjd	if (name == NULL) {
335148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
336148456Spjd		return;
337148456Spjd	}
338148456Spjd	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
339148456Spjd		name += strlen("/dev/");
340148456Spjd	pp = g_provider_by_name(name);
341148456Spjd	if (pp == NULL) {
342148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
343148456Spjd		return;
344148456Spjd	}
345148456Spjd
346148456Spjd	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
347148456Spjd	if (sectorsize == NULL) {
348148456Spjd		gctl_error(req, "No '%s' argument.", "sectorsize");
349148456Spjd		return;
350148456Spjd	}
351148456Spjd	if (*sectorsize == 0)
352148456Spjd		md.md_sectorsize = pp->sectorsize;
353148456Spjd	else {
354148456Spjd		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
355148456Spjd			gctl_error(req, "Invalid sector size.");
356148456Spjd			return;
357148456Spjd		}
358148456Spjd		md.md_sectorsize = *sectorsize;
359148456Spjd	}
360148456Spjd
361148456Spjd	g_eli_create(req, mp, pp, &md, mkey, -1);
362148456Spjd	bzero(mkey, sizeof(mkey));
363148456Spjd	bzero(&md, sizeof(md));
364148456Spjd}
365148456Spjd
366148456Spjdstatic void
367148456Spjdg_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
368148456Spjd{
369148456Spjd	struct g_eli_softc *sc;
370148456Spjd	struct g_eli_metadata md;
371148456Spjd	struct g_provider *pp;
372148456Spjd	struct g_consumer *cp;
373148456Spjd	const char *name;
374148456Spjd	u_char *key, *mkeydst, *sector;
375148456Spjd	intmax_t *valp;
376149304Spjd	int keysize, nkey, error;
377148456Spjd
378148456Spjd	g_topology_assert();
379148456Spjd
380148456Spjd	name = gctl_get_asciiparam(req, "arg0");
381148456Spjd	if (name == NULL) {
382148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
383148456Spjd		return;
384148456Spjd	}
385148456Spjd	sc = g_eli_find_device(mp, name);
386148456Spjd	if (sc == NULL) {
387148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
388148456Spjd		return;
389148456Spjd	}
390161127Spjd	if (sc->sc_flags & G_ELI_FLAG_RO) {
391161127Spjd		gctl_error(req, "Cannot change keys for read-only provider.");
392161127Spjd		return;
393161127Spjd	}
394148456Spjd	cp = LIST_FIRST(&sc->sc_geom->consumer);
395148456Spjd	pp = cp->provider;
396148456Spjd
397148456Spjd	error = g_eli_read_metadata(mp, pp, &md);
398148456Spjd	if (error != 0) {
399148456Spjd		gctl_error(req, "Cannot read metadata from %s (error=%d).",
400148456Spjd		    name, error);
401148456Spjd		return;
402148456Spjd	}
403148456Spjd
404148456Spjd	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
405148456Spjd	if (valp == NULL) {
406148456Spjd		gctl_error(req, "No '%s' argument.", "keyno");
407148456Spjd		return;
408148456Spjd	}
409148456Spjd	if (*valp != -1)
410148456Spjd		nkey = *valp;
411148456Spjd	else
412148456Spjd		nkey = sc->sc_nkey;
413148456Spjd	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
414148456Spjd		gctl_error(req, "Invalid '%s' argument.", "keyno");
415148456Spjd		return;
416148456Spjd	}
417148456Spjd
418149304Spjd	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
419149304Spjd	if (valp == NULL) {
420149304Spjd		gctl_error(req, "No '%s' argument.", "iterations");
421149304Spjd		return;
422149304Spjd	}
423149304Spjd	/* Check if iterations number should and can be changed. */
424149304Spjd	if (*valp != -1) {
425149304Spjd		if (bitcount32(md.md_keys) != 1) {
426149304Spjd			gctl_error(req, "To be able to use '-i' option, only "
427149304Spjd			    "one key can be defined.");
428149304Spjd			return;
429149304Spjd		}
430149304Spjd		if (md.md_keys != (1 << nkey)) {
431149304Spjd			gctl_error(req, "Only already defined key can be "
432149304Spjd			    "changed when '-i' option is used.");
433149304Spjd			return;
434149304Spjd		}
435149304Spjd		md.md_iterations = *valp;
436149304Spjd	}
437149304Spjd
438148456Spjd	key = gctl_get_param(req, "key", &keysize);
439148456Spjd	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
440148456Spjd		bzero(&md, sizeof(md));
441148456Spjd		gctl_error(req, "No '%s' argument.", "key");
442148456Spjd		return;
443148456Spjd	}
444148456Spjd
445148456Spjd	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
446148456Spjd	md.md_keys |= (1 << nkey);
447148456Spjd
448159307Spjd	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
449148456Spjd
450148456Spjd	/* Encrypt Master Key with the new key. */
451159307Spjd	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
452148456Spjd	bzero(key, sizeof(key));
453148456Spjd	if (error != 0) {
454148456Spjd		bzero(&md, sizeof(md));
455148456Spjd		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
456148456Spjd		return;
457148456Spjd	}
458148456Spjd
459148456Spjd	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
460148456Spjd	/* Store metadata with fresh key. */
461148456Spjd	eli_metadata_encode(&md, sector);
462148456Spjd	bzero(&md, sizeof(md));
463148456Spjd	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
464148456Spjd	    pp->sectorsize);
465148456Spjd	bzero(sector, sizeof(sector));
466148456Spjd	free(sector, M_ELI);
467148456Spjd	if (error != 0) {
468148456Spjd		gctl_error(req, "Cannot store metadata on %s (error=%d).",
469148456Spjd		    pp->name, error);
470148456Spjd		return;
471148456Spjd	}
472148456Spjd	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
473148456Spjd}
474148456Spjd
475148456Spjdstatic void
476148456Spjdg_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
477148456Spjd{
478148456Spjd	struct g_eli_softc *sc;
479148456Spjd	struct g_eli_metadata md;
480148456Spjd	struct g_provider *pp;
481148456Spjd	struct g_consumer *cp;
482148456Spjd	const char *name;
483148456Spjd	u_char *mkeydst, *sector;
484148456Spjd	intmax_t *valp;
485148456Spjd	size_t keysize;
486148456Spjd	int error, nkey, *all, *force;
487148456Spjd	u_int i;
488148456Spjd
489148456Spjd	g_topology_assert();
490148456Spjd
491148456Spjd	nkey = 0;	/* fixes causeless gcc warning */
492148456Spjd
493148456Spjd	name = gctl_get_asciiparam(req, "arg0");
494148456Spjd	if (name == NULL) {
495148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
496148456Spjd		return;
497148456Spjd	}
498148456Spjd	sc = g_eli_find_device(mp, name);
499148456Spjd	if (sc == NULL) {
500148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
501148456Spjd		return;
502148456Spjd	}
503161127Spjd	if (sc->sc_flags & G_ELI_FLAG_RO) {
504161127Spjd		gctl_error(req, "Cannot delete keys for read-only provider.");
505161127Spjd		return;
506161127Spjd	}
507148456Spjd	cp = LIST_FIRST(&sc->sc_geom->consumer);
508148456Spjd	pp = cp->provider;
509148456Spjd
510148456Spjd	error = g_eli_read_metadata(mp, pp, &md);
511148456Spjd	if (error != 0) {
512148456Spjd		gctl_error(req, "Cannot read metadata from %s (error=%d).",
513148456Spjd		    name, error);
514148456Spjd		return;
515148456Spjd	}
516148456Spjd
517148456Spjd	all = gctl_get_paraml(req, "all", sizeof(*all));
518148456Spjd	if (all == NULL) {
519148456Spjd		gctl_error(req, "No '%s' argument.", "all");
520148456Spjd		return;
521148456Spjd	}
522148456Spjd
523148456Spjd	if (*all) {
524148456Spjd		mkeydst = md.md_mkeys;
525148456Spjd		keysize = sizeof(md.md_mkeys);
526148456Spjd	} else {
527148456Spjd		force = gctl_get_paraml(req, "force", sizeof(*force));
528148456Spjd		if (force == NULL) {
529148456Spjd			gctl_error(req, "No '%s' argument.", "force");
530148456Spjd			return;
531148456Spjd		}
532148456Spjd
533148456Spjd		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
534148456Spjd		if (valp == NULL) {
535148456Spjd			gctl_error(req, "No '%s' argument.", "keyno");
536148456Spjd			return;
537148456Spjd		}
538148456Spjd		if (*valp != -1)
539148456Spjd			nkey = *valp;
540148456Spjd		else
541148456Spjd			nkey = sc->sc_nkey;
542148456Spjd		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
543148456Spjd			gctl_error(req, "Invalid '%s' argument.", "keyno");
544148456Spjd			return;
545148456Spjd		}
546148456Spjd		if (!(md.md_keys & (1 << nkey)) && !*force) {
547148456Spjd			gctl_error(req, "Master Key %u is not set.", nkey);
548148456Spjd			return;
549148456Spjd		}
550148456Spjd		md.md_keys &= ~(1 << nkey);
551148456Spjd		if (md.md_keys == 0 && !*force) {
552148456Spjd			gctl_error(req, "This is the last Master Key. Use '-f' "
553148456Spjd			    "flag if you really want to remove it.");
554148456Spjd			return;
555148456Spjd		}
556148456Spjd		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
557148456Spjd		keysize = G_ELI_MKEYLEN;
558148456Spjd	}
559148456Spjd
560148456Spjd	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
561148456Spjd	for (i = 0; i <= g_eli_overwrites; i++) {
562148456Spjd		if (i == g_eli_overwrites)
563148456Spjd			bzero(mkeydst, keysize);
564148456Spjd		else
565148456Spjd			arc4rand(mkeydst, keysize, 0);
566148456Spjd		/* Store metadata with destroyed key. */
567148456Spjd		eli_metadata_encode(&md, sector);
568148456Spjd		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
569148456Spjd		    pp->sectorsize);
570148456Spjd		if (error != 0) {
571148456Spjd			G_ELI_DEBUG(0, "Cannot store metadata on %s "
572148456Spjd			    "(error=%d).", pp->name, error);
573148456Spjd		}
574148456Spjd	}
575148456Spjd	bzero(&md, sizeof(md));
576148456Spjd	bzero(sector, sizeof(sector));
577148456Spjd	free(sector, M_ELI);
578148456Spjd	if (*all)
579148456Spjd		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
580148456Spjd	else
581148456Spjd		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
582148456Spjd}
583148456Spjd
584148456Spjdstatic int
585148456Spjdg_eli_kill_one(struct g_eli_softc *sc)
586148456Spjd{
587148456Spjd	struct g_provider *pp;
588148456Spjd	struct g_consumer *cp;
589161127Spjd	int error = 0;
590148456Spjd
591148456Spjd	g_topology_assert();
592148456Spjd
593148456Spjd	if (sc == NULL)
594148456Spjd		return (ENOENT);
595148456Spjd
596148456Spjd	pp = LIST_FIRST(&sc->sc_geom->provider);
597148456Spjd	g_error_provider(pp, ENXIO);
598148456Spjd
599148456Spjd	cp = LIST_FIRST(&sc->sc_geom->consumer);
600148456Spjd	pp = cp->provider;
601148456Spjd
602161127Spjd	if (sc->sc_flags & G_ELI_FLAG_RO) {
603161127Spjd		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
604161127Spjd		    "provider: %s.", pp->name);
605161127Spjd	} else {
606161127Spjd		u_char *sector;
607161127Spjd		u_int i;
608161127Spjd		int err;
609161127Spjd
610161127Spjd		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
611161127Spjd		for (i = 0; i <= g_eli_overwrites; i++) {
612161127Spjd			if (i == g_eli_overwrites)
613161127Spjd				bzero(sector, pp->sectorsize);
614161127Spjd			else
615161127Spjd				arc4rand(sector, pp->sectorsize, 0);
616161127Spjd			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
617161127Spjd			    sector, pp->sectorsize);
618161127Spjd			if (err != 0) {
619161127Spjd				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
620161127Spjd				    "(error=%d).", pp->name, err);
621161127Spjd				if (error == 0)
622161127Spjd					error = err;
623161127Spjd			}
624148456Spjd		}
625161127Spjd		free(sector, M_ELI);
626148456Spjd	}
627148456Spjd	if (error == 0)
628148456Spjd		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
629148456Spjd	g_eli_destroy(sc, 1);
630148456Spjd	return (error);
631148456Spjd}
632148456Spjd
633148456Spjdstatic void
634148456Spjdg_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
635148456Spjd{
636148456Spjd	int *all, *nargs;
637148456Spjd	int error;
638148456Spjd
639148456Spjd	g_topology_assert();
640148456Spjd
641148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
642148456Spjd	if (nargs == NULL) {
643148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
644148456Spjd		return;
645148456Spjd	}
646148456Spjd	all = gctl_get_paraml(req, "all", sizeof(*all));
647148456Spjd	if (all == NULL) {
648148456Spjd		gctl_error(req, "No '%s' argument.", "all");
649148456Spjd		return;
650148456Spjd	}
651148456Spjd	if (!*all && *nargs == 0) {
652148456Spjd		gctl_error(req, "Too few arguments.");
653148456Spjd		return;
654148456Spjd	}
655148456Spjd
656148456Spjd	if (*all) {
657148456Spjd		struct g_geom *gp, *gp2;
658148456Spjd
659148456Spjd		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
660148456Spjd			error = g_eli_kill_one(gp->softc);
661148456Spjd			if (error != 0)
662148456Spjd				gctl_error(req, "Not fully done.");
663148456Spjd		}
664148456Spjd	} else {
665148456Spjd		struct g_eli_softc *sc;
666148456Spjd		const char *prov;
667148456Spjd		char param[16];
668148456Spjd		int i;
669148456Spjd
670148456Spjd		for (i = 0; i < *nargs; i++) {
671154463Spjd			snprintf(param, sizeof(param), "arg%d", i);
672148456Spjd			prov = gctl_get_asciiparam(req, param);
673154462Spjd			if (prov == NULL) {
674154462Spjd				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
675154462Spjd				continue;
676154462Spjd			}
677148456Spjd
678148456Spjd			sc = g_eli_find_device(mp, prov);
679148456Spjd			if (sc == NULL) {
680154463Spjd				G_ELI_DEBUG(0, "No such provider: %s.", prov);
681148456Spjd				continue;
682148456Spjd			}
683148456Spjd			error = g_eli_kill_one(sc);
684148456Spjd			if (error != 0)
685148456Spjd				gctl_error(req, "Not fully done.");
686148456Spjd		}
687148456Spjd	}
688148456Spjd}
689148456Spjd
690148456Spjdvoid
691148456Spjdg_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
692148456Spjd{
693148456Spjd	uint32_t *version;
694148456Spjd
695148456Spjd	g_topology_assert();
696148456Spjd
697148456Spjd	version = gctl_get_paraml(req, "version", sizeof(*version));
698148456Spjd	if (version == NULL) {
699148456Spjd		gctl_error(req, "No '%s' argument.", "version");
700148456Spjd		return;
701148456Spjd	}
702148456Spjd	if (*version != G_ELI_VERSION) {
703148456Spjd		gctl_error(req, "Userland and kernel parts are out of sync.");
704148456Spjd		return;
705148456Spjd	}
706148456Spjd
707148456Spjd	if (strcmp(verb, "attach") == 0)
708148456Spjd		g_eli_ctl_attach(req, mp);
709148456Spjd	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
710148456Spjd		g_eli_ctl_detach(req, mp);
711148456Spjd	else if (strcmp(verb, "onetime") == 0)
712148456Spjd		g_eli_ctl_onetime(req, mp);
713148456Spjd	else if (strcmp(verb, "setkey") == 0)
714148456Spjd		g_eli_ctl_setkey(req, mp);
715148456Spjd	else if (strcmp(verb, "delkey") == 0)
716148456Spjd		g_eli_ctl_delkey(req, mp);
717148456Spjd	else if (strcmp(verb, "kill") == 0)
718148456Spjd		g_eli_ctl_kill(req, mp);
719148456Spjd	else
720148456Spjd		gctl_error(req, "Unknown verb.");
721148456Spjd}
722