Deleted Added
full compact
g_eli_ctl.c (154463) g_eli_ctl.c (155174)
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.
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 *
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>
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 154463 2006-01-17 07:32:43Z pjd $");
28__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 155174 2006-02-01 12:06:01Z 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;
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
134static struct g_eli_softc *
135g_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
160static void
161g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
162{
163 struct g_eli_softc *sc;
164 int *force, *last, *nargs, error;
165 const char *prov;
166 char param[16];
167 int i;
168
169 g_topology_assert();
170
171 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
172 if (nargs == NULL) {
173 gctl_error(req, "No '%s' argument.", "nargs");
174 return;
175 }
176 if (*nargs <= 0) {
177 gctl_error(req, "Missing device(s).");
178 return;
179 }
180 force = gctl_get_paraml(req, "force", sizeof(*force));
181 if (force == NULL) {
182 gctl_error(req, "No '%s' argument.", "force");
183 return;
184 }
185 last = gctl_get_paraml(req, "last", sizeof(*last));
186 if (last == NULL) {
187 gctl_error(req, "No '%s' argument.", "last");
188 return;
189 }
190
191 for (i = 0; i < *nargs; i++) {
192 snprintf(param, sizeof(param), "arg%d", i);
193 prov = gctl_get_asciiparam(req, param);
194 if (prov == NULL) {
195 gctl_error(req, "No 'arg%d' argument.", i);
196 return;
197 }
198 sc = g_eli_find_device(mp, prov);
199 if (sc == NULL) {
200 gctl_error(req, "No such device: %s.", prov);
201 return;
202 }
203 if (*last) {
204 sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
205 sc->sc_geom->access = g_eli_access;
206 } else {
207 error = g_eli_destroy(sc, *force);
208 if (error != 0) {
209 gctl_error(req,
210 "Cannot destroy device %s (error=%d).",
211 sc->sc_name, error);
212 return;
213 }
214 }
215 }
216}
217
218static void
219g_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
320static void
321g_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
427static void
428g_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
532static int
533g_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
574static void
575g_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%d", i);
613 prov = gctl_get_asciiparam(req, param);
614 if (prov == NULL) {
615 G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
616 continue;
617 }
618
619 sc = g_eli_find_device(mp, prov);
620 if (sc == NULL) {
621 G_ELI_DEBUG(0, "No such provider: %s.", prov);
622 continue;
623 }
624 error = g_eli_kill_one(sc);
625 if (error != 0)
626 gctl_error(req, "Not fully done.");
627 }
628 }
629}
630
631void
632g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
633{
634 uint32_t *version;
635
636 g_topology_assert();
637
638 version = gctl_get_paraml(req, "version", sizeof(*version));
639 if (version == NULL) {
640 gctl_error(req, "No '%s' argument.", "version");
641 return;
642 }
643 if (*version != G_ELI_VERSION) {
644 gctl_error(req, "Userland and kernel parts are out of sync.");
645 return;
646 }
647
648 if (strcmp(verb, "attach") == 0)
649 g_eli_ctl_attach(req, mp);
650 else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
651 g_eli_ctl_detach(req, mp);
652 else if (strcmp(verb, "onetime") == 0)
653 g_eli_ctl_onetime(req, mp);
654 else if (strcmp(verb, "setkey") == 0)
655 g_eli_ctl_setkey(req, mp);
656 else if (strcmp(verb, "delkey") == 0)
657 g_eli_ctl_delkey(req, mp);
658 else if (strcmp(verb, "kill") == 0)
659 g_eli_ctl_kill(req, mp);
660 else
661 gctl_error(req, "Unknown verb.");
662}
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;
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
134static struct g_eli_softc *
135g_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
160static void
161g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
162{
163 struct g_eli_softc *sc;
164 int *force, *last, *nargs, error;
165 const char *prov;
166 char param[16];
167 int i;
168
169 g_topology_assert();
170
171 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
172 if (nargs == NULL) {
173 gctl_error(req, "No '%s' argument.", "nargs");
174 return;
175 }
176 if (*nargs <= 0) {
177 gctl_error(req, "Missing device(s).");
178 return;
179 }
180 force = gctl_get_paraml(req, "force", sizeof(*force));
181 if (force == NULL) {
182 gctl_error(req, "No '%s' argument.", "force");
183 return;
184 }
185 last = gctl_get_paraml(req, "last", sizeof(*last));
186 if (last == NULL) {
187 gctl_error(req, "No '%s' argument.", "last");
188 return;
189 }
190
191 for (i = 0; i < *nargs; i++) {
192 snprintf(param, sizeof(param), "arg%d", i);
193 prov = gctl_get_asciiparam(req, param);
194 if (prov == NULL) {
195 gctl_error(req, "No 'arg%d' argument.", i);
196 return;
197 }
198 sc = g_eli_find_device(mp, prov);
199 if (sc == NULL) {
200 gctl_error(req, "No such device: %s.", prov);
201 return;
202 }
203 if (*last) {
204 sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
205 sc->sc_geom->access = g_eli_access;
206 } else {
207 error = g_eli_destroy(sc, *force);
208 if (error != 0) {
209 gctl_error(req,
210 "Cannot destroy device %s (error=%d).",
211 sc->sc_name, error);
212 return;
213 }
214 }
215 }
216}
217
218static void
219g_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
320static void
321g_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
427static void
428g_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
532static int
533g_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
574static void
575g_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%d", i);
613 prov = gctl_get_asciiparam(req, param);
614 if (prov == NULL) {
615 G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
616 continue;
617 }
618
619 sc = g_eli_find_device(mp, prov);
620 if (sc == NULL) {
621 G_ELI_DEBUG(0, "No such provider: %s.", prov);
622 continue;
623 }
624 error = g_eli_kill_one(sc);
625 if (error != 0)
626 gctl_error(req, "Not fully done.");
627 }
628 }
629}
630
631void
632g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
633{
634 uint32_t *version;
635
636 g_topology_assert();
637
638 version = gctl_get_paraml(req, "version", sizeof(*version));
639 if (version == NULL) {
640 gctl_error(req, "No '%s' argument.", "version");
641 return;
642 }
643 if (*version != G_ELI_VERSION) {
644 gctl_error(req, "Userland and kernel parts are out of sync.");
645 return;
646 }
647
648 if (strcmp(verb, "attach") == 0)
649 g_eli_ctl_attach(req, mp);
650 else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
651 g_eli_ctl_detach(req, mp);
652 else if (strcmp(verb, "onetime") == 0)
653 g_eli_ctl_onetime(req, mp);
654 else if (strcmp(verb, "setkey") == 0)
655 g_eli_ctl_setkey(req, mp);
656 else if (strcmp(verb, "delkey") == 0)
657 g_eli_ctl_delkey(req, mp);
658 else if (strcmp(verb, "kill") == 0)
659 g_eli_ctl_kill(req, mp);
660 else
661 gctl_error(req, "Unknown verb.");
662}