g_eli_ctl.c revision 161127
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 161127 2006-08-09 18:11:14Z 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, *readonly;
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	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
83	if (readonly == NULL) {
84		gctl_error(req, "No '%s' argument.", "readonly");
85		return;
86	}
87
88	name = gctl_get_asciiparam(req, "arg0");
89	if (name == NULL) {
90		gctl_error(req, "No 'arg%u' argument.", 0);
91		return;
92	}
93	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
94		name += strlen("/dev/");
95	pp = g_provider_by_name(name);
96	if (pp == NULL) {
97		gctl_error(req, "Provider %s is invalid.", name);
98		return;
99	}
100	error = g_eli_read_metadata(mp, pp, &md);
101	if (error != 0) {
102		gctl_error(req, "Cannot read metadata from %s (error=%d).",
103		    name, error);
104		return;
105	}
106	if (md.md_keys == 0x00) {
107		bzero(&md, sizeof(md));
108		gctl_error(req, "No valid keys on %s.", pp->name);
109		return;
110	}
111
112	key = gctl_get_param(req, "key", &keysize);
113	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
114		bzero(&md, sizeof(md));
115		gctl_error(req, "No '%s' argument.", "key");
116		return;
117	}
118
119	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
120	bzero(key, keysize);
121	if (error == -1) {
122		bzero(&md, sizeof(md));
123		gctl_error(req, "Wrong key for %s.", pp->name);
124		return;
125	} else if (error > 0) {
126		bzero(&md, sizeof(md));
127		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
128		    pp->name, error);
129		return;
130	}
131	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
132
133	if (*detach && *readonly) {
134		bzero(&md, sizeof(md));
135		gctl_error(req, "Options -d and -r are mutually exclusive.",
136		    pp->name, error);
137		return;
138	}
139	if (*detach)
140		md.md_flags |= G_ELI_FLAG_WO_DETACH;
141	if (*readonly)
142		md.md_flags |= G_ELI_FLAG_RO;
143	g_eli_create(req, mp, pp, &md, mkey, nkey);
144	bzero(mkey, sizeof(mkey));
145	bzero(&md, sizeof(md));
146}
147
148static struct g_eli_softc *
149g_eli_find_device(struct g_class *mp, const char *prov)
150{
151	struct g_eli_softc *sc;
152	struct g_geom *gp;
153	struct g_provider *pp;
154	struct g_consumer *cp;
155
156	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
157		prov += strlen("/dev/");
158	LIST_FOREACH(gp, &mp->geom, geom) {
159		sc = gp->softc;
160		if (sc == NULL)
161			continue;
162		pp = LIST_FIRST(&gp->provider);
163		if (pp != NULL && strcmp(pp->name, prov) == 0)
164			return (sc);
165		cp = LIST_FIRST(&gp->consumer);
166		if (cp != NULL && cp->provider != NULL &&
167		    strcmp(cp->provider->name, prov) == 0) {
168			return (sc);
169		}
170	}
171	return (NULL);
172}
173
174static void
175g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
176{
177	struct g_eli_softc *sc;
178	int *force, *last, *nargs, error;
179	const char *prov;
180	char param[16];
181	int i;
182
183	g_topology_assert();
184
185	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
186	if (nargs == NULL) {
187		gctl_error(req, "No '%s' argument.", "nargs");
188		return;
189	}
190	if (*nargs <= 0) {
191		gctl_error(req, "Missing device(s).");
192		return;
193	}
194	force = gctl_get_paraml(req, "force", sizeof(*force));
195	if (force == NULL) {
196		gctl_error(req, "No '%s' argument.", "force");
197		return;
198	}
199	last = gctl_get_paraml(req, "last", sizeof(*last));
200	if (last == NULL) {
201		gctl_error(req, "No '%s' argument.", "last");
202		return;
203	}
204
205	for (i = 0; i < *nargs; i++) {
206		snprintf(param, sizeof(param), "arg%d", i);
207		prov = gctl_get_asciiparam(req, param);
208		if (prov == NULL) {
209			gctl_error(req, "No 'arg%d' argument.", i);
210			return;
211		}
212		sc = g_eli_find_device(mp, prov);
213		if (sc == NULL) {
214			gctl_error(req, "No such device: %s.", prov);
215			return;
216		}
217		if (*last) {
218			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
219			sc->sc_geom->access = g_eli_access;
220		} else {
221			error = g_eli_destroy(sc, *force);
222			if (error != 0) {
223				gctl_error(req,
224				    "Cannot destroy device %s (error=%d).",
225				    sc->sc_name, error);
226				return;
227			}
228		}
229	}
230}
231
232static void
233g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
234{
235	struct g_eli_metadata md;
236	struct g_provider *pp;
237	const char *name;
238	intmax_t *keylen, *sectorsize;
239	u_char mkey[G_ELI_DATAIVKEYLEN];
240	int *nargs, *detach;
241
242	g_topology_assert();
243	bzero(&md, sizeof(md));
244
245	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
246	if (nargs == NULL) {
247		gctl_error(req, "No '%s' argument.", "nargs");
248		return;
249	}
250	if (*nargs != 1) {
251		gctl_error(req, "Invalid number of arguments.");
252		return;
253	}
254
255	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
256	if (detach == NULL) {
257		gctl_error(req, "No '%s' argument.", "detach");
258		return;
259	}
260
261	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
262	md.md_version = G_ELI_VERSION;
263	md.md_flags |= G_ELI_FLAG_ONETIME;
264	if (*detach)
265		md.md_flags |= G_ELI_FLAG_WO_DETACH;
266
267	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
268	name = gctl_get_asciiparam(req, "aalgo");
269	if (name == NULL) {
270		gctl_error(req, "No '%s' argument.", "aalgo");
271		return;
272	}
273	if (strcmp(name, "none") != 0) {
274		md.md_aalgo = g_eli_str2aalgo(name);
275		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
276		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
277			md.md_flags |= G_ELI_FLAG_AUTH;
278		} else {
279			/*
280			 * For backward compatibility, check if the -a option
281			 * was used to provide encryption algorithm.
282			 */
283			md.md_ealgo = g_eli_str2ealgo(name);
284			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
285			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
286				gctl_error(req,
287				    "Invalid authentication algorithm.");
288				return;
289			} else {
290				gctl_error(req, "warning: The -e option, not "
291				    "the -a option is now used to specify "
292				    "encryption algorithm to use.");
293			}
294		}
295	}
296
297	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
298	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
299		name = gctl_get_asciiparam(req, "ealgo");
300		if (name == NULL) {
301			gctl_error(req, "No '%s' argument.", "ealgo");
302			return;
303		}
304		md.md_ealgo = g_eli_str2ealgo(name);
305		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
306		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
307			gctl_error(req, "Invalid encryption algorithm.");
308			return;
309		}
310	}
311
312	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
313	if (keylen == NULL) {
314		gctl_error(req, "No '%s' argument.", "keylen");
315		return;
316	}
317	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
318	if (md.md_keylen == 0) {
319		gctl_error(req, "Invalid '%s' argument.", "keylen");
320		return;
321	}
322
323	/* Not important here. */
324	md.md_provsize = 0;
325	/* Not important here. */
326	bzero(md.md_salt, sizeof(md.md_salt));
327
328	md.md_keys = 0x01;
329	arc4rand(mkey, sizeof(mkey), 0);
330
331	/* Not important here. */
332	bzero(md.md_hash, sizeof(md.md_hash));
333
334	name = gctl_get_asciiparam(req, "arg0");
335	if (name == NULL) {
336		gctl_error(req, "No 'arg%u' argument.", 0);
337		return;
338	}
339	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
340		name += strlen("/dev/");
341	pp = g_provider_by_name(name);
342	if (pp == NULL) {
343		gctl_error(req, "Provider %s is invalid.", name);
344		return;
345	}
346
347	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
348	if (sectorsize == NULL) {
349		gctl_error(req, "No '%s' argument.", "sectorsize");
350		return;
351	}
352	if (*sectorsize == 0)
353		md.md_sectorsize = pp->sectorsize;
354	else {
355		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
356			gctl_error(req, "Invalid sector size.");
357			return;
358		}
359		md.md_sectorsize = *sectorsize;
360	}
361
362	g_eli_create(req, mp, pp, &md, mkey, -1);
363	bzero(mkey, sizeof(mkey));
364	bzero(&md, sizeof(md));
365}
366
367static void
368g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
369{
370	struct g_eli_softc *sc;
371	struct g_eli_metadata md;
372	struct g_provider *pp;
373	struct g_consumer *cp;
374	const char *name;
375	u_char *key, *mkeydst, *sector;
376	intmax_t *valp;
377	int keysize, nkey, error;
378
379	g_topology_assert();
380
381	name = gctl_get_asciiparam(req, "arg0");
382	if (name == NULL) {
383		gctl_error(req, "No 'arg%u' argument.", 0);
384		return;
385	}
386	sc = g_eli_find_device(mp, name);
387	if (sc == NULL) {
388		gctl_error(req, "Provider %s is invalid.", name);
389		return;
390	}
391	if (sc->sc_flags & G_ELI_FLAG_RO) {
392		gctl_error(req, "Cannot change keys for read-only provider.");
393		return;
394	}
395	cp = LIST_FIRST(&sc->sc_geom->consumer);
396	pp = cp->provider;
397
398	error = g_eli_read_metadata(mp, pp, &md);
399	if (error != 0) {
400		gctl_error(req, "Cannot read metadata from %s (error=%d).",
401		    name, error);
402		return;
403	}
404
405	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
406	if (valp == NULL) {
407		gctl_error(req, "No '%s' argument.", "keyno");
408		return;
409	}
410	if (*valp != -1)
411		nkey = *valp;
412	else
413		nkey = sc->sc_nkey;
414	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
415		gctl_error(req, "Invalid '%s' argument.", "keyno");
416		return;
417	}
418
419	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
420	if (valp == NULL) {
421		gctl_error(req, "No '%s' argument.", "iterations");
422		return;
423	}
424	/* Check if iterations number should and can be changed. */
425	if (*valp != -1) {
426		if (bitcount32(md.md_keys) != 1) {
427			gctl_error(req, "To be able to use '-i' option, only "
428			    "one key can be defined.");
429			return;
430		}
431		if (md.md_keys != (1 << nkey)) {
432			gctl_error(req, "Only already defined key can be "
433			    "changed when '-i' option is used.");
434			return;
435		}
436		md.md_iterations = *valp;
437	}
438
439	key = gctl_get_param(req, "key", &keysize);
440	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
441		bzero(&md, sizeof(md));
442		gctl_error(req, "No '%s' argument.", "key");
443		return;
444	}
445
446	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
447	md.md_keys |= (1 << nkey);
448
449	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
450
451	/* Encrypt Master Key with the new key. */
452	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
453	bzero(key, sizeof(key));
454	if (error != 0) {
455		bzero(&md, sizeof(md));
456		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
457		return;
458	}
459
460	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
461	/* Store metadata with fresh key. */
462	eli_metadata_encode(&md, sector);
463	bzero(&md, sizeof(md));
464	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
465	    pp->sectorsize);
466	bzero(sector, sizeof(sector));
467	free(sector, M_ELI);
468	if (error != 0) {
469		gctl_error(req, "Cannot store metadata on %s (error=%d).",
470		    pp->name, error);
471		return;
472	}
473	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
474}
475
476static void
477g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
478{
479	struct g_eli_softc *sc;
480	struct g_eli_metadata md;
481	struct g_provider *pp;
482	struct g_consumer *cp;
483	const char *name;
484	u_char *mkeydst, *sector;
485	intmax_t *valp;
486	size_t keysize;
487	int error, nkey, *all, *force;
488	u_int i;
489
490	g_topology_assert();
491
492	nkey = 0;	/* fixes causeless gcc warning */
493
494	name = gctl_get_asciiparam(req, "arg0");
495	if (name == NULL) {
496		gctl_error(req, "No 'arg%u' argument.", 0);
497		return;
498	}
499	sc = g_eli_find_device(mp, name);
500	if (sc == NULL) {
501		gctl_error(req, "Provider %s is invalid.", name);
502		return;
503	}
504	if (sc->sc_flags & G_ELI_FLAG_RO) {
505		gctl_error(req, "Cannot delete keys for read-only provider.");
506		return;
507	}
508	cp = LIST_FIRST(&sc->sc_geom->consumer);
509	pp = cp->provider;
510
511	error = g_eli_read_metadata(mp, pp, &md);
512	if (error != 0) {
513		gctl_error(req, "Cannot read metadata from %s (error=%d).",
514		    name, error);
515		return;
516	}
517
518	all = gctl_get_paraml(req, "all", sizeof(*all));
519	if (all == NULL) {
520		gctl_error(req, "No '%s' argument.", "all");
521		return;
522	}
523
524	if (*all) {
525		mkeydst = md.md_mkeys;
526		keysize = sizeof(md.md_mkeys);
527	} else {
528		force = gctl_get_paraml(req, "force", sizeof(*force));
529		if (force == NULL) {
530			gctl_error(req, "No '%s' argument.", "force");
531			return;
532		}
533
534		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
535		if (valp == NULL) {
536			gctl_error(req, "No '%s' argument.", "keyno");
537			return;
538		}
539		if (*valp != -1)
540			nkey = *valp;
541		else
542			nkey = sc->sc_nkey;
543		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
544			gctl_error(req, "Invalid '%s' argument.", "keyno");
545			return;
546		}
547		if (!(md.md_keys & (1 << nkey)) && !*force) {
548			gctl_error(req, "Master Key %u is not set.", nkey);
549			return;
550		}
551		md.md_keys &= ~(1 << nkey);
552		if (md.md_keys == 0 && !*force) {
553			gctl_error(req, "This is the last Master Key. Use '-f' "
554			    "flag if you really want to remove it.");
555			return;
556		}
557		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
558		keysize = G_ELI_MKEYLEN;
559	}
560
561	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
562	for (i = 0; i <= g_eli_overwrites; i++) {
563		if (i == g_eli_overwrites)
564			bzero(mkeydst, keysize);
565		else
566			arc4rand(mkeydst, keysize, 0);
567		/* Store metadata with destroyed key. */
568		eli_metadata_encode(&md, sector);
569		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
570		    pp->sectorsize);
571		if (error != 0) {
572			G_ELI_DEBUG(0, "Cannot store metadata on %s "
573			    "(error=%d).", pp->name, error);
574		}
575	}
576	bzero(&md, sizeof(md));
577	bzero(sector, sizeof(sector));
578	free(sector, M_ELI);
579	if (*all)
580		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
581	else
582		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
583}
584
585static int
586g_eli_kill_one(struct g_eli_softc *sc)
587{
588	struct g_provider *pp;
589	struct g_consumer *cp;
590	int error = 0;
591
592	g_topology_assert();
593
594	if (sc == NULL)
595		return (ENOENT);
596
597	pp = LIST_FIRST(&sc->sc_geom->provider);
598	g_error_provider(pp, ENXIO);
599
600	cp = LIST_FIRST(&sc->sc_geom->consumer);
601	pp = cp->provider;
602
603	if (sc->sc_flags & G_ELI_FLAG_RO) {
604		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
605		    "provider: %s.", pp->name);
606	} else {
607		u_char *sector;
608		u_int i;
609		int err;
610
611		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
612		for (i = 0; i <= g_eli_overwrites; i++) {
613			if (i == g_eli_overwrites)
614				bzero(sector, pp->sectorsize);
615			else
616				arc4rand(sector, pp->sectorsize, 0);
617			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
618			    sector, pp->sectorsize);
619			if (err != 0) {
620				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
621				    "(error=%d).", pp->name, err);
622				if (error == 0)
623					error = err;
624			}
625		}
626		free(sector, M_ELI);
627	}
628	if (error == 0)
629		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
630	g_eli_destroy(sc, 1);
631	return (error);
632}
633
634static void
635g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
636{
637	int *all, *nargs;
638	int error;
639
640	g_topology_assert();
641
642	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
643	if (nargs == NULL) {
644		gctl_error(req, "No '%s' argument.", "nargs");
645		return;
646	}
647	all = gctl_get_paraml(req, "all", sizeof(*all));
648	if (all == NULL) {
649		gctl_error(req, "No '%s' argument.", "all");
650		return;
651	}
652	if (!*all && *nargs == 0) {
653		gctl_error(req, "Too few arguments.");
654		return;
655	}
656
657	if (*all) {
658		struct g_geom *gp, *gp2;
659
660		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
661			error = g_eli_kill_one(gp->softc);
662			if (error != 0)
663				gctl_error(req, "Not fully done.");
664		}
665	} else {
666		struct g_eli_softc *sc;
667		const char *prov;
668		char param[16];
669		int i;
670
671		for (i = 0; i < *nargs; i++) {
672			snprintf(param, sizeof(param), "arg%d", i);
673			prov = gctl_get_asciiparam(req, param);
674			if (prov == NULL) {
675				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
676				continue;
677			}
678
679			sc = g_eli_find_device(mp, prov);
680			if (sc == NULL) {
681				G_ELI_DEBUG(0, "No such provider: %s.", prov);
682				continue;
683			}
684			error = g_eli_kill_one(sc);
685			if (error != 0)
686				gctl_error(req, "Not fully done.");
687		}
688	}
689}
690
691void
692g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
693{
694	uint32_t *version;
695
696	g_topology_assert();
697
698	version = gctl_get_paraml(req, "version", sizeof(*version));
699	if (version == NULL) {
700		gctl_error(req, "No '%s' argument.", "version");
701		return;
702	}
703	if (*version != G_ELI_VERSION) {
704		gctl_error(req, "Userland and kernel parts are out of sync.");
705		return;
706	}
707
708	if (strcmp(verb, "attach") == 0)
709		g_eli_ctl_attach(req, mp);
710	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
711		g_eli_ctl_detach(req, mp);
712	else if (strcmp(verb, "onetime") == 0)
713		g_eli_ctl_onetime(req, mp);
714	else if (strcmp(verb, "setkey") == 0)
715		g_eli_ctl_setkey(req, mp);
716	else if (strcmp(verb, "delkey") == 0)
717		g_eli_ctl_delkey(req, mp);
718	else if (strcmp(verb, "kill") == 0)
719		g_eli_ctl_kill(req, mp);
720	else
721		gctl_error(req, "Unknown verb.");
722}
723