]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/geom/eli/g_eli_ctl.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / geom / eli / g_eli_ctl.c
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, *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                 return;
137         }
138         if (*detach)
139                 md.md_flags |= G_ELI_FLAG_WO_DETACH;
140         if (*readonly)
141                 md.md_flags |= G_ELI_FLAG_RO;
142         g_eli_create(req, mp, pp, &md, mkey, nkey);
143         bzero(mkey, sizeof(mkey));
144         bzero(&md, sizeof(md));
145 }
146
147 static struct g_eli_softc *
148 g_eli_find_device(struct g_class *mp, const char *prov)
149 {
150         struct g_eli_softc *sc;
151         struct g_geom *gp;
152         struct g_provider *pp;
153         struct g_consumer *cp;
154
155         if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
156                 prov += strlen("/dev/");
157         LIST_FOREACH(gp, &mp->geom, geom) {
158                 sc = gp->softc;
159                 if (sc == NULL)
160                         continue;
161                 pp = LIST_FIRST(&gp->provider);
162                 if (pp != NULL && strcmp(pp->name, prov) == 0)
163                         return (sc);
164                 cp = LIST_FIRST(&gp->consumer);
165                 if (cp != NULL && cp->provider != NULL &&
166                     strcmp(cp->provider->name, prov) == 0) {
167                         return (sc);
168                 }
169         }
170         return (NULL);
171 }
172
173 static void
174 g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
175 {
176         struct g_eli_softc *sc;
177         int *force, *last, *nargs, error;
178         const char *prov;
179         char param[16];
180         int i;
181
182         g_topology_assert();
183
184         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
185         if (nargs == NULL) {
186                 gctl_error(req, "No '%s' argument.", "nargs");
187                 return;
188         }
189         if (*nargs <= 0) {
190                 gctl_error(req, "Missing device(s).");
191                 return;
192         }
193         force = gctl_get_paraml(req, "force", sizeof(*force));
194         if (force == NULL) {
195                 gctl_error(req, "No '%s' argument.", "force");
196                 return;
197         }
198         last = gctl_get_paraml(req, "last", sizeof(*last));
199         if (last == NULL) {
200                 gctl_error(req, "No '%s' argument.", "last");
201                 return;
202         }
203
204         for (i = 0; i < *nargs; i++) {
205                 snprintf(param, sizeof(param), "arg%d", i);
206                 prov = gctl_get_asciiparam(req, param);
207                 if (prov == NULL) {
208                         gctl_error(req, "No 'arg%d' argument.", i);
209                         return;
210                 }
211                 sc = g_eli_find_device(mp, prov);
212                 if (sc == NULL) {
213                         gctl_error(req, "No such device: %s.", prov);
214                         return;
215                 }
216                 if (*last) {
217                         sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
218                         sc->sc_geom->access = g_eli_access;
219                 } else {
220                         error = g_eli_destroy(sc, *force);
221                         if (error != 0) {
222                                 gctl_error(req,
223                                     "Cannot destroy device %s (error=%d).",
224                                     sc->sc_name, error);
225                                 return;
226                         }
227                 }
228         }
229 }
230
231 static void
232 g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
233 {
234         struct g_eli_metadata md;
235         struct g_provider *pp;
236         const char *name;
237         intmax_t *keylen, *sectorsize;
238         u_char mkey[G_ELI_DATAIVKEYLEN];
239         int *nargs, *detach;
240
241         g_topology_assert();
242         bzero(&md, sizeof(md));
243
244         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
245         if (nargs == NULL) {
246                 gctl_error(req, "No '%s' argument.", "nargs");
247                 return;
248         }
249         if (*nargs != 1) {
250                 gctl_error(req, "Invalid number of arguments.");
251                 return;
252         }
253
254         detach = gctl_get_paraml(req, "detach", sizeof(*detach));
255         if (detach == NULL) {
256                 gctl_error(req, "No '%s' argument.", "detach");
257                 return;
258         }
259
260         strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
261         md.md_version = G_ELI_VERSION;
262         md.md_flags |= G_ELI_FLAG_ONETIME;
263         if (*detach)
264                 md.md_flags |= G_ELI_FLAG_WO_DETACH;
265
266         md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
267         name = gctl_get_asciiparam(req, "aalgo");
268         if (name == NULL) {
269                 gctl_error(req, "No '%s' argument.", "aalgo");
270                 return;
271         }
272         if (strcmp(name, "none") != 0) {
273                 md.md_aalgo = g_eli_str2aalgo(name);
274                 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
275                     md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
276                         md.md_flags |= G_ELI_FLAG_AUTH;
277                 } else {
278                         /*
279                          * For backward compatibility, check if the -a option
280                          * was used to provide encryption algorithm.
281                          */
282                         md.md_ealgo = g_eli_str2ealgo(name);
283                         if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
284                             md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
285                                 gctl_error(req,
286                                     "Invalid authentication algorithm.");
287                                 return;
288                         } else {
289                                 gctl_error(req, "warning: The -e option, not "
290                                     "the -a option is now used to specify "
291                                     "encryption algorithm to use.");
292                         }
293                 }
294         }
295
296         if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
297             md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
298                 name = gctl_get_asciiparam(req, "ealgo");
299                 if (name == NULL) {
300                         gctl_error(req, "No '%s' argument.", "ealgo");
301                         return;
302                 }
303                 md.md_ealgo = g_eli_str2ealgo(name);
304                 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
305                     md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
306                         gctl_error(req, "Invalid encryption algorithm.");
307                         return;
308                 }
309         }
310
311         keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
312         if (keylen == NULL) {
313                 gctl_error(req, "No '%s' argument.", "keylen");
314                 return;
315         }
316         md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
317         if (md.md_keylen == 0) {
318                 gctl_error(req, "Invalid '%s' argument.", "keylen");
319                 return;
320         }
321
322         /* Not important here. */
323         md.md_provsize = 0;
324         /* Not important here. */
325         bzero(md.md_salt, sizeof(md.md_salt));
326
327         md.md_keys = 0x01;
328         arc4rand(mkey, sizeof(mkey), 0);
329
330         /* Not important here. */
331         bzero(md.md_hash, sizeof(md.md_hash));
332
333         name = gctl_get_asciiparam(req, "arg0");
334         if (name == NULL) {
335                 gctl_error(req, "No 'arg%u' argument.", 0);
336                 return;
337         }
338         if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
339                 name += strlen("/dev/");
340         pp = g_provider_by_name(name);
341         if (pp == NULL) {
342                 gctl_error(req, "Provider %s is invalid.", name);
343                 return;
344         }
345
346         sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
347         if (sectorsize == NULL) {
348                 gctl_error(req, "No '%s' argument.", "sectorsize");
349                 return;
350         }
351         if (*sectorsize == 0)
352                 md.md_sectorsize = pp->sectorsize;
353         else {
354                 if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
355                         gctl_error(req, "Invalid sector size.");
356                         return;
357                 }
358                 if (*sectorsize > PAGE_SIZE) {
359                         gctl_error(req, "warning: Using sectorsize bigger than "
360                             "the page size!");
361                 }
362                 md.md_sectorsize = *sectorsize;
363         }
364
365         g_eli_create(req, mp, pp, &md, mkey, -1);
366         bzero(mkey, sizeof(mkey));
367         bzero(&md, sizeof(md));
368 }
369
370 static void
371 g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
372 {
373         struct g_eli_softc *sc;
374         struct g_eli_metadata md;
375         struct g_provider *pp;
376         struct g_consumer *cp;
377         char param[16];
378         const char *prov;
379         u_char *sector;
380         int *nargs, *boot, *noboot;
381         int error;
382         u_int i;
383
384         g_topology_assert();
385
386         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
387         if (nargs == NULL) {
388                 gctl_error(req, "No '%s' argument.", "nargs");
389                 return;
390         }
391         if (*nargs <= 0) {
392                 gctl_error(req, "Missing device(s).");
393                 return;
394         }
395
396         boot = gctl_get_paraml(req, "boot", sizeof(*boot));
397         if (boot == NULL) {
398                 gctl_error(req, "No '%s' argument.", "boot");
399                 return;
400         }
401         noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
402         if (noboot == NULL) {
403                 gctl_error(req, "No '%s' argument.", "noboot");
404                 return;
405         }
406         if (*boot && *noboot) {
407                 gctl_error(req, "Options -b and -B are mutually exclusive.");
408                 return;
409         }
410         if (!*boot && !*noboot) {
411                 gctl_error(req, "No option given.");
412                 return;
413         }
414
415         for (i = 0; i < *nargs; i++) {
416                 snprintf(param, sizeof(param), "arg%d", i);
417                 prov = gctl_get_asciiparam(req, param);
418                 if (prov == NULL) {
419                         gctl_error(req, "No 'arg%d' argument.", i);
420                         return;
421                 }
422                 sc = g_eli_find_device(mp, prov);
423                 if (sc == NULL) {
424                         /*
425                          * We ignore not attached providers, userland part will
426                          * take care of them.
427                          */
428                         G_ELI_DEBUG(1, "Skipping configuration of not attached "
429                             "provider %s.", prov);
430                         continue;
431                 }
432                 if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
433                         G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
434                             prov);
435                         continue;
436                 } else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
437                         G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
438                             prov);
439                         continue;
440                 }
441                 if (sc->sc_flags & G_ELI_FLAG_RO) {
442                         gctl_error(req, "Cannot change configuration of "
443                             "read-only provider %s.", prov);
444                         continue;
445                 }
446                 cp = LIST_FIRST(&sc->sc_geom->consumer);
447                 pp = cp->provider;
448                 error = g_eli_read_metadata(mp, pp, &md);
449                 if (error != 0) {
450                         gctl_error(req,
451                             "Cannot read metadata from %s (error=%d).",
452                             prov, error);
453                         continue;
454                 }
455
456                 if (*boot) {
457                         md.md_flags |= G_ELI_FLAG_BOOT;
458                         sc->sc_flags |= G_ELI_FLAG_BOOT;
459                 } else {
460                         md.md_flags &= ~G_ELI_FLAG_BOOT;
461                         sc->sc_flags &= ~G_ELI_FLAG_BOOT;
462                 }
463
464                 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
465                 eli_metadata_encode(&md, sector);
466                 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
467                     pp->sectorsize);
468                 if (error != 0) {
469                         gctl_error(req,
470                             "Cannot store metadata on %s (error=%d).",
471                             prov, error);
472                 }
473                 bzero(&md, sizeof(md));
474                 bzero(sector, sizeof(sector));
475                 free(sector, M_ELI);
476         }
477 }
478
479 static void
480 g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
481 {
482         struct g_eli_softc *sc;
483         struct g_eli_metadata md;
484         struct g_provider *pp;
485         struct g_consumer *cp;
486         const char *name;
487         u_char *key, *mkeydst, *sector;
488         intmax_t *valp;
489         int keysize, nkey, error;
490
491         g_topology_assert();
492
493         name = gctl_get_asciiparam(req, "arg0");
494         if (name == NULL) {
495                 gctl_error(req, "No 'arg%u' argument.", 0);
496                 return;
497         }
498         sc = g_eli_find_device(mp, name);
499         if (sc == NULL) {
500                 gctl_error(req, "Provider %s is invalid.", name);
501                 return;
502         }
503         if (sc->sc_flags & G_ELI_FLAG_RO) {
504                 gctl_error(req, "Cannot change keys for read-only provider.");
505                 return;
506         }
507         cp = LIST_FIRST(&sc->sc_geom->consumer);
508         pp = cp->provider;
509
510         error = g_eli_read_metadata(mp, pp, &md);
511         if (error != 0) {
512                 gctl_error(req, "Cannot read metadata from %s (error=%d).",
513                     name, error);
514                 return;
515         }
516
517         valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
518         if (valp == NULL) {
519                 gctl_error(req, "No '%s' argument.", "keyno");
520                 return;
521         }
522         if (*valp != -1)
523                 nkey = *valp;
524         else
525                 nkey = sc->sc_nkey;
526         if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
527                 gctl_error(req, "Invalid '%s' argument.", "keyno");
528                 return;
529         }
530
531         valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
532         if (valp == NULL) {
533                 gctl_error(req, "No '%s' argument.", "iterations");
534                 return;
535         }
536         /* Check if iterations number should and can be changed. */
537         if (*valp != -1) {
538                 if (bitcount32(md.md_keys) != 1) {
539                         gctl_error(req, "To be able to use '-i' option, only "
540                             "one key can be defined.");
541                         return;
542                 }
543                 if (md.md_keys != (1 << nkey)) {
544                         gctl_error(req, "Only already defined key can be "
545                             "changed when '-i' option is used.");
546                         return;
547                 }
548                 md.md_iterations = *valp;
549         }
550
551         key = gctl_get_param(req, "key", &keysize);
552         if (key == NULL || keysize != G_ELI_USERKEYLEN) {
553                 bzero(&md, sizeof(md));
554                 gctl_error(req, "No '%s' argument.", "key");
555                 return;
556         }
557
558         mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
559         md.md_keys |= (1 << nkey);
560
561         bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
562
563         /* Encrypt Master Key with the new key. */
564         error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
565         bzero(key, sizeof(key));
566         if (error != 0) {
567                 bzero(&md, sizeof(md));
568                 gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
569                 return;
570         }
571
572         sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
573         /* Store metadata with fresh key. */
574         eli_metadata_encode(&md, sector);
575         bzero(&md, sizeof(md));
576         error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
577             pp->sectorsize);
578         bzero(sector, sizeof(sector));
579         free(sector, M_ELI);
580         if (error != 0) {
581                 gctl_error(req, "Cannot store metadata on %s (error=%d).",
582                     pp->name, error);
583                 return;
584         }
585         G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
586 }
587
588 static void
589 g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
590 {
591         struct g_eli_softc *sc;
592         struct g_eli_metadata md;
593         struct g_provider *pp;
594         struct g_consumer *cp;
595         const char *name;
596         u_char *mkeydst, *sector;
597         intmax_t *valp;
598         size_t keysize;
599         int error, nkey, *all, *force;
600         u_int i;
601
602         g_topology_assert();
603
604         nkey = 0;       /* fixes causeless gcc warning */
605
606         name = gctl_get_asciiparam(req, "arg0");
607         if (name == NULL) {
608                 gctl_error(req, "No 'arg%u' argument.", 0);
609                 return;
610         }
611         sc = g_eli_find_device(mp, name);
612         if (sc == NULL) {
613                 gctl_error(req, "Provider %s is invalid.", name);
614                 return;
615         }
616         if (sc->sc_flags & G_ELI_FLAG_RO) {
617                 gctl_error(req, "Cannot delete keys for read-only provider.");
618                 return;
619         }
620         cp = LIST_FIRST(&sc->sc_geom->consumer);
621         pp = cp->provider;
622
623         error = g_eli_read_metadata(mp, pp, &md);
624         if (error != 0) {
625                 gctl_error(req, "Cannot read metadata from %s (error=%d).",
626                     name, error);
627                 return;
628         }
629
630         all = gctl_get_paraml(req, "all", sizeof(*all));
631         if (all == NULL) {
632                 gctl_error(req, "No '%s' argument.", "all");
633                 return;
634         }
635
636         if (*all) {
637                 mkeydst = md.md_mkeys;
638                 keysize = sizeof(md.md_mkeys);
639         } else {
640                 force = gctl_get_paraml(req, "force", sizeof(*force));
641                 if (force == NULL) {
642                         gctl_error(req, "No '%s' argument.", "force");
643                         return;
644                 }
645
646                 valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
647                 if (valp == NULL) {
648                         gctl_error(req, "No '%s' argument.", "keyno");
649                         return;
650                 }
651                 if (*valp != -1)
652                         nkey = *valp;
653                 else
654                         nkey = sc->sc_nkey;
655                 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
656                         gctl_error(req, "Invalid '%s' argument.", "keyno");
657                         return;
658                 }
659                 if (!(md.md_keys & (1 << nkey)) && !*force) {
660                         gctl_error(req, "Master Key %u is not set.", nkey);
661                         return;
662                 }
663                 md.md_keys &= ~(1 << nkey);
664                 if (md.md_keys == 0 && !*force) {
665                         gctl_error(req, "This is the last Master Key. Use '-f' "
666                             "flag if you really want to remove it.");
667                         return;
668                 }
669                 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
670                 keysize = G_ELI_MKEYLEN;
671         }
672
673         sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
674         for (i = 0; i <= g_eli_overwrites; i++) {
675                 if (i == g_eli_overwrites)
676                         bzero(mkeydst, keysize);
677                 else
678                         arc4rand(mkeydst, keysize, 0);
679                 /* Store metadata with destroyed key. */
680                 eli_metadata_encode(&md, sector);
681                 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
682                     pp->sectorsize);
683                 if (error != 0) {
684                         G_ELI_DEBUG(0, "Cannot store metadata on %s "
685                             "(error=%d).", pp->name, error);
686                 }
687                 /*
688                  * Flush write cache so we don't overwrite data N times in cache
689                  * and only once on disk.
690                  */
691                 g_io_flush(cp);
692         }
693         bzero(&md, sizeof(md));
694         bzero(sector, sizeof(sector));
695         free(sector, M_ELI);
696         if (*all)
697                 G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
698         else
699                 G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
700 }
701
702 static int
703 g_eli_kill_one(struct g_eli_softc *sc)
704 {
705         struct g_provider *pp;
706         struct g_consumer *cp;
707         int error = 0;
708
709         g_topology_assert();
710
711         if (sc == NULL)
712                 return (ENOENT);
713
714         pp = LIST_FIRST(&sc->sc_geom->provider);
715         g_error_provider(pp, ENXIO);
716
717         cp = LIST_FIRST(&sc->sc_geom->consumer);
718         pp = cp->provider;
719
720         if (sc->sc_flags & G_ELI_FLAG_RO) {
721                 G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
722                     "provider: %s.", pp->name);
723         } else {
724                 u_char *sector;
725                 u_int i;
726                 int err;
727
728                 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
729                 for (i = 0; i <= g_eli_overwrites; i++) {
730                         if (i == g_eli_overwrites)
731                                 bzero(sector, pp->sectorsize);
732                         else
733                                 arc4rand(sector, pp->sectorsize, 0);
734                         err = g_write_data(cp, pp->mediasize - pp->sectorsize,
735                             sector, pp->sectorsize);
736                         if (err != 0) {
737                                 G_ELI_DEBUG(0, "Cannot erase metadata on %s "
738                                     "(error=%d).", pp->name, err);
739                                 if (error == 0)
740                                         error = err;
741                         }
742                 }
743                 free(sector, M_ELI);
744         }
745         if (error == 0)
746                 G_ELI_DEBUG(0, "%s has been killed.", pp->name);
747         g_eli_destroy(sc, 1);
748         return (error);
749 }
750
751 static void
752 g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
753 {
754         int *all, *nargs;
755         int error;
756
757         g_topology_assert();
758
759         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
760         if (nargs == NULL) {
761                 gctl_error(req, "No '%s' argument.", "nargs");
762                 return;
763         }
764         all = gctl_get_paraml(req, "all", sizeof(*all));
765         if (all == NULL) {
766                 gctl_error(req, "No '%s' argument.", "all");
767                 return;
768         }
769         if (!*all && *nargs == 0) {
770                 gctl_error(req, "Too few arguments.");
771                 return;
772         }
773
774         if (*all) {
775                 struct g_geom *gp, *gp2;
776
777                 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
778                         error = g_eli_kill_one(gp->softc);
779                         if (error != 0)
780                                 gctl_error(req, "Not fully done.");
781                 }
782         } else {
783                 struct g_eli_softc *sc;
784                 const char *prov;
785                 char param[16];
786                 int i;
787
788                 for (i = 0; i < *nargs; i++) {
789                         snprintf(param, sizeof(param), "arg%d", i);
790                         prov = gctl_get_asciiparam(req, param);
791                         if (prov == NULL) {
792                                 G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
793                                 continue;
794                         }
795
796                         sc = g_eli_find_device(mp, prov);
797                         if (sc == NULL) {
798                                 G_ELI_DEBUG(0, "No such provider: %s.", prov);
799                                 continue;
800                         }
801                         error = g_eli_kill_one(sc);
802                         if (error != 0)
803                                 gctl_error(req, "Not fully done.");
804                 }
805         }
806 }
807
808 void
809 g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
810 {
811         uint32_t *version;
812
813         g_topology_assert();
814
815         version = gctl_get_paraml(req, "version", sizeof(*version));
816         if (version == NULL) {
817                 gctl_error(req, "No '%s' argument.", "version");
818                 return;
819         }
820         if (*version != G_ELI_VERSION) {
821                 gctl_error(req, "Userland and kernel parts are out of sync.");
822                 return;
823         }
824
825         if (strcmp(verb, "attach") == 0)
826                 g_eli_ctl_attach(req, mp);
827         else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
828                 g_eli_ctl_detach(req, mp);
829         else if (strcmp(verb, "onetime") == 0)
830                 g_eli_ctl_onetime(req, mp);
831         else if (strcmp(verb, "configure") == 0)
832                 g_eli_ctl_configure(req, mp);
833         else if (strcmp(verb, "setkey") == 0)
834                 g_eli_ctl_setkey(req, mp);
835         else if (strcmp(verb, "delkey") == 0)
836                 g_eli_ctl_delkey(req, mp);
837         else if (strcmp(verb, "kill") == 0)
838                 g_eli_ctl_kill(req, mp);
839         else
840                 gctl_error(req, "Unknown verb.");
841 }