xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision 262e143bd46171a6415a5b28af260a5efa2a3db8)
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 	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 
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 	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 
320 static void
321 g_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 keysize, nkey, error;
331 
332 	g_topology_assert();
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 	sc = g_eli_find_device(mp, name);
340 	if (sc == NULL) {
341 		gctl_error(req, "Provider %s is invalid.", name);
342 		return;
343 	}
344 	cp = LIST_FIRST(&sc->sc_geom->consumer);
345 	pp = cp->provider;
346 
347 	error = g_eli_read_metadata(mp, pp, &md);
348 	if (error != 0) {
349 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
350 		    name, error);
351 		return;
352 	}
353 
354 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
355 	if (valp == NULL) {
356 		gctl_error(req, "No '%s' argument.", "keyno");
357 		return;
358 	}
359 	if (*valp != -1)
360 		nkey = *valp;
361 	else
362 		nkey = sc->sc_nkey;
363 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
364 		gctl_error(req, "Invalid '%s' argument.", "keyno");
365 		return;
366 	}
367 
368 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
369 	if (valp == NULL) {
370 		gctl_error(req, "No '%s' argument.", "iterations");
371 		return;
372 	}
373 	/* Check if iterations number should and can be changed. */
374 	if (*valp != -1) {
375 		if (bitcount32(md.md_keys) != 1) {
376 			gctl_error(req, "To be able to use '-i' option, only "
377 			    "one key can be defined.");
378 			return;
379 		}
380 		if (md.md_keys != (1 << nkey)) {
381 			gctl_error(req, "Only already defined key can be "
382 			    "changed when '-i' option is used.");
383 			return;
384 		}
385 		md.md_iterations = *valp;
386 	}
387 
388 	key = gctl_get_param(req, "key", &keysize);
389 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
390 		bzero(&md, sizeof(md));
391 		gctl_error(req, "No '%s' argument.", "key");
392 		return;
393 	}
394 
395 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
396 	md.md_keys |= (1 << nkey);
397 
398 	bcopy(sc->sc_ivkey, mkeydst, sizeof(sc->sc_ivkey));
399 	bcopy(sc->sc_datakey, mkeydst + sizeof(sc->sc_ivkey),
400 	    sizeof(sc->sc_datakey));
401 
402 	/* Encrypt Master Key with the new key. */
403 	error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst);
404 	bzero(key, sizeof(key));
405 	if (error != 0) {
406 		bzero(&md, sizeof(md));
407 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
408 		return;
409 	}
410 
411 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
412 	/* Store metadata with fresh key. */
413 	eli_metadata_encode(&md, sector);
414 	bzero(&md, sizeof(md));
415 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
416 	    pp->sectorsize);
417 	bzero(sector, sizeof(sector));
418 	free(sector, M_ELI);
419 	if (error != 0) {
420 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
421 		    pp->name, error);
422 		return;
423 	}
424 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
425 }
426 
427 static void
428 g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
429 {
430 	struct g_eli_softc *sc;
431 	struct g_eli_metadata md;
432 	struct g_provider *pp;
433 	struct g_consumer *cp;
434 	const char *name;
435 	u_char *mkeydst, *sector;
436 	intmax_t *valp;
437 	size_t keysize;
438 	int error, nkey, *all, *force;
439 	u_int i;
440 
441 	g_topology_assert();
442 
443 	nkey = 0;	/* fixes causeless gcc warning */
444 
445 	name = gctl_get_asciiparam(req, "arg0");
446 	if (name == NULL) {
447 		gctl_error(req, "No 'arg%u' argument.", 0);
448 		return;
449 	}
450 	sc = g_eli_find_device(mp, name);
451 	if (sc == NULL) {
452 		gctl_error(req, "Provider %s is invalid.", name);
453 		return;
454 	}
455 	cp = LIST_FIRST(&sc->sc_geom->consumer);
456 	pp = cp->provider;
457 
458 	error = g_eli_read_metadata(mp, pp, &md);
459 	if (error != 0) {
460 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
461 		    name, error);
462 		return;
463 	}
464 
465 	all = gctl_get_paraml(req, "all", sizeof(*all));
466 	if (all == NULL) {
467 		gctl_error(req, "No '%s' argument.", "all");
468 		return;
469 	}
470 
471 	if (*all) {
472 		mkeydst = md.md_mkeys;
473 		keysize = sizeof(md.md_mkeys);
474 	} else {
475 		force = gctl_get_paraml(req, "force", sizeof(*force));
476 		if (force == NULL) {
477 			gctl_error(req, "No '%s' argument.", "force");
478 			return;
479 		}
480 
481 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
482 		if (valp == NULL) {
483 			gctl_error(req, "No '%s' argument.", "keyno");
484 			return;
485 		}
486 		if (*valp != -1)
487 			nkey = *valp;
488 		else
489 			nkey = sc->sc_nkey;
490 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
491 			gctl_error(req, "Invalid '%s' argument.", "keyno");
492 			return;
493 		}
494 		if (!(md.md_keys & (1 << nkey)) && !*force) {
495 			gctl_error(req, "Master Key %u is not set.", nkey);
496 			return;
497 		}
498 		md.md_keys &= ~(1 << nkey);
499 		if (md.md_keys == 0 && !*force) {
500 			gctl_error(req, "This is the last Master Key. Use '-f' "
501 			    "flag if you really want to remove it.");
502 			return;
503 		}
504 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
505 		keysize = G_ELI_MKEYLEN;
506 	}
507 
508 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
509 	for (i = 0; i <= g_eli_overwrites; i++) {
510 		if (i == g_eli_overwrites)
511 			bzero(mkeydst, keysize);
512 		else
513 			arc4rand(mkeydst, keysize, 0);
514 		/* Store metadata with destroyed key. */
515 		eli_metadata_encode(&md, sector);
516 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
517 		    pp->sectorsize);
518 		if (error != 0) {
519 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
520 			    "(error=%d).", pp->name, error);
521 		}
522 	}
523 	bzero(&md, sizeof(md));
524 	bzero(sector, sizeof(sector));
525 	free(sector, M_ELI);
526 	if (*all)
527 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
528 	else
529 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
530 }
531 
532 static int
533 g_eli_kill_one(struct g_eli_softc *sc)
534 {
535 	struct g_provider *pp;
536 	struct g_consumer *cp;
537 	u_char *sector;
538 	int err, error = 0;
539 	u_int i;
540 
541 	g_topology_assert();
542 
543 	if (sc == NULL)
544 		return (ENOENT);
545 
546 	pp = LIST_FIRST(&sc->sc_geom->provider);
547 	g_error_provider(pp, ENXIO);
548 
549 	cp = LIST_FIRST(&sc->sc_geom->consumer);
550 	pp = cp->provider;
551 
552 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
553 	for (i = 0; i <= g_eli_overwrites; i++) {
554 		if (i == g_eli_overwrites)
555 			bzero(sector, pp->sectorsize);
556 		else
557 			arc4rand(sector, pp->sectorsize, 0);
558 		err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
559 		    pp->sectorsize);
560 		if (err != 0) {
561 			G_ELI_DEBUG(0, "Cannot erase metadata on %s "
562 			    "(error=%d).", pp->name, err);
563 			if (error == 0)
564 				error = err;
565 		}
566 	}
567 	free(sector, M_ELI);
568 	if (error == 0)
569 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
570 	g_eli_destroy(sc, 1);
571 	return (error);
572 }
573 
574 static void
575 g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
576 {
577 	int *all, *nargs;
578 	int error;
579 
580 	g_topology_assert();
581 
582 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
583 	if (nargs == NULL) {
584 		gctl_error(req, "No '%s' argument.", "nargs");
585 		return;
586 	}
587 	all = gctl_get_paraml(req, "all", sizeof(*all));
588 	if (all == NULL) {
589 		gctl_error(req, "No '%s' argument.", "all");
590 		return;
591 	}
592 	if (!*all && *nargs == 0) {
593 		gctl_error(req, "Too few arguments.");
594 		return;
595 	}
596 
597 	if (*all) {
598 		struct g_geom *gp, *gp2;
599 
600 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
601 			error = g_eli_kill_one(gp->softc);
602 			if (error != 0)
603 				gctl_error(req, "Not fully done.");
604 		}
605 	} else {
606 		struct g_eli_softc *sc;
607 		const char *prov;
608 		char param[16];
609 		int i;
610 
611 		for (i = 0; i < *nargs; i++) {
612 			snprintf(param, sizeof(param), "arg%u", i);
613 			prov = gctl_get_asciiparam(req, param);
614 
615 			sc = g_eli_find_device(mp, prov);
616 			if (sc == NULL) {
617 				G_ELI_DEBUG(1, "No such provider: %s.", prov);
618 				continue;
619 			}
620 			error = g_eli_kill_one(sc);
621 			if (error != 0)
622 				gctl_error(req, "Not fully done.");
623 		}
624 	}
625 }
626 
627 void
628 g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
629 {
630 	uint32_t *version;
631 
632 	g_topology_assert();
633 
634 	version = gctl_get_paraml(req, "version", sizeof(*version));
635 	if (version == NULL) {
636 		gctl_error(req, "No '%s' argument.", "version");
637 		return;
638 	}
639 	if (*version != G_ELI_VERSION) {
640 		gctl_error(req, "Userland and kernel parts are out of sync.");
641 		return;
642 	}
643 
644 	if (strcmp(verb, "attach") == 0)
645 		g_eli_ctl_attach(req, mp);
646 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
647 		g_eli_ctl_detach(req, mp);
648 	else if (strcmp(verb, "onetime") == 0)
649 		g_eli_ctl_onetime(req, mp);
650 	else if (strcmp(verb, "setkey") == 0)
651 		g_eli_ctl_setkey(req, mp);
652 	else if (strcmp(verb, "delkey") == 0)
653 		g_eli_ctl_delkey(req, mp);
654 	else if (strcmp(verb, "kill") == 0)
655 		g_eli_ctl_kill(req, mp);
656 	else
657 		gctl_error(req, "Unknown verb.");
658 }
659