g_eli_ctl.c revision 148456
1/*-
2 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 148456 2005-07-27 21:43:37Z pjd $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <sys/module.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/bio.h>
37#include <sys/sysctl.h>
38#include <sys/malloc.h>
39#include <sys/kthread.h>
40#include <sys/proc.h>
41#include <sys/sched.h>
42#include <sys/uio.h>
43
44#include <vm/uma.h>
45
46#include <geom/geom.h>
47#include <geom/eli/g_eli.h>
48
49
50MALLOC_DECLARE(M_ELI);
51
52
53static void
54g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
55{
56	struct g_eli_metadata md;
57	struct g_provider *pp;
58	const char *name;
59	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
60	int *nargs, *detach;
61	int keysize, error;
62	u_int nkey;
63
64	g_topology_assert();
65
66	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
67	if (nargs == NULL) {
68		gctl_error(req, "No '%s' argument.", "nargs");
69		return;
70	}
71	if (*nargs != 1) {
72		gctl_error(req, "Invalid number of arguments.");
73		return;
74	}
75
76	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
77	if (detach == NULL) {
78		gctl_error(req, "No '%s' argument.", "detach");
79		return;
80	}
81
82	name = gctl_get_asciiparam(req, "arg0");
83	if (name == NULL) {
84		gctl_error(req, "No 'arg%u' argument.", 0);
85		return;
86	}
87	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
88		name += strlen("/dev/");
89	pp = g_provider_by_name(name);
90	if (pp == NULL) {
91		gctl_error(req, "Provider %s is invalid.", name);
92		return;
93	}
94	error = g_eli_read_metadata(mp, pp, &md);
95	if (error != 0) {
96		gctl_error(req, "Cannot read metadata from %s (error=%d).",
97		    name, error);
98		return;
99	}
100	if (md.md_keys == 0x00) {
101		bzero(&md, sizeof(md));
102		gctl_error(req, "No valid keys on %s.", pp->name);
103		return;
104	}
105
106	key = gctl_get_param(req, "key", &keysize);
107	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
108		bzero(&md, sizeof(md));
109		gctl_error(req, "No '%s' argument.", "key");
110		return;
111	}
112
113	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
114	bzero(key, keysize);
115	if (error == -1) {
116		bzero(&md, sizeof(md));
117		gctl_error(req, "Wrong key for %s.", pp->name);
118		return;
119	} else if (error > 0) {
120		bzero(&md, sizeof(md));
121		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
122		    pp->name, error);
123		return;
124	}
125	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
126
127	if (*detach)
128		md.md_flags |= G_ELI_FLAG_WO_DETACH;
129	g_eli_create(req, mp, pp, &md, mkey, nkey);
130	bzero(mkey, sizeof(mkey));
131	bzero(&md, sizeof(md));
132}
133
134static struct g_eli_softc *
135g_eli_find_device(struct g_class *mp, const char *prov)
136{
137	struct g_eli_softc *sc;
138	struct g_geom *gp;
139	struct g_provider *pp;
140	struct g_consumer *cp;
141
142	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
143		prov += strlen("/dev/");
144	LIST_FOREACH(gp, &mp->geom, geom) {
145		sc = gp->softc;
146		if (sc == NULL)
147			continue;
148		pp = LIST_FIRST(&gp->provider);
149		if (pp != NULL && strcmp(pp->name, prov) == 0)
150			return (sc);
151		cp = LIST_FIRST(&gp->consumer);
152		if (cp != NULL && cp->provider != NULL &&
153		    strcmp(cp->provider->name, prov) == 0) {
154			return (sc);
155		}
156	}
157	return (NULL);
158}
159
160static void
161g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
162{
163	struct g_eli_softc *sc;
164	int *force, *last, *nargs, error;
165	const char *prov;
166	char param[16];
167	u_int i;
168
169	g_topology_assert();
170
171	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
172	if (nargs == NULL) {
173		gctl_error(req, "No '%s' argument.", "nargs");
174		return;
175	}
176	if (*nargs <= 0) {
177		gctl_error(req, "Missing device(s).");
178		return;
179	}
180	force = gctl_get_paraml(req, "force", sizeof(*force));
181	if (force == NULL) {
182		gctl_error(req, "No '%s' argument.", "force");
183		return;
184	}
185	last = gctl_get_paraml(req, "last", sizeof(*last));
186	if (last == NULL) {
187		gctl_error(req, "No '%s' argument.", "last");
188		return;
189	}
190
191	for (i = 0; i < (u_int)*nargs; i++) {
192		snprintf(param, sizeof(param), "arg%u", i);
193		prov = gctl_get_asciiparam(req, param);
194		if (prov == NULL) {
195			gctl_error(req, "No 'arg%u' argument.", i);
196			return;
197		}
198		sc = g_eli_find_device(mp, prov);
199		if (sc == NULL) {
200			gctl_error(req, "No such device: %s.", prov);
201			return;
202		}
203		if (*last) {
204			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
205			sc->sc_geom->access = g_eli_access;
206		} else {
207			error = g_eli_destroy(sc, *force);
208			if (error != 0) {
209				gctl_error(req,
210				    "Cannot destroy device %s (error=%d).",
211				    sc->sc_name, error);
212				return;
213			}
214		}
215	}
216}
217
218static void
219g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
220{
221	struct g_eli_metadata md;
222	struct g_provider *pp;
223	const char *name;
224	intmax_t *keylen, *sectorsize;
225	u_char mkey[G_ELI_DATAIVKEYLEN];
226	int *nargs, *detach;
227
228	g_topology_assert();
229	bzero(&md, sizeof(md));
230
231	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
232	if (nargs == NULL) {
233		gctl_error(req, "No '%s' argument.", "nargs");
234		return;
235	}
236	if (*nargs != 1) {
237		gctl_error(req, "Invalid number of arguments.");
238		return;
239	}
240
241	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
242	if (detach == NULL) {
243		gctl_error(req, "No '%s' argument.", "detach");
244		return;
245	}
246
247	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
248	md.md_version = G_ELI_VERSION;
249	md.md_flags |= G_ELI_FLAG_ONETIME;
250	if (*detach)
251		md.md_flags |= G_ELI_FLAG_WO_DETACH;
252
253	name = gctl_get_asciiparam(req, "algo");
254	if (name == NULL) {
255		gctl_error(req, "No '%s' argument.", "algo");
256		return;
257	}
258	md.md_algo = g_eli_str2algo(name);
259	if (md.md_algo < CRYPTO_ALGORITHM_MIN ||
260	    md.md_algo > CRYPTO_ALGORITHM_MAX) {
261		gctl_error(req, "Invalid '%s' argument.", "algo");
262		return;
263	}
264
265	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
266	if (keylen == NULL) {
267		gctl_error(req, "No '%s' argument.", "keylen");
268		return;
269	}
270	md.md_keylen = g_eli_keylen(md.md_algo, *keylen);
271	if (md.md_keylen == 0) {
272		gctl_error(req, "Invalid '%s' argument.", "keylen");
273		return;
274	}
275
276	/* Not important here. */
277	md.md_provsize = 0;
278	/* Not important here. */
279	bzero(md.md_salt, sizeof(md.md_salt));
280
281	md.md_keys = 0x01;
282	arc4rand(mkey, sizeof(mkey), 0);
283
284	/* Not important here. */
285	bzero(md.md_hash, sizeof(md.md_hash));
286
287	name = gctl_get_asciiparam(req, "arg0");
288	if (name == NULL) {
289		gctl_error(req, "No 'arg%u' argument.", 0);
290		return;
291	}
292	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
293		name += strlen("/dev/");
294	pp = g_provider_by_name(name);
295	if (pp == NULL) {
296		gctl_error(req, "Provider %s is invalid.", name);
297		return;
298	}
299
300	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
301	if (sectorsize == NULL) {
302		gctl_error(req, "No '%s' argument.", "sectorsize");
303		return;
304	}
305	if (*sectorsize == 0)
306		md.md_sectorsize = pp->sectorsize;
307	else {
308		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
309			gctl_error(req, "Invalid sector size.");
310			return;
311		}
312		md.md_sectorsize = *sectorsize;
313	}
314
315	g_eli_create(req, mp, pp, &md, mkey, -1);
316	bzero(mkey, sizeof(mkey));
317	bzero(&md, sizeof(md));
318}
319
320static void
321g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
322{
323	struct g_eli_softc *sc;
324	struct g_eli_metadata md;
325	struct g_provider *pp;
326	struct g_consumer *cp;
327	const char *name;
328	u_char *key, *mkeydst, *sector;
329	intmax_t *valp;
330	int nkey;
331	int keysize, error;
332
333	g_topology_assert();
334
335	name = gctl_get_asciiparam(req, "arg0");
336	if (name == NULL) {
337		gctl_error(req, "No 'arg%u' argument.", 0);
338		return;
339	}
340	sc = g_eli_find_device(mp, name);
341	if (sc == NULL) {
342		gctl_error(req, "Provider %s is invalid.", name);
343		return;
344	}
345	cp = LIST_FIRST(&sc->sc_geom->consumer);
346	pp = cp->provider;
347
348	error = g_eli_read_metadata(mp, pp, &md);
349	if (error != 0) {
350		gctl_error(req, "Cannot read metadata from %s (error=%d).",
351		    name, error);
352		return;
353	}
354
355	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
356	if (valp == NULL) {
357		gctl_error(req, "No '%s' argument.", "keyno");
358		return;
359	}
360	if (*valp != -1)
361		nkey = *valp;
362	else
363		nkey = sc->sc_nkey;
364	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
365		gctl_error(req, "Invalid '%s' argument.", "keyno");
366		return;
367	}
368
369	key = gctl_get_param(req, "key", &keysize);
370	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
371		bzero(&md, sizeof(md));
372		gctl_error(req, "No '%s' argument.", "key");
373		return;
374	}
375
376	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
377	md.md_keys |= (1 << nkey);
378
379	bcopy(sc->sc_ivkey, mkeydst, sizeof(sc->sc_ivkey));
380	bcopy(sc->sc_datakey, mkeydst + sizeof(sc->sc_ivkey),
381	    sizeof(sc->sc_datakey));
382
383	/* Encrypt Master Key with the new key. */
384	error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst);
385	bzero(key, sizeof(key));
386	if (error != 0) {
387		bzero(&md, sizeof(md));
388		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
389		return;
390	}
391
392	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
393	/* Store metadata with fresh key. */
394	eli_metadata_encode(&md, sector);
395	bzero(&md, sizeof(md));
396	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
397	    pp->sectorsize);
398	bzero(sector, sizeof(sector));
399	free(sector, M_ELI);
400	if (error != 0) {
401		gctl_error(req, "Cannot store metadata on %s (error=%d).",
402		    pp->name, error);
403		return;
404	}
405	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
406}
407
408static void
409g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
410{
411	struct g_eli_softc *sc;
412	struct g_eli_metadata md;
413	struct g_provider *pp;
414	struct g_consumer *cp;
415	const char *name;
416	u_char *mkeydst, *sector;
417	intmax_t *valp;
418	size_t keysize;
419	int error, nkey, *all, *force;
420	u_int i;
421
422	g_topology_assert();
423
424	nkey = 0;	/* fixes causeless gcc warning */
425
426	name = gctl_get_asciiparam(req, "arg0");
427	if (name == NULL) {
428		gctl_error(req, "No 'arg%u' argument.", 0);
429		return;
430	}
431	sc = g_eli_find_device(mp, name);
432	if (sc == NULL) {
433		gctl_error(req, "Provider %s is invalid.", name);
434		return;
435	}
436	cp = LIST_FIRST(&sc->sc_geom->consumer);
437	pp = cp->provider;
438
439	error = g_eli_read_metadata(mp, pp, &md);
440	if (error != 0) {
441		gctl_error(req, "Cannot read metadata from %s (error=%d).",
442		    name, error);
443		return;
444	}
445
446	all = gctl_get_paraml(req, "all", sizeof(*all));
447	if (all == NULL) {
448		gctl_error(req, "No '%s' argument.", "all");
449		return;
450	}
451
452	if (*all) {
453		mkeydst = md.md_mkeys;
454		keysize = sizeof(md.md_mkeys);
455	} else {
456		force = gctl_get_paraml(req, "force", sizeof(*force));
457		if (force == NULL) {
458			gctl_error(req, "No '%s' argument.", "force");
459			return;
460		}
461
462		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
463		if (valp == NULL) {
464			gctl_error(req, "No '%s' argument.", "keyno");
465			return;
466		}
467		if (*valp != -1)
468			nkey = *valp;
469		else
470			nkey = sc->sc_nkey;
471		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
472			gctl_error(req, "Invalid '%s' argument.", "keyno");
473			return;
474		}
475		if (!(md.md_keys & (1 << nkey)) && !*force) {
476			gctl_error(req, "Master Key %u is not set.", nkey);
477			return;
478		}
479		md.md_keys &= ~(1 << nkey);
480		if (md.md_keys == 0 && !*force) {
481			gctl_error(req, "This is the last Master Key. Use '-f' "
482			    "flag if you really want to remove it.");
483			return;
484		}
485		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
486		keysize = G_ELI_MKEYLEN;
487	}
488
489	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
490	for (i = 0; i <= g_eli_overwrites; i++) {
491		if (i == g_eli_overwrites)
492			bzero(mkeydst, keysize);
493		else
494			arc4rand(mkeydst, keysize, 0);
495		/* Store metadata with destroyed key. */
496		eli_metadata_encode(&md, sector);
497		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
498		    pp->sectorsize);
499		if (error != 0) {
500			G_ELI_DEBUG(0, "Cannot store metadata on %s "
501			    "(error=%d).", pp->name, error);
502		}
503	}
504	bzero(&md, sizeof(md));
505	bzero(sector, sizeof(sector));
506	free(sector, M_ELI);
507	if (*all)
508		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
509	else
510		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
511}
512
513static int
514g_eli_kill_one(struct g_eli_softc *sc)
515{
516	struct g_provider *pp;
517	struct g_consumer *cp;
518	u_char *sector;
519	int err, error = 0;
520	u_int i;
521
522	g_topology_assert();
523
524	if (sc == NULL)
525		return (ENOENT);
526
527	pp = LIST_FIRST(&sc->sc_geom->provider);
528	g_error_provider(pp, ENXIO);
529
530	cp = LIST_FIRST(&sc->sc_geom->consumer);
531	pp = cp->provider;
532
533	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
534	for (i = 0; i <= g_eli_overwrites; i++) {
535		if (i == g_eli_overwrites)
536			bzero(sector, pp->sectorsize);
537		else
538			arc4rand(sector, pp->sectorsize, 0);
539		err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
540		    pp->sectorsize);
541		if (err != 0) {
542			G_ELI_DEBUG(0, "Cannot erase metadata on %s "
543			    "(error=%d).", pp->name, err);
544			if (error == 0)
545				error = err;
546		}
547	}
548	free(sector, M_ELI);
549	if (error == 0)
550		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
551	g_eli_destroy(sc, 1);
552	return (error);
553}
554
555static void
556g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
557{
558	int *all, *nargs;
559	int error;
560
561	g_topology_assert();
562
563	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
564	if (nargs == NULL) {
565		gctl_error(req, "No '%s' argument.", "nargs");
566		return;
567	}
568	all = gctl_get_paraml(req, "all", sizeof(*all));
569	if (all == NULL) {
570		gctl_error(req, "No '%s' argument.", "all");
571		return;
572	}
573	if (!*all && *nargs == 0) {
574		gctl_error(req, "Too few arguments.");
575		return;
576	}
577
578	if (*all) {
579		struct g_geom *gp, *gp2;
580
581		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
582			error = g_eli_kill_one(gp->softc);
583			if (error != 0)
584				gctl_error(req, "Not fully done.");
585		}
586	} else {
587		struct g_eli_softc *sc;
588		const char *prov;
589		char param[16];
590		int i;
591
592		for (i = 0; i < *nargs; i++) {
593			snprintf(param, sizeof(param), "arg%u", i);
594			prov = gctl_get_asciiparam(req, param);
595
596			sc = g_eli_find_device(mp, prov);
597			if (sc == NULL) {
598				G_ELI_DEBUG(1, "No such provider: %s.", prov);
599				continue;
600			}
601			error = g_eli_kill_one(sc);
602			if (error != 0)
603				gctl_error(req, "Not fully done.");
604		}
605	}
606}
607
608void
609g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
610{
611	uint32_t *version;
612
613	g_topology_assert();
614
615	version = gctl_get_paraml(req, "version", sizeof(*version));
616	if (version == NULL) {
617		gctl_error(req, "No '%s' argument.", "version");
618		return;
619	}
620	if (*version != G_ELI_VERSION) {
621		gctl_error(req, "Userland and kernel parts are out of sync.");
622		return;
623	}
624
625	if (strcmp(verb, "attach") == 0)
626		g_eli_ctl_attach(req, mp);
627	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
628		g_eli_ctl_detach(req, mp);
629	else if (strcmp(verb, "onetime") == 0)
630		g_eli_ctl_onetime(req, mp);
631	else if (strcmp(verb, "setkey") == 0)
632		g_eli_ctl_setkey(req, mp);
633	else if (strcmp(verb, "delkey") == 0)
634		g_eli_ctl_delkey(req, mp);
635	else if (strcmp(verb, "kill") == 0)
636		g_eli_ctl_kill(req, mp);
637	else
638		gctl_error(req, "Unknown verb.");
639}
640