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 162353 2006-09-16 10:43:17Z 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 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
147static struct g_eli_softc *
148g_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
173static void
174g_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
231static void
232g_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 md.md_sectorsize = *sectorsize;
359 }
360
361 g_eli_create(req, mp, pp, &md, mkey, -1);
362 bzero(mkey, sizeof(mkey));
363 bzero(&md, sizeof(md));
364}
365
366static void
367g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
368{
369 struct g_eli_softc *sc;
370 struct g_eli_metadata md;
371 struct g_provider *pp;
372 struct g_consumer *cp;
373 char param[16];
374 const char *prov;
375 u_char *sector;
376 int *nargs, *boot, *noboot;
377 int error;
378 u_int i;
379
380 g_topology_assert();
381
382 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
383 if (nargs == NULL) {
384 gctl_error(req, "No '%s' argument.", "nargs");
385 return;
386 }
387 if (*nargs <= 0) {
388 gctl_error(req, "Missing device(s).");
389 return;
390 }
391
392 boot = gctl_get_paraml(req, "boot", sizeof(*boot));
393 if (boot == NULL) {
394 gctl_error(req, "No '%s' argument.", "boot");
395 return;
396 }
397 noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
398 if (noboot == NULL) {
399 gctl_error(req, "No '%s' argument.", "noboot");
400 return;
401 }
402 if (*boot && *noboot) {
403 gctl_error(req, "Options -b and -B are mutually exclusive.");
404 return;
405 }
406 if (!*boot && !*noboot) {
407 gctl_error(req, "No option given.");
408 return;
409 }
410
411 for (i = 0; i < *nargs; i++) {
412 snprintf(param, sizeof(param), "arg%d", i);
413 prov = gctl_get_asciiparam(req, param);
414 if (prov == NULL) {
415 gctl_error(req, "No 'arg%d' argument.", i);
416 return;
417 }
418 sc = g_eli_find_device(mp, prov);
419 if (sc == NULL) {
420 /*
421 * We ignore not attached providers, userland part will
422 * take care of them.
423 */
424 G_ELI_DEBUG(1, "Skipping configuration of not attached "
425 "provider %s.", prov);
426 continue;
427 }
428 if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
429 G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
430 prov);
431 continue;
432 } else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
433 G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
434 prov);
435 continue;
436 }
437 if (sc->sc_flags & G_ELI_FLAG_RO) {
438 gctl_error(req, "Cannot change configuration of "
439 "read-only provider %s.", prov);
440 continue;
441 }
442 cp = LIST_FIRST(&sc->sc_geom->consumer);
443 pp = cp->provider;
444 error = g_eli_read_metadata(mp, pp, &md);
445 if (error != 0) {
446 gctl_error(req,
447 "Cannot read metadata from %s (error=%d).",
448 prov, error);
449 continue;
450 }
451
452 if (*boot) {
453 md.md_flags |= G_ELI_FLAG_BOOT;
454 sc->sc_flags |= G_ELI_FLAG_BOOT;
455 } else {
456 md.md_flags &= ~G_ELI_FLAG_BOOT;
457 sc->sc_flags &= ~G_ELI_FLAG_BOOT;
458 }
459
460 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
461 eli_metadata_encode(&md, sector);
462 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
463 pp->sectorsize);
464 if (error != 0) {
465 gctl_error(req,
466 "Cannot store metadata on %s (error=%d).",
467 prov, error);
468 }
469 bzero(&md, sizeof(md));
470 bzero(sector, sizeof(sector));
471 free(sector, M_ELI);
472 }
473}
474
475static void
476g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
477{
478 struct g_eli_softc *sc;
479 struct g_eli_metadata md;
480 struct g_provider *pp;
481 struct g_consumer *cp;
482 const char *name;
483 u_char *key, *mkeydst, *sector;
484 intmax_t *valp;
485 int keysize, nkey, error;
486
487 g_topology_assert();
488
489 name = gctl_get_asciiparam(req, "arg0");
490 if (name == NULL) {
491 gctl_error(req, "No 'arg%u' argument.", 0);
492 return;
493 }
494 sc = g_eli_find_device(mp, name);
495 if (sc == NULL) {
496 gctl_error(req, "Provider %s is invalid.", name);
497 return;
498 }
499 if (sc->sc_flags & G_ELI_FLAG_RO) {
500 gctl_error(req, "Cannot change keys for read-only provider.");
501 return;
502 }
503 cp = LIST_FIRST(&sc->sc_geom->consumer);
504 pp = cp->provider;
505
506 error = g_eli_read_metadata(mp, pp, &md);
507 if (error != 0) {
508 gctl_error(req, "Cannot read metadata from %s (error=%d).",
509 name, error);
510 return;
511 }
512
513 valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
514 if (valp == NULL) {
515 gctl_error(req, "No '%s' argument.", "keyno");
516 return;
517 }
518 if (*valp != -1)
519 nkey = *valp;
520 else
521 nkey = sc->sc_nkey;
522 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
523 gctl_error(req, "Invalid '%s' argument.", "keyno");
524 return;
525 }
526
527 valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
528 if (valp == NULL) {
529 gctl_error(req, "No '%s' argument.", "iterations");
530 return;
531 }
532 /* Check if iterations number should and can be changed. */
533 if (*valp != -1) {
534 if (bitcount32(md.md_keys) != 1) {
535 gctl_error(req, "To be able to use '-i' option, only "
536 "one key can be defined.");
537 return;
538 }
539 if (md.md_keys != (1 << nkey)) {
540 gctl_error(req, "Only already defined key can be "
541 "changed when '-i' option is used.");
542 return;
543 }
544 md.md_iterations = *valp;
545 }
546
547 key = gctl_get_param(req, "key", &keysize);
548 if (key == NULL || keysize != G_ELI_USERKEYLEN) {
549 bzero(&md, sizeof(md));
550 gctl_error(req, "No '%s' argument.", "key");
551 return;
552 }
553
554 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
555 md.md_keys |= (1 << nkey);
556
557 bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
558
559 /* Encrypt Master Key with the new key. */
560 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
561 bzero(key, sizeof(key));
562 if (error != 0) {
563 bzero(&md, sizeof(md));
564 gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
565 return;
566 }
567
568 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
569 /* Store metadata with fresh key. */
570 eli_metadata_encode(&md, sector);
571 bzero(&md, sizeof(md));
572 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
573 pp->sectorsize);
574 bzero(sector, sizeof(sector));
575 free(sector, M_ELI);
576 if (error != 0) {
577 gctl_error(req, "Cannot store metadata on %s (error=%d).",
578 pp->name, error);
579 return;
580 }
581 G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
582}
583
584static void
585g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
586{
587 struct g_eli_softc *sc;
588 struct g_eli_metadata md;
589 struct g_provider *pp;
590 struct g_consumer *cp;
591 const char *name;
592 u_char *mkeydst, *sector;
593 intmax_t *valp;
594 size_t keysize;
595 int error, nkey, *all, *force;
596 u_int i;
597
598 g_topology_assert();
599
600 nkey = 0; /* fixes causeless gcc warning */
601
602 name = gctl_get_asciiparam(req, "arg0");
603 if (name == NULL) {
604 gctl_error(req, "No 'arg%u' argument.", 0);
605 return;
606 }
607 sc = g_eli_find_device(mp, name);
608 if (sc == NULL) {
609 gctl_error(req, "Provider %s is invalid.", name);
610 return;
611 }
612 if (sc->sc_flags & G_ELI_FLAG_RO) {
613 gctl_error(req, "Cannot delete keys for read-only provider.");
614 return;
615 }
616 cp = LIST_FIRST(&sc->sc_geom->consumer);
617 pp = cp->provider;
618
619 error = g_eli_read_metadata(mp, pp, &md);
620 if (error != 0) {
621 gctl_error(req, "Cannot read metadata from %s (error=%d).",
622 name, error);
623 return;
624 }
625
626 all = gctl_get_paraml(req, "all", sizeof(*all));
627 if (all == NULL) {
628 gctl_error(req, "No '%s' argument.", "all");
629 return;
630 }
631
632 if (*all) {
633 mkeydst = md.md_mkeys;
634 keysize = sizeof(md.md_mkeys);
635 } else {
636 force = gctl_get_paraml(req, "force", sizeof(*force));
637 if (force == NULL) {
638 gctl_error(req, "No '%s' argument.", "force");
639 return;
640 }
641
642 valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
643 if (valp == NULL) {
644 gctl_error(req, "No '%s' argument.", "keyno");
645 return;
646 }
647 if (*valp != -1)
648 nkey = *valp;
649 else
650 nkey = sc->sc_nkey;
651 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
652 gctl_error(req, "Invalid '%s' argument.", "keyno");
653 return;
654 }
655 if (!(md.md_keys & (1 << nkey)) && !*force) {
656 gctl_error(req, "Master Key %u is not set.", nkey);
657 return;
658 }
659 md.md_keys &= ~(1 << nkey);
660 if (md.md_keys == 0 && !*force) {
661 gctl_error(req, "This is the last Master Key. Use '-f' "
662 "flag if you really want to remove it.");
663 return;
664 }
665 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
666 keysize = G_ELI_MKEYLEN;
667 }
668
669 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
670 for (i = 0; i <= g_eli_overwrites; i++) {
671 if (i == g_eli_overwrites)
672 bzero(mkeydst, keysize);
673 else
674 arc4rand(mkeydst, keysize, 0);
675 /* Store metadata with destroyed key. */
676 eli_metadata_encode(&md, sector);
677 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
678 pp->sectorsize);
679 if (error != 0) {
680 G_ELI_DEBUG(0, "Cannot store metadata on %s "
681 "(error=%d).", pp->name, error);
682 }
683 }
684 bzero(&md, sizeof(md));
685 bzero(sector, sizeof(sector));
686 free(sector, M_ELI);
687 if (*all)
688 G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
689 else
690 G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
691}
692
693static int
694g_eli_kill_one(struct g_eli_softc *sc)
695{
696 struct g_provider *pp;
697 struct g_consumer *cp;
698 int error = 0;
699
700 g_topology_assert();
701
702 if (sc == NULL)
703 return (ENOENT);
704
705 pp = LIST_FIRST(&sc->sc_geom->provider);
706 g_error_provider(pp, ENXIO);
707
708 cp = LIST_FIRST(&sc->sc_geom->consumer);
709 pp = cp->provider;
710
711 if (sc->sc_flags & G_ELI_FLAG_RO) {
712 G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
713 "provider: %s.", pp->name);
714 } else {
715 u_char *sector;
716 u_int i;
717 int err;
718
719 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
720 for (i = 0; i <= g_eli_overwrites; i++) {
721 if (i == g_eli_overwrites)
722 bzero(sector, pp->sectorsize);
723 else
724 arc4rand(sector, pp->sectorsize, 0);
725 err = g_write_data(cp, pp->mediasize - pp->sectorsize,
726 sector, pp->sectorsize);
727 if (err != 0) {
728 G_ELI_DEBUG(0, "Cannot erase metadata on %s "
729 "(error=%d).", pp->name, err);
730 if (error == 0)
731 error = err;
732 }
733 }
734 free(sector, M_ELI);
735 }
736 if (error == 0)
737 G_ELI_DEBUG(0, "%s has been killed.", pp->name);
738 g_eli_destroy(sc, 1);
739 return (error);
740}
741
742static void
743g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
744{
745 int *all, *nargs;
746 int error;
747
748 g_topology_assert();
749
750 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
751 if (nargs == NULL) {
752 gctl_error(req, "No '%s' argument.", "nargs");
753 return;
754 }
755 all = gctl_get_paraml(req, "all", sizeof(*all));
756 if (all == NULL) {
757 gctl_error(req, "No '%s' argument.", "all");
758 return;
759 }
760 if (!*all && *nargs == 0) {
761 gctl_error(req, "Too few arguments.");
762 return;
763 }
764
765 if (*all) {
766 struct g_geom *gp, *gp2;
767
768 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
769 error = g_eli_kill_one(gp->softc);
770 if (error != 0)
771 gctl_error(req, "Not fully done.");
772 }
773 } else {
774 struct g_eli_softc *sc;
775 const char *prov;
776 char param[16];
777 int i;
778
779 for (i = 0; i < *nargs; i++) {
780 snprintf(param, sizeof(param), "arg%d", i);
781 prov = gctl_get_asciiparam(req, param);
782 if (prov == NULL) {
783 G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
784 continue;
785 }
786
787 sc = g_eli_find_device(mp, prov);
788 if (sc == NULL) {
789 G_ELI_DEBUG(0, "No such provider: %s.", prov);
790 continue;
791 }
792 error = g_eli_kill_one(sc);
793 if (error != 0)
794 gctl_error(req, "Not fully done.");
795 }
796 }
797}
798
799void
800g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
801{
802 uint32_t *version;
803
804 g_topology_assert();
805
806 version = gctl_get_paraml(req, "version", sizeof(*version));
807 if (version == NULL) {
808 gctl_error(req, "No '%s' argument.", "version");
809 return;
810 }
811 if (*version != G_ELI_VERSION) {
812 gctl_error(req, "Userland and kernel parts are out of sync.");
813 return;
814 }
815
816 if (strcmp(verb, "attach") == 0)
817 g_eli_ctl_attach(req, mp);
818 else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
819 g_eli_ctl_detach(req, mp);
820 else if (strcmp(verb, "onetime") == 0)
821 g_eli_ctl_onetime(req, mp);
822 else if (strcmp(verb, "configure") == 0)
823 g_eli_ctl_configure(req, mp);
824 else if (strcmp(verb, "setkey") == 0)
825 g_eli_ctl_setkey(req, mp);
826 else if (strcmp(verb, "delkey") == 0)
827 g_eli_ctl_delkey(req, mp);
828 else if (strcmp(verb, "kill") == 0)
829 g_eli_ctl_kill(req, mp);
830 else
831 gctl_error(req, "Unknown verb.");
832}
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 162353 2006-09-16 10:43:17Z 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 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
147static struct g_eli_softc *
148g_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
173static void
174g_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
231static void
232g_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 md.md_sectorsize = *sectorsize;
359 }
360
361 g_eli_create(req, mp, pp, &md, mkey, -1);
362 bzero(mkey, sizeof(mkey));
363 bzero(&md, sizeof(md));
364}
365
366static void
367g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
368{
369 struct g_eli_softc *sc;
370 struct g_eli_metadata md;
371 struct g_provider *pp;
372 struct g_consumer *cp;
373 char param[16];
374 const char *prov;
375 u_char *sector;
376 int *nargs, *boot, *noboot;
377 int error;
378 u_int i;
379
380 g_topology_assert();
381
382 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
383 if (nargs == NULL) {
384 gctl_error(req, "No '%s' argument.", "nargs");
385 return;
386 }
387 if (*nargs <= 0) {
388 gctl_error(req, "Missing device(s).");
389 return;
390 }
391
392 boot = gctl_get_paraml(req, "boot", sizeof(*boot));
393 if (boot == NULL) {
394 gctl_error(req, "No '%s' argument.", "boot");
395 return;
396 }
397 noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
398 if (noboot == NULL) {
399 gctl_error(req, "No '%s' argument.", "noboot");
400 return;
401 }
402 if (*boot && *noboot) {
403 gctl_error(req, "Options -b and -B are mutually exclusive.");
404 return;
405 }
406 if (!*boot && !*noboot) {
407 gctl_error(req, "No option given.");
408 return;
409 }
410
411 for (i = 0; i < *nargs; i++) {
412 snprintf(param, sizeof(param), "arg%d", i);
413 prov = gctl_get_asciiparam(req, param);
414 if (prov == NULL) {
415 gctl_error(req, "No 'arg%d' argument.", i);
416 return;
417 }
418 sc = g_eli_find_device(mp, prov);
419 if (sc == NULL) {
420 /*
421 * We ignore not attached providers, userland part will
422 * take care of them.
423 */
424 G_ELI_DEBUG(1, "Skipping configuration of not attached "
425 "provider %s.", prov);
426 continue;
427 }
428 if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
429 G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
430 prov);
431 continue;
432 } else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
433 G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
434 prov);
435 continue;
436 }
437 if (sc->sc_flags & G_ELI_FLAG_RO) {
438 gctl_error(req, "Cannot change configuration of "
439 "read-only provider %s.", prov);
440 continue;
441 }
442 cp = LIST_FIRST(&sc->sc_geom->consumer);
443 pp = cp->provider;
444 error = g_eli_read_metadata(mp, pp, &md);
445 if (error != 0) {
446 gctl_error(req,
447 "Cannot read metadata from %s (error=%d).",
448 prov, error);
449 continue;
450 }
451
452 if (*boot) {
453 md.md_flags |= G_ELI_FLAG_BOOT;
454 sc->sc_flags |= G_ELI_FLAG_BOOT;
455 } else {
456 md.md_flags &= ~G_ELI_FLAG_BOOT;
457 sc->sc_flags &= ~G_ELI_FLAG_BOOT;
458 }
459
460 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
461 eli_metadata_encode(&md, sector);
462 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
463 pp->sectorsize);
464 if (error != 0) {
465 gctl_error(req,
466 "Cannot store metadata on %s (error=%d).",
467 prov, error);
468 }
469 bzero(&md, sizeof(md));
470 bzero(sector, sizeof(sector));
471 free(sector, M_ELI);
472 }
473}
474
475static void
476g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
477{
478 struct g_eli_softc *sc;
479 struct g_eli_metadata md;
480 struct g_provider *pp;
481 struct g_consumer *cp;
482 const char *name;
483 u_char *key, *mkeydst, *sector;
484 intmax_t *valp;
485 int keysize, nkey, error;
486
487 g_topology_assert();
488
489 name = gctl_get_asciiparam(req, "arg0");
490 if (name == NULL) {
491 gctl_error(req, "No 'arg%u' argument.", 0);
492 return;
493 }
494 sc = g_eli_find_device(mp, name);
495 if (sc == NULL) {
496 gctl_error(req, "Provider %s is invalid.", name);
497 return;
498 }
499 if (sc->sc_flags & G_ELI_FLAG_RO) {
500 gctl_error(req, "Cannot change keys for read-only provider.");
501 return;
502 }
503 cp = LIST_FIRST(&sc->sc_geom->consumer);
504 pp = cp->provider;
505
506 error = g_eli_read_metadata(mp, pp, &md);
507 if (error != 0) {
508 gctl_error(req, "Cannot read metadata from %s (error=%d).",
509 name, error);
510 return;
511 }
512
513 valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
514 if (valp == NULL) {
515 gctl_error(req, "No '%s' argument.", "keyno");
516 return;
517 }
518 if (*valp != -1)
519 nkey = *valp;
520 else
521 nkey = sc->sc_nkey;
522 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
523 gctl_error(req, "Invalid '%s' argument.", "keyno");
524 return;
525 }
526
527 valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
528 if (valp == NULL) {
529 gctl_error(req, "No '%s' argument.", "iterations");
530 return;
531 }
532 /* Check if iterations number should and can be changed. */
533 if (*valp != -1) {
534 if (bitcount32(md.md_keys) != 1) {
535 gctl_error(req, "To be able to use '-i' option, only "
536 "one key can be defined.");
537 return;
538 }
539 if (md.md_keys != (1 << nkey)) {
540 gctl_error(req, "Only already defined key can be "
541 "changed when '-i' option is used.");
542 return;
543 }
544 md.md_iterations = *valp;
545 }
546
547 key = gctl_get_param(req, "key", &keysize);
548 if (key == NULL || keysize != G_ELI_USERKEYLEN) {
549 bzero(&md, sizeof(md));
550 gctl_error(req, "No '%s' argument.", "key");
551 return;
552 }
553
554 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
555 md.md_keys |= (1 << nkey);
556
557 bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
558
559 /* Encrypt Master Key with the new key. */
560 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
561 bzero(key, sizeof(key));
562 if (error != 0) {
563 bzero(&md, sizeof(md));
564 gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
565 return;
566 }
567
568 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
569 /* Store metadata with fresh key. */
570 eli_metadata_encode(&md, sector);
571 bzero(&md, sizeof(md));
572 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
573 pp->sectorsize);
574 bzero(sector, sizeof(sector));
575 free(sector, M_ELI);
576 if (error != 0) {
577 gctl_error(req, "Cannot store metadata on %s (error=%d).",
578 pp->name, error);
579 return;
580 }
581 G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
582}
583
584static void
585g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
586{
587 struct g_eli_softc *sc;
588 struct g_eli_metadata md;
589 struct g_provider *pp;
590 struct g_consumer *cp;
591 const char *name;
592 u_char *mkeydst, *sector;
593 intmax_t *valp;
594 size_t keysize;
595 int error, nkey, *all, *force;
596 u_int i;
597
598 g_topology_assert();
599
600 nkey = 0; /* fixes causeless gcc warning */
601
602 name = gctl_get_asciiparam(req, "arg0");
603 if (name == NULL) {
604 gctl_error(req, "No 'arg%u' argument.", 0);
605 return;
606 }
607 sc = g_eli_find_device(mp, name);
608 if (sc == NULL) {
609 gctl_error(req, "Provider %s is invalid.", name);
610 return;
611 }
612 if (sc->sc_flags & G_ELI_FLAG_RO) {
613 gctl_error(req, "Cannot delete keys for read-only provider.");
614 return;
615 }
616 cp = LIST_FIRST(&sc->sc_geom->consumer);
617 pp = cp->provider;
618
619 error = g_eli_read_metadata(mp, pp, &md);
620 if (error != 0) {
621 gctl_error(req, "Cannot read metadata from %s (error=%d).",
622 name, error);
623 return;
624 }
625
626 all = gctl_get_paraml(req, "all", sizeof(*all));
627 if (all == NULL) {
628 gctl_error(req, "No '%s' argument.", "all");
629 return;
630 }
631
632 if (*all) {
633 mkeydst = md.md_mkeys;
634 keysize = sizeof(md.md_mkeys);
635 } else {
636 force = gctl_get_paraml(req, "force", sizeof(*force));
637 if (force == NULL) {
638 gctl_error(req, "No '%s' argument.", "force");
639 return;
640 }
641
642 valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
643 if (valp == NULL) {
644 gctl_error(req, "No '%s' argument.", "keyno");
645 return;
646 }
647 if (*valp != -1)
648 nkey = *valp;
649 else
650 nkey = sc->sc_nkey;
651 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
652 gctl_error(req, "Invalid '%s' argument.", "keyno");
653 return;
654 }
655 if (!(md.md_keys & (1 << nkey)) && !*force) {
656 gctl_error(req, "Master Key %u is not set.", nkey);
657 return;
658 }
659 md.md_keys &= ~(1 << nkey);
660 if (md.md_keys == 0 && !*force) {
661 gctl_error(req, "This is the last Master Key. Use '-f' "
662 "flag if you really want to remove it.");
663 return;
664 }
665 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
666 keysize = G_ELI_MKEYLEN;
667 }
668
669 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
670 for (i = 0; i <= g_eli_overwrites; i++) {
671 if (i == g_eli_overwrites)
672 bzero(mkeydst, keysize);
673 else
674 arc4rand(mkeydst, keysize, 0);
675 /* Store metadata with destroyed key. */
676 eli_metadata_encode(&md, sector);
677 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
678 pp->sectorsize);
679 if (error != 0) {
680 G_ELI_DEBUG(0, "Cannot store metadata on %s "
681 "(error=%d).", pp->name, error);
682 }
683 }
684 bzero(&md, sizeof(md));
685 bzero(sector, sizeof(sector));
686 free(sector, M_ELI);
687 if (*all)
688 G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
689 else
690 G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
691}
692
693static int
694g_eli_kill_one(struct g_eli_softc *sc)
695{
696 struct g_provider *pp;
697 struct g_consumer *cp;
698 int error = 0;
699
700 g_topology_assert();
701
702 if (sc == NULL)
703 return (ENOENT);
704
705 pp = LIST_FIRST(&sc->sc_geom->provider);
706 g_error_provider(pp, ENXIO);
707
708 cp = LIST_FIRST(&sc->sc_geom->consumer);
709 pp = cp->provider;
710
711 if (sc->sc_flags & G_ELI_FLAG_RO) {
712 G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
713 "provider: %s.", pp->name);
714 } else {
715 u_char *sector;
716 u_int i;
717 int err;
718
719 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
720 for (i = 0; i <= g_eli_overwrites; i++) {
721 if (i == g_eli_overwrites)
722 bzero(sector, pp->sectorsize);
723 else
724 arc4rand(sector, pp->sectorsize, 0);
725 err = g_write_data(cp, pp->mediasize - pp->sectorsize,
726 sector, pp->sectorsize);
727 if (err != 0) {
728 G_ELI_DEBUG(0, "Cannot erase metadata on %s "
729 "(error=%d).", pp->name, err);
730 if (error == 0)
731 error = err;
732 }
733 }
734 free(sector, M_ELI);
735 }
736 if (error == 0)
737 G_ELI_DEBUG(0, "%s has been killed.", pp->name);
738 g_eli_destroy(sc, 1);
739 return (error);
740}
741
742static void
743g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
744{
745 int *all, *nargs;
746 int error;
747
748 g_topology_assert();
749
750 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
751 if (nargs == NULL) {
752 gctl_error(req, "No '%s' argument.", "nargs");
753 return;
754 }
755 all = gctl_get_paraml(req, "all", sizeof(*all));
756 if (all == NULL) {
757 gctl_error(req, "No '%s' argument.", "all");
758 return;
759 }
760 if (!*all && *nargs == 0) {
761 gctl_error(req, "Too few arguments.");
762 return;
763 }
764
765 if (*all) {
766 struct g_geom *gp, *gp2;
767
768 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
769 error = g_eli_kill_one(gp->softc);
770 if (error != 0)
771 gctl_error(req, "Not fully done.");
772 }
773 } else {
774 struct g_eli_softc *sc;
775 const char *prov;
776 char param[16];
777 int i;
778
779 for (i = 0; i < *nargs; i++) {
780 snprintf(param, sizeof(param), "arg%d", i);
781 prov = gctl_get_asciiparam(req, param);
782 if (prov == NULL) {
783 G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
784 continue;
785 }
786
787 sc = g_eli_find_device(mp, prov);
788 if (sc == NULL) {
789 G_ELI_DEBUG(0, "No such provider: %s.", prov);
790 continue;
791 }
792 error = g_eli_kill_one(sc);
793 if (error != 0)
794 gctl_error(req, "Not fully done.");
795 }
796 }
797}
798
799void
800g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
801{
802 uint32_t *version;
803
804 g_topology_assert();
805
806 version = gctl_get_paraml(req, "version", sizeof(*version));
807 if (version == NULL) {
808 gctl_error(req, "No '%s' argument.", "version");
809 return;
810 }
811 if (*version != G_ELI_VERSION) {
812 gctl_error(req, "Userland and kernel parts are out of sync.");
813 return;
814 }
815
816 if (strcmp(verb, "attach") == 0)
817 g_eli_ctl_attach(req, mp);
818 else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
819 g_eli_ctl_detach(req, mp);
820 else if (strcmp(verb, "onetime") == 0)
821 g_eli_ctl_onetime(req, mp);
822 else if (strcmp(verb, "configure") == 0)
823 g_eli_ctl_configure(req, mp);
824 else if (strcmp(verb, "setkey") == 0)
825 g_eli_ctl_setkey(req, mp);
826 else if (strcmp(verb, "delkey") == 0)
827 g_eli_ctl_delkey(req, mp);
828 else if (strcmp(verb, "kill") == 0)
829 g_eli_ctl_kill(req, mp);
830 else
831 gctl_error(req, "Unknown verb.");
832}