xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision d056fa046c6a91b90cd98165face0e42a33a5173)
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$");
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 
50 MALLOC_DECLARE(M_ELI);
51 
52 
53 static void
54 g_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 
134 static struct g_eli_softc *
135 g_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 
160 static void
161 g_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 	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 < *nargs; i++) {
192 		snprintf(param, sizeof(param), "arg%d", i);
193 		prov = gctl_get_asciiparam(req, param);
194 		if (prov == NULL) {
195 			gctl_error(req, "No 'arg%d' 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 
218 static void
219 g_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 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
254 	name = gctl_get_asciiparam(req, "aalgo");
255 	if (name == NULL) {
256 		gctl_error(req, "No '%s' argument.", "aalgo");
257 		return;
258 	}
259 	if (strcmp(name, "none") != 0) {
260 		md.md_aalgo = g_eli_str2aalgo(name);
261 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
262 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
263 			md.md_flags |= G_ELI_FLAG_AUTH;
264 		} else {
265 			/*
266 			 * For backward compatibility, check if the -a option
267 			 * was used to provide encryption algorithm.
268 			 */
269 			md.md_ealgo = g_eli_str2ealgo(name);
270 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
271 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
272 				gctl_error(req,
273 				    "Invalid authentication algorithm.");
274 				return;
275 			} else {
276 				gctl_error(req, "warning: The -e option, not "
277 				    "the -a option is now used to specify "
278 				    "encryption algorithm to use.");
279 			}
280 		}
281 	}
282 
283 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
284 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
285 		name = gctl_get_asciiparam(req, "ealgo");
286 		if (name == NULL) {
287 			gctl_error(req, "No '%s' argument.", "ealgo");
288 			return;
289 		}
290 		md.md_ealgo = g_eli_str2ealgo(name);
291 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
292 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
293 			gctl_error(req, "Invalid encryption algorithm.");
294 			return;
295 		}
296 	}
297 
298 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
299 	if (keylen == NULL) {
300 		gctl_error(req, "No '%s' argument.", "keylen");
301 		return;
302 	}
303 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
304 	if (md.md_keylen == 0) {
305 		gctl_error(req, "Invalid '%s' argument.", "keylen");
306 		return;
307 	}
308 
309 	/* Not important here. */
310 	md.md_provsize = 0;
311 	/* Not important here. */
312 	bzero(md.md_salt, sizeof(md.md_salt));
313 
314 	md.md_keys = 0x01;
315 	arc4rand(mkey, sizeof(mkey), 0);
316 
317 	/* Not important here. */
318 	bzero(md.md_hash, sizeof(md.md_hash));
319 
320 	name = gctl_get_asciiparam(req, "arg0");
321 	if (name == NULL) {
322 		gctl_error(req, "No 'arg%u' argument.", 0);
323 		return;
324 	}
325 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
326 		name += strlen("/dev/");
327 	pp = g_provider_by_name(name);
328 	if (pp == NULL) {
329 		gctl_error(req, "Provider %s is invalid.", name);
330 		return;
331 	}
332 
333 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
334 	if (sectorsize == NULL) {
335 		gctl_error(req, "No '%s' argument.", "sectorsize");
336 		return;
337 	}
338 	if (*sectorsize == 0)
339 		md.md_sectorsize = pp->sectorsize;
340 	else {
341 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
342 			gctl_error(req, "Invalid sector size.");
343 			return;
344 		}
345 		md.md_sectorsize = *sectorsize;
346 	}
347 
348 	g_eli_create(req, mp, pp, &md, mkey, -1);
349 	bzero(mkey, sizeof(mkey));
350 	bzero(&md, sizeof(md));
351 }
352 
353 static void
354 g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
355 {
356 	struct g_eli_softc *sc;
357 	struct g_eli_metadata md;
358 	struct g_provider *pp;
359 	struct g_consumer *cp;
360 	const char *name;
361 	u_char *key, *mkeydst, *sector;
362 	intmax_t *valp;
363 	int keysize, nkey, error;
364 
365 	g_topology_assert();
366 
367 	name = gctl_get_asciiparam(req, "arg0");
368 	if (name == NULL) {
369 		gctl_error(req, "No 'arg%u' argument.", 0);
370 		return;
371 	}
372 	sc = g_eli_find_device(mp, name);
373 	if (sc == NULL) {
374 		gctl_error(req, "Provider %s is invalid.", name);
375 		return;
376 	}
377 	cp = LIST_FIRST(&sc->sc_geom->consumer);
378 	pp = cp->provider;
379 
380 	error = g_eli_read_metadata(mp, pp, &md);
381 	if (error != 0) {
382 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
383 		    name, error);
384 		return;
385 	}
386 
387 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
388 	if (valp == NULL) {
389 		gctl_error(req, "No '%s' argument.", "keyno");
390 		return;
391 	}
392 	if (*valp != -1)
393 		nkey = *valp;
394 	else
395 		nkey = sc->sc_nkey;
396 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
397 		gctl_error(req, "Invalid '%s' argument.", "keyno");
398 		return;
399 	}
400 
401 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
402 	if (valp == NULL) {
403 		gctl_error(req, "No '%s' argument.", "iterations");
404 		return;
405 	}
406 	/* Check if iterations number should and can be changed. */
407 	if (*valp != -1) {
408 		if (bitcount32(md.md_keys) != 1) {
409 			gctl_error(req, "To be able to use '-i' option, only "
410 			    "one key can be defined.");
411 			return;
412 		}
413 		if (md.md_keys != (1 << nkey)) {
414 			gctl_error(req, "Only already defined key can be "
415 			    "changed when '-i' option is used.");
416 			return;
417 		}
418 		md.md_iterations = *valp;
419 	}
420 
421 	key = gctl_get_param(req, "key", &keysize);
422 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
423 		bzero(&md, sizeof(md));
424 		gctl_error(req, "No '%s' argument.", "key");
425 		return;
426 	}
427 
428 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
429 	md.md_keys |= (1 << nkey);
430 
431 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
432 
433 	/* Encrypt Master Key with the new key. */
434 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
435 	bzero(key, sizeof(key));
436 	if (error != 0) {
437 		bzero(&md, sizeof(md));
438 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
439 		return;
440 	}
441 
442 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
443 	/* Store metadata with fresh key. */
444 	eli_metadata_encode(&md, sector);
445 	bzero(&md, sizeof(md));
446 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
447 	    pp->sectorsize);
448 	bzero(sector, sizeof(sector));
449 	free(sector, M_ELI);
450 	if (error != 0) {
451 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
452 		    pp->name, error);
453 		return;
454 	}
455 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
456 }
457 
458 static void
459 g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
460 {
461 	struct g_eli_softc *sc;
462 	struct g_eli_metadata md;
463 	struct g_provider *pp;
464 	struct g_consumer *cp;
465 	const char *name;
466 	u_char *mkeydst, *sector;
467 	intmax_t *valp;
468 	size_t keysize;
469 	int error, nkey, *all, *force;
470 	u_int i;
471 
472 	g_topology_assert();
473 
474 	nkey = 0;	/* fixes causeless gcc warning */
475 
476 	name = gctl_get_asciiparam(req, "arg0");
477 	if (name == NULL) {
478 		gctl_error(req, "No 'arg%u' argument.", 0);
479 		return;
480 	}
481 	sc = g_eli_find_device(mp, name);
482 	if (sc == NULL) {
483 		gctl_error(req, "Provider %s is invalid.", name);
484 		return;
485 	}
486 	cp = LIST_FIRST(&sc->sc_geom->consumer);
487 	pp = cp->provider;
488 
489 	error = g_eli_read_metadata(mp, pp, &md);
490 	if (error != 0) {
491 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
492 		    name, error);
493 		return;
494 	}
495 
496 	all = gctl_get_paraml(req, "all", sizeof(*all));
497 	if (all == NULL) {
498 		gctl_error(req, "No '%s' argument.", "all");
499 		return;
500 	}
501 
502 	if (*all) {
503 		mkeydst = md.md_mkeys;
504 		keysize = sizeof(md.md_mkeys);
505 	} else {
506 		force = gctl_get_paraml(req, "force", sizeof(*force));
507 		if (force == NULL) {
508 			gctl_error(req, "No '%s' argument.", "force");
509 			return;
510 		}
511 
512 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
513 		if (valp == NULL) {
514 			gctl_error(req, "No '%s' argument.", "keyno");
515 			return;
516 		}
517 		if (*valp != -1)
518 			nkey = *valp;
519 		else
520 			nkey = sc->sc_nkey;
521 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
522 			gctl_error(req, "Invalid '%s' argument.", "keyno");
523 			return;
524 		}
525 		if (!(md.md_keys & (1 << nkey)) && !*force) {
526 			gctl_error(req, "Master Key %u is not set.", nkey);
527 			return;
528 		}
529 		md.md_keys &= ~(1 << nkey);
530 		if (md.md_keys == 0 && !*force) {
531 			gctl_error(req, "This is the last Master Key. Use '-f' "
532 			    "flag if you really want to remove it.");
533 			return;
534 		}
535 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
536 		keysize = G_ELI_MKEYLEN;
537 	}
538 
539 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
540 	for (i = 0; i <= g_eli_overwrites; i++) {
541 		if (i == g_eli_overwrites)
542 			bzero(mkeydst, keysize);
543 		else
544 			arc4rand(mkeydst, keysize, 0);
545 		/* Store metadata with destroyed key. */
546 		eli_metadata_encode(&md, sector);
547 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
548 		    pp->sectorsize);
549 		if (error != 0) {
550 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
551 			    "(error=%d).", pp->name, error);
552 		}
553 	}
554 	bzero(&md, sizeof(md));
555 	bzero(sector, sizeof(sector));
556 	free(sector, M_ELI);
557 	if (*all)
558 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
559 	else
560 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
561 }
562 
563 static int
564 g_eli_kill_one(struct g_eli_softc *sc)
565 {
566 	struct g_provider *pp;
567 	struct g_consumer *cp;
568 	u_char *sector;
569 	int err, error = 0;
570 	u_int i;
571 
572 	g_topology_assert();
573 
574 	if (sc == NULL)
575 		return (ENOENT);
576 
577 	pp = LIST_FIRST(&sc->sc_geom->provider);
578 	g_error_provider(pp, ENXIO);
579 
580 	cp = LIST_FIRST(&sc->sc_geom->consumer);
581 	pp = cp->provider;
582 
583 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
584 	for (i = 0; i <= g_eli_overwrites; i++) {
585 		if (i == g_eli_overwrites)
586 			bzero(sector, pp->sectorsize);
587 		else
588 			arc4rand(sector, pp->sectorsize, 0);
589 		err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
590 		    pp->sectorsize);
591 		if (err != 0) {
592 			G_ELI_DEBUG(0, "Cannot erase metadata on %s "
593 			    "(error=%d).", pp->name, err);
594 			if (error == 0)
595 				error = err;
596 		}
597 	}
598 	free(sector, M_ELI);
599 	if (error == 0)
600 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
601 	g_eli_destroy(sc, 1);
602 	return (error);
603 }
604 
605 static void
606 g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
607 {
608 	int *all, *nargs;
609 	int error;
610 
611 	g_topology_assert();
612 
613 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
614 	if (nargs == NULL) {
615 		gctl_error(req, "No '%s' argument.", "nargs");
616 		return;
617 	}
618 	all = gctl_get_paraml(req, "all", sizeof(*all));
619 	if (all == NULL) {
620 		gctl_error(req, "No '%s' argument.", "all");
621 		return;
622 	}
623 	if (!*all && *nargs == 0) {
624 		gctl_error(req, "Too few arguments.");
625 		return;
626 	}
627 
628 	if (*all) {
629 		struct g_geom *gp, *gp2;
630 
631 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
632 			error = g_eli_kill_one(gp->softc);
633 			if (error != 0)
634 				gctl_error(req, "Not fully done.");
635 		}
636 	} else {
637 		struct g_eli_softc *sc;
638 		const char *prov;
639 		char param[16];
640 		int i;
641 
642 		for (i = 0; i < *nargs; i++) {
643 			snprintf(param, sizeof(param), "arg%d", i);
644 			prov = gctl_get_asciiparam(req, param);
645 			if (prov == NULL) {
646 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
647 				continue;
648 			}
649 
650 			sc = g_eli_find_device(mp, prov);
651 			if (sc == NULL) {
652 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
653 				continue;
654 			}
655 			error = g_eli_kill_one(sc);
656 			if (error != 0)
657 				gctl_error(req, "Not fully done.");
658 		}
659 	}
660 }
661 
662 void
663 g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
664 {
665 	uint32_t *version;
666 
667 	g_topology_assert();
668 
669 	version = gctl_get_paraml(req, "version", sizeof(*version));
670 	if (version == NULL) {
671 		gctl_error(req, "No '%s' argument.", "version");
672 		return;
673 	}
674 	if (*version != G_ELI_VERSION) {
675 		gctl_error(req, "Userland and kernel parts are out of sync.");
676 		return;
677 	}
678 
679 	if (strcmp(verb, "attach") == 0)
680 		g_eli_ctl_attach(req, mp);
681 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
682 		g_eli_ctl_detach(req, mp);
683 	else if (strcmp(verb, "onetime") == 0)
684 		g_eli_ctl_onetime(req, mp);
685 	else if (strcmp(verb, "setkey") == 0)
686 		g_eli_ctl_setkey(req, mp);
687 	else if (strcmp(verb, "delkey") == 0)
688 		g_eli_ctl_delkey(req, mp);
689 	else if (strcmp(verb, "kill") == 0)
690 		g_eli_ctl_kill(req, mp);
691 	else
692 		gctl_error(req, "Unknown verb.");
693 }
694