Deleted Added
sdiff udiff text old ( 161052 ) new ( 161127 )
full compact
1/*-
2 * Copyright (c) 2004 Pawel Jakub Dawidek
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/sbin/geom/class/eli/geom_eli.c 161052 2006-08-07 20:09:09Z pjd $");
29
30#include <stdio.h>
31#include <stdint.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <readpassphrase.h>
36#include <string.h>
37#include <strings.h>
38#include <libgeom.h>
39#include <paths.h>
40#include <errno.h>
41#include <assert.h>
42
43#include <sys/param.h>
44#include <sys/mman.h>
45#include <sys/resource.h>
46#include <opencrypto/cryptodev.h>
47#include <geom/eli/g_eli.h>
48#include <geom/eli/pkcs5v2.h>
49
50#include "core/geom.h"
51#include "misc/subr.h"
52
53
54uint32_t lib_version = G_LIB_VERSION;
55uint32_t version = G_ELI_VERSION;
56
57static char aalgo[] = "none";
58static char ealgo[] = "aes";
59static intmax_t keylen = 0;
60static intmax_t keyno = -1;
61static intmax_t iterations = -1;
62static intmax_t sectorsize = 0;
63static char keyfile[] = "", newkeyfile[] = "";
64
65static void eli_main(struct gctl_req *req, unsigned flags);
66static void eli_init(struct gctl_req *req);
67static void eli_attach(struct gctl_req *req);
68static void eli_setkey(struct gctl_req *req);
69static void eli_delkey(struct gctl_req *req);
70static void eli_kill(struct gctl_req *req);
71static void eli_backup(struct gctl_req *req);
72static void eli_restore(struct gctl_req *req);
73static void eli_clear(struct gctl_req *req);
74static void eli_dump(struct gctl_req *req);
75
76/*
77 * Available commands:
78 *
79 * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
80 * label - alias for 'init'
81 * attach [-dpv] [-k keyfile] prov
82 * detach [-fl] prov ...
83 * stop - alias for 'detach'
84 * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
85 * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
86 * delkey [-afv] [-n keyno] prov
87 * kill [-av] [prov ...]
88 * backup [-v] prov file
89 * restore [-v] file prov
90 * clear [-v] prov ...
91 * dump [-v] prov ...
92 */
93struct g_command class_commands[] = {
94 { "init", G_FLAG_VERBOSE, eli_main,
95 {
96 { 'a', "aalgo", aalgo, G_TYPE_STRING },
97 { 'b', "boot", NULL, G_TYPE_NONE },
98 { 'e', "ealgo", ealgo, G_TYPE_STRING },
99 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
100 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
101 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
102 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
103 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
104 G_OPT_SENTINEL
105 },
106 "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
107 },
108 { "label", G_FLAG_VERBOSE, eli_main,
109 {
110 { 'a', "aalgo", aalgo, G_TYPE_STRING },
111 { 'b', "boot", NULL, G_TYPE_NONE },
112 { 'e', "ealgo", ealgo, G_TYPE_STRING },
113 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
114 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
115 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
116 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
117 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
118 G_OPT_SENTINEL
119 },
120 "- an alias for 'init'"
121 },
122 { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
123 {
124 { 'd', "detach", NULL, G_TYPE_NONE },
125 { 'k', "keyfile", keyfile, G_TYPE_STRING },
126 { 'p', "nopassphrase", NULL, G_TYPE_NONE },
127 G_OPT_SENTINEL
128 },
129 "[-dpv] [-k keyfile] prov"
130 },
131 { "detach", 0, NULL,
132 {
133 { 'f', "force", NULL, G_TYPE_NONE },
134 { 'l', "last", NULL, G_TYPE_NONE },
135 G_OPT_SENTINEL
136 },
137 "[-fl] prov ..."
138 },
139 { "stop", 0, NULL,
140 {
141 { 'f', "force", NULL, G_TYPE_NONE },
142 { 'l', "last", NULL, G_TYPE_NONE },
143 G_OPT_SENTINEL
144 },
145 "- an alias for 'detach'"
146 },
147 { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
148 {
149 { 'a', "aalgo", aalgo, G_TYPE_STRING },
150 { 'd', "detach", NULL, G_TYPE_NONE },
151 { 'e', "ealgo", ealgo, G_TYPE_STRING },
152 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
153 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
154 G_OPT_SENTINEL
155 },
156 "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..."
157 },
158 { "setkey", G_FLAG_VERBOSE, eli_main,
159 {
160 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
161 { 'k', "keyfile", keyfile, G_TYPE_STRING },
162 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
163 { 'n', "keyno", &keyno, G_TYPE_NUMBER },
164 { 'p', "nopassphrase", NULL, G_TYPE_NONE },
165 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
166 G_OPT_SENTINEL
167 },
168 "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
169 },
170 { "delkey", G_FLAG_VERBOSE, eli_main,
171 {
172 { 'a', "all", NULL, G_TYPE_NONE },
173 { 'f', "force", NULL, G_TYPE_NONE },
174 { 'n', "keyno", &keyno, G_TYPE_NUMBER },
175 G_OPT_SENTINEL
176 },
177 "[-afv] [-n keyno] prov"
178 },
179 { "kill", G_FLAG_VERBOSE, eli_main,
180 {
181 { 'a', "all", NULL, G_TYPE_NONE },
182 G_OPT_SENTINEL
183 },
184 "[-av] [prov ...]"
185 },
186 { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
187 "[-v] prov file"
188 },
189 { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
190 "[-v] file prov"
191 },
192 { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
193 "[-v] prov ..."
194 },
195 { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
196 "[-v] prov ..."
197 },
198 G_CMD_SENTINEL
199};
200
201static int verbose = 0;
202
203static int
204eli_protect(struct gctl_req *req)
205{
206 struct rlimit rl;
207
208 /* Disable core dumps. */
209 rl.rlim_cur = 0;
210 rl.rlim_max = 0;
211 if (setrlimit(RLIMIT_CORE, &rl) == -1) {
212 gctl_error(req, "Cannot disable core dumps: %s.",
213 strerror(errno));
214 return (-1);
215 }
216 /* Disable swapping. */
217 if (mlockall(MCL_FUTURE) == -1) {
218 gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
219 return (-1);
220 }
221 return (0);
222}
223
224static void
225eli_main(struct gctl_req *req, unsigned flags)
226{
227 const char *name;
228
229 if (eli_protect(req) == -1)
230 return;
231
232 if ((flags & G_FLAG_VERBOSE) != 0)
233 verbose = 1;
234
235 name = gctl_get_ascii(req, "verb");
236 if (name == NULL) {
237 gctl_error(req, "No '%s' argument.", "verb");
238 return;
239 }
240 if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
241 eli_init(req);
242 else if (strcmp(name, "attach") == 0)
243 eli_attach(req);
244 else if (strcmp(name, "setkey") == 0)
245 eli_setkey(req);
246 else if (strcmp(name, "delkey") == 0)
247 eli_delkey(req);
248 else if (strcmp(name, "kill") == 0)
249 eli_kill(req);
250 else if (strcmp(name, "backup") == 0)
251 eli_backup(req);
252 else if (strcmp(name, "restore") == 0)
253 eli_restore(req);
254 else if (strcmp(name, "dump") == 0)
255 eli_dump(req);
256 else if (strcmp(name, "clear") == 0)
257 eli_clear(req);
258 else
259 gctl_error(req, "Unknown command: %s.", name);
260}
261
262static void
263arc4rand(unsigned char *buf, size_t size)
264{
265 uint32_t *buf4;
266 size_t size4;
267 unsigned i;
268
269 buf4 = (uint32_t *)buf;
270 size4 = size / 4;
271
272 for (i = 0; i < size4; i++)
273 buf4[i] = arc4random();
274 for (i *= 4; i < size; i++)
275 buf[i] = arc4random() % 0xff;
276}
277
278static int
279eli_is_attached(const char *prov)
280{
281 char name[MAXPATHLEN];
282 unsigned secsize;
283
284 /*
285 * Not the best way to do it, but the easiest.
286 * We try to open provider and check if it is a GEOM provider
287 * by asking about its sectorsize.
288 */
289 snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
290 secsize = g_get_sectorsize(name);
291 if (secsize > 0)
292 return (1);
293 return (0);
294}
295
296static unsigned char *
297eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
298 int new)
299{
300 struct hmac_ctx ctx;
301 const char *str;
302 int error, nopassphrase;
303
304 nopassphrase =
305 gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
306
307 g_eli_crypto_hmac_init(&ctx, NULL, 0);
308
309 str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
310 if (str[0] == '\0' && nopassphrase) {
311 gctl_error(req, "No key components given.");
312 return (NULL);
313 } else if (str[0] != '\0') {
314 char buf[MAXPHYS];
315 ssize_t done;
316 int fd;
317
318 if (strcmp(str, "-") == 0)
319 fd = STDIN_FILENO;
320 else {
321 fd = open(str, O_RDONLY);
322 if (fd == -1) {
323 gctl_error(req, "Cannot open keyfile %s: %s.",
324 str, strerror(errno));
325 return (NULL);
326 }
327 }
328 while ((done = read(fd, buf, sizeof(buf))) > 0)
329 g_eli_crypto_hmac_update(&ctx, buf, done);
330 error = errno;
331 if (strcmp(str, "-") != 0)
332 close(fd);
333 bzero(buf, sizeof(buf));
334 if (done == -1) {
335 gctl_error(req, "Cannot read keyfile %s: %s.", str,
336 strerror(error));
337 return (NULL);
338 }
339 }
340
341 if (!nopassphrase) {
342 char buf1[BUFSIZ], buf2[BUFSIZ], *p;
343
344 if (!new && md->md_iterations == -1) {
345 gctl_error(req, "Missing -p flag.");
346 return (NULL);
347 }
348 for (;;) {
349 p = readpassphrase(
350 new ? "Enter new passphrase:" : "Enter passphrase:",
351 buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
352 if (p == NULL) {
353 bzero(buf1, sizeof(buf1));
354 gctl_error(req, "Cannot read passphrase: %s.",
355 strerror(errno));
356 return (NULL);
357 }
358
359 if (new) {
360 p = readpassphrase("Reenter new passphrase: ",
361 buf2, sizeof(buf2),
362 RPP_ECHO_OFF | RPP_REQUIRE_TTY);
363 if (p == NULL) {
364 bzero(buf1, sizeof(buf1));
365 gctl_error(req,
366 "Cannot read passphrase: %s.",
367 strerror(errno));
368 return (NULL);
369 }
370
371 if (strcmp(buf1, buf2) != 0) {
372 bzero(buf2, sizeof(buf2));
373 fprintf(stderr, "They didn't match.\n");
374 continue;
375 }
376 bzero(buf2, sizeof(buf2));
377 }
378 break;
379 }
380 /*
381 * Field md_iterations equal to -1 means "choose some sane
382 * value for me".
383 */
384 if (md->md_iterations == -1) {
385 assert(new);
386 if (verbose)
387 printf("Calculating number of iterations...\n");
388 md->md_iterations = pkcs5v2_calculate(2000000);
389 assert(md->md_iterations > 0);
390 if (verbose) {
391 printf("Done, using %d iterations.\n",
392 md->md_iterations);
393 }
394 }
395 /*
396 * If md_iterations is equal to 0, user don't want PKCS#5v2.
397 */
398 if (md->md_iterations == 0) {
399 g_eli_crypto_hmac_update(&ctx, md->md_salt,
400 sizeof(md->md_salt));
401 g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
402 } else /* if (md->md_iterations > 0) */ {
403 unsigned char dkey[G_ELI_USERKEYLEN];
404
405 pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
406 sizeof(md->md_salt), buf1, md->md_iterations);
407 g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
408 bzero(dkey, sizeof(dkey));
409 }
410 bzero(buf1, sizeof(buf1));
411 }
412 g_eli_crypto_hmac_final(&ctx, key, 0);
413 return (key);
414}
415
416static int
417eli_metadata_read(struct gctl_req *req, const char *prov,
418 struct g_eli_metadata *md)
419{
420 unsigned char sector[sizeof(struct g_eli_metadata)];
421 int error;
422
423 if (g_get_sectorsize(prov) == 0) {
424 int fd;
425
426 /* This is a file probably. */
427 fd = open(prov, O_RDONLY);
428 if (fd == -1) {
429 gctl_error(req, "Cannot open %s: %s.", prov,
430 strerror(errno));
431 return (-1);
432 }
433 if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
434 gctl_error(req, "Cannot read metadata from %s: %s.",
435 prov, strerror(errno));
436 close(fd);
437 return (-1);
438 }
439 close(fd);
440 } else {
441 /* This is a GEOM provider. */
442 error = g_metadata_read(prov, sector, sizeof(sector),
443 G_ELI_MAGIC);
444 if (error != 0) {
445 gctl_error(req, "Cannot read metadata from %s: %s.",
446 prov, strerror(error));
447 return (-1);
448 }
449 }
450 if (eli_metadata_decode(sector, md) != 0) {
451 gctl_error(req, "MD5 hash mismatch for %s.", prov);
452 return (-1);
453 }
454 return (0);
455}
456
457static int
458eli_metadata_store(struct gctl_req *req, const char *prov,
459 struct g_eli_metadata *md)
460{
461 unsigned char sector[sizeof(struct g_eli_metadata)];
462 int error;
463
464 eli_metadata_encode(md, sector);
465 if (g_get_sectorsize(prov) == 0) {
466 int fd;
467
468 /* This is a file probably. */
469 fd = open(prov, O_WRONLY | O_TRUNC);
470 if (fd == -1) {
471 gctl_error(req, "Cannot open %s: %s.", prov,
472 strerror(errno));
473 bzero(sector, sizeof(sector));
474 return (-1);
475 }
476 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
477 gctl_error(req, "Cannot write metadata to %s: %s.",
478 prov, strerror(errno));
479 bzero(sector, sizeof(sector));
480 close(fd);
481 return (-1);
482 }
483 close(fd);
484 } else {
485 /* This is a GEOM provider. */
486 error = g_metadata_store(prov, sector, sizeof(sector));
487 if (error != 0) {
488 gctl_error(req, "Cannot write metadata to %s: %s.",
489 prov, strerror(errno));
490 bzero(sector, sizeof(sector));
491 return (-1);
492 }
493 }
494 bzero(sector, sizeof(sector));
495 return (0);
496}
497
498static void
499eli_init(struct gctl_req *req)
500{
501 struct g_eli_metadata md;
502 unsigned char sector[sizeof(struct g_eli_metadata)];
503 unsigned char key[G_ELI_USERKEYLEN];
504 const char *str, *prov;
505 unsigned secsize;
506 off_t mediasize;
507 intmax_t val;
508 int error, nargs;
509
510 nargs = gctl_get_int(req, "nargs");
511 if (nargs != 1) {
512 gctl_error(req, "Invalid number of arguments.");
513 return;
514 }
515 prov = gctl_get_ascii(req, "arg0");
516 mediasize = g_get_mediasize(prov);
517 secsize = g_get_sectorsize(prov);
518 if (mediasize == 0 || secsize == 0) {
519 gctl_error(req, "Cannot get informations about %s: %s.", prov,
520 strerror(errno));
521 return;
522 }
523
524 bzero(&md, sizeof(md));
525 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
526 md.md_version = G_ELI_VERSION;
527 md.md_flags = 0;
528 if (gctl_get_int(req, "boot"))
529 md.md_flags |= G_ELI_FLAG_BOOT;
530 md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
531 str = gctl_get_ascii(req, "aalgo");
532 if (strcmp(str, "none") != 0) {
533 md.md_aalgo = g_eli_str2aalgo(str);
534 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
535 md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
536 md.md_flags |= G_ELI_FLAG_AUTH;
537 } else {
538 /*
539 * For backward compatibility, check if the -a option
540 * was used to provide encryption algorithm.
541 */
542 md.md_ealgo = g_eli_str2ealgo(str);
543 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
544 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
545 gctl_error(req,
546 "Invalid authentication algorithm.");
547 return;
548 } else {
549 fprintf(stderr, "warning: The -e option, not "
550 "the -a option is now used to specify "
551 "encryption algorithm to use.\n");
552 }
553 }
554 }
555 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
556 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
557 str = gctl_get_ascii(req, "ealgo");
558 md.md_ealgo = g_eli_str2ealgo(str);
559 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
560 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
561 gctl_error(req, "Invalid encryption algorithm.");
562 return;
563 }
564 }
565 val = gctl_get_intmax(req, "keylen");
566 md.md_keylen = val;
567 md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
568 if (md.md_keylen == 0) {
569 gctl_error(req, "Invalid key length.");
570 return;
571 }
572 md.md_provsize = mediasize;
573
574 val = gctl_get_intmax(req, "iterations");
575 if (val != -1) {
576 int nonewpassphrase;
577
578 /*
579 * Don't allow to set iterations when there will be no
580 * passphrase.
581 */
582 nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
583 if (nonewpassphrase) {
584 gctl_error(req,
585 "Options -i and -P are mutually exclusive.");
586 return;
587 }
588 }
589 md.md_iterations = val;
590
591 val = gctl_get_intmax(req, "sectorsize");
592 if (val == 0)
593 md.md_sectorsize = secsize;
594 else {
595 if (val < 0 || (val % secsize) != 0) {
596 gctl_error(req, "Invalid sector size.");
597 return;
598 }
599 md.md_sectorsize = val;
600 }
601
602 md.md_keys = 0x01;
603 arc4rand(md.md_salt, sizeof(md.md_salt));
604 arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
605
606 /* Generate user key. */
607 if (eli_genkey(req, &md, key, 1) == NULL) {
608 bzero(key, sizeof(key));
609 bzero(&md, sizeof(md));
610 return;
611 }
612
613 /* Encrypt the first and the only Master Key. */
614 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
615 bzero(key, sizeof(key));
616 if (error != 0) {
617 bzero(&md, sizeof(md));
618 gctl_error(req, "Cannot encrypt Master Key: %s.",
619 strerror(error));
620 return;
621 }
622
623 eli_metadata_encode(&md, sector);
624 bzero(&md, sizeof(md));
625 error = g_metadata_store(prov, sector, sizeof(sector));
626 bzero(sector, sizeof(sector));
627 if (error != 0) {
628 gctl_error(req, "Cannot store metadata on %s: %s.", prov,
629 strerror(error));
630 return;
631 }
632 if (verbose)
633 printf("Metadata value stored on %s.\n", prov);
634}
635
636static void
637eli_attach(struct gctl_req *req)
638{
639 struct g_eli_metadata md;
640 unsigned char key[G_ELI_USERKEYLEN];
641 const char *prov;
642 int nargs;
643
644 nargs = gctl_get_int(req, "nargs");
645 if (nargs != 1) {
646 gctl_error(req, "Invalid number of arguments.");
647 return;
648 }
649 prov = gctl_get_ascii(req, "arg0");
650
651 if (eli_metadata_read(req, prov, &md) == -1)
652 return;
653
654 if (eli_genkey(req, &md, key, 0) == NULL) {
655 bzero(key, sizeof(key));
656 return;
657 }
658
659 gctl_ro_param(req, "key", sizeof(key), key);
660 if (gctl_issue(req) == NULL) {
661 if (verbose)
662 printf("Attched to %s.\n", prov);
663 }
664 bzero(key, sizeof(key));
665}
666
667static void
668eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
669{
670 unsigned char key[G_ELI_USERKEYLEN];
671 intmax_t val;
672
673 val = gctl_get_intmax(req, "iterations");
674 /* Check if iterations number should be changed. */
675 if (val != -1)
676 md->md_iterations = val;
677
678 /* Generate key for Master Key encryption. */
679 if (eli_genkey(req, md, key, 1) == NULL) {
680 bzero(key, sizeof(key));
681 return;
682 }
683
684 gctl_ro_param(req, "key", sizeof(key), key);
685 gctl_issue(req);
686 bzero(key, sizeof(key));
687}
688
689static void
690eli_setkey_detached(struct gctl_req *req, const char *prov,
691 struct g_eli_metadata *md)
692{
693 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
694 unsigned char *mkeydst;
695 intmax_t val;
696 unsigned nkey;
697 int error;
698
699 if (md->md_keys == 0) {
700 gctl_error(req, "No valid keys on %s.", prov);
701 return;
702 }
703
704 /* Generate key for Master Key decryption. */
705 if (eli_genkey(req, md, key, 0) == NULL) {
706 bzero(key, sizeof(key));
707 return;
708 }
709
710 /* Decrypt Master Key. */
711 error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
712 bzero(key, sizeof(key));
713 if (error != 0) {
714 bzero(md, sizeof(*md));
715 if (error == -1)
716 gctl_error(req, "Wrong key for %s.", prov);
717 else /* if (error > 0) */ {
718 gctl_error(req, "Cannot decrypt Master Key: %s.",
719 strerror(error));
720 }
721 return;
722 }
723 if (verbose)
724 printf("Decrypted Master Key %u.\n", nkey);
725
726 val = gctl_get_intmax(req, "keyno");
727 if (val != -1)
728 nkey = val;
729#if 0
730 else
731 ; /* Use the key number which was found during decryption. */
732#endif
733 if (nkey >= G_ELI_MAXMKEYS) {
734 gctl_error(req, "Invalid '%s' argument.", "keyno");
735 return;
736 }
737
738 val = gctl_get_intmax(req, "iterations");
739 /* Check if iterations number should and can be changed. */
740 if (val != -1) {
741 if (bitcount32(md->md_keys) != 1) {
742 gctl_error(req, "To be able to use '-i' option, only "
743 "one key can be defined.");
744 return;
745 }
746 if (md->md_keys != (1 << nkey)) {
747 gctl_error(req, "Only already defined key can be "
748 "changed when '-i' option is used.");
749 return;
750 }
751 md->md_iterations = val;
752 }
753
754 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
755 md->md_keys |= (1 << nkey);
756
757 bcopy(mkey, mkeydst, sizeof(mkey));
758 bzero(mkey, sizeof(mkey));
759
760 /* Generate key for Master Key encryption. */
761 if (eli_genkey(req, md, key, 1) == NULL) {
762 bzero(key, sizeof(key));
763 bzero(md, sizeof(*md));
764 return;
765 }
766
767 /* Encrypt the Master-Key with the new key. */
768 error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
769 bzero(key, sizeof(key));
770 if (error != 0) {
771 bzero(md, sizeof(*md));
772 gctl_error(req, "Cannot encrypt Master Key: %s.",
773 strerror(error));
774 return;
775 }
776
777 /* Store metadata with fresh key. */
778 eli_metadata_store(req, prov, md);
779 bzero(md, sizeof(*md));
780}
781
782static void
783eli_setkey(struct gctl_req *req)
784{
785 struct g_eli_metadata md;
786 const char *prov;
787 int nargs;
788
789 nargs = gctl_get_int(req, "nargs");
790 if (nargs != 1) {
791 gctl_error(req, "Invalid number of arguments.");
792 return;
793 }
794 prov = gctl_get_ascii(req, "arg0");
795
796 if (eli_metadata_read(req, prov, &md) == -1)
797 return;
798
799 if (eli_is_attached(prov))
800 eli_setkey_attached(req, &md);
801 else
802 eli_setkey_detached(req, prov, &md);
803}
804
805static void
806eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
807{
808
809 gctl_issue(req);
810}
811
812static void
813eli_delkey_detached(struct gctl_req *req, const char *prov)
814{
815 struct g_eli_metadata md;
816 unsigned char *mkeydst;
817 intmax_t val;
818 unsigned nkey;
819 int all, force;
820
821 if (eli_metadata_read(req, prov, &md) == -1)
822 return;
823
824 all = gctl_get_int(req, "all");
825 if (all)
826 arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
827 else {
828 force = gctl_get_int(req, "force");
829 val = gctl_get_intmax(req, "keyno");
830 if (val == -1) {
831 gctl_error(req, "Key number has to be specified.");
832 return;
833 }
834 nkey = val;
835 if (nkey >= G_ELI_MAXMKEYS) {
836 gctl_error(req, "Invalid '%s' argument.", "keyno");
837 return;
838 }
839 if (!(md.md_keys & (1 << nkey)) && !force) {
840 gctl_error(req, "Master Key %u is not set.", nkey);
841 return;
842 }
843 md.md_keys &= ~(1 << nkey);
844 if (md.md_keys == 0 && !force) {
845 gctl_error(req, "This is the last Master Key. Use '-f' "
846 "option if you really want to remove it.");
847 return;
848 }
849 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
850 arc4rand(mkeydst, G_ELI_MKEYLEN);
851 }
852
853 eli_metadata_store(req, prov, &md);
854 bzero(&md, sizeof(md));
855}
856
857static void
858eli_delkey(struct gctl_req *req)
859{
860 const char *prov;
861 int nargs;
862
863 nargs = gctl_get_int(req, "nargs");
864 if (nargs != 1) {
865 gctl_error(req, "Invalid number of arguments.");
866 return;
867 }
868 prov = gctl_get_ascii(req, "arg0");
869
870 if (eli_is_attached(prov))
871 eli_delkey_attached(req, prov);
872 else
873 eli_delkey_detached(req, prov);
874}
875
876static void
877eli_kill_detached(struct gctl_req *req, const char *prov)
878{
879 struct g_eli_metadata md;
880 int error;
881
882 /*
883 * NOTE: Maybe we should verify if this is geli provider first,
884 * but 'kill' command is quite critical so better don't waste
885 * the time.
886 */
887#if 0
888 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
889 G_ELI_MAGIC);
890 if (error != 0) {
891 gctl_error(req, "Cannot read metadata from %s: %s.", prov,
892 strerror(error));
893 return;
894 }
895#endif
896
897 arc4rand((unsigned char *)&md, sizeof(md));
898 error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
899 if (error != 0) {
900 gctl_error(req, "Cannot write metadata to %s: %s.", prov,
901 strerror(error));
902 }
903}
904
905static void
906eli_kill(struct gctl_req *req)
907{
908 const char *prov;
909 int i, nargs, all;
910
911 nargs = gctl_get_int(req, "nargs");
912 all = gctl_get_int(req, "all");
913 if (!all && nargs == 0) {
914 gctl_error(req, "Too few arguments.");
915 return;
916 }
917 /*
918 * How '-a' option combine with a list of providers:
919 * Delete Master Keys from all attached providers:
920 * geli kill -a
921 * Delete Master Keys from all attached provider and from
922 * detached da0 and da1:
923 * geli kill -a da0 da1
924 * Delete Master Keys from (attached or detached) da0 and da1:
925 * geli kill da0 da1
926 */
927
928 /*
929 * First attached providers.
930 */
931 gctl_issue(req);
932 /*
933 * Now the rest.
934 */
935 for (i = 0; i < nargs; i++) {
936 prov = gctl_get_ascii(req, "arg%d", i);
937 if (!eli_is_attached(prov))
938 eli_kill_detached(req, prov);
939 }
940}
941
942static void
943eli_backup(struct gctl_req *req)
944{
945 struct g_eli_metadata md;
946 const char *file, *prov;
947 unsigned secsize;
948 unsigned char *sector;
949 off_t mediasize;
950 int nargs, filefd, provfd;
951
952 nargs = gctl_get_int(req, "nargs");
953 if (nargs != 2) {
954 gctl_error(req, "Invalid number of arguments.");
955 return;
956 }
957 prov = gctl_get_ascii(req, "arg0");
958 file = gctl_get_ascii(req, "arg1");
959
960 provfd = filefd = -1;
961 sector = NULL;
962 secsize = 0;
963
964 provfd = open(prov, O_RDONLY);
965 if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
966 char devprov[MAXPATHLEN];
967
968 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
969 provfd = open(devprov, O_RDONLY);
970 }
971 if (provfd == -1) {
972 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
973 return;
974 }
975 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
976 if (filefd == -1) {
977 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
978 goto out;
979 }
980
981 mediasize = g_get_mediasize(prov);
982 secsize = g_get_sectorsize(prov);
983 if (mediasize == 0 || secsize == 0) {
984 gctl_error(req, "Cannot get informations about %s: %s.", prov,
985 strerror(errno));
986 return;
987 }
988
989 sector = malloc(secsize);
990 if (sector == NULL) {
991 gctl_error(req, "Cannot allocate memory.");
992 return;
993 }
994
995 /* Read metadata from the provider. */
996 if (pread(provfd, sector, secsize, mediasize - secsize) !=
997 (ssize_t)secsize) {
998 gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
999 goto out;
1000 }
1001 /* Check if this is geli provider. */
1002 if (eli_metadata_decode(sector, &md) != 0) {
1003 gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1004 goto out;
1005 }
1006 /* Write metadata to the destination file. */
1007 if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1008 gctl_error(req, "Cannot write to %s: %s.", file,
1009 strerror(errno));
1010 goto out;
1011 }
1012out:
1013 if (provfd > 0)
1014 close(provfd);
1015 if (filefd > 0)
1016 close(filefd);
1017 if (sector != NULL) {
1018 bzero(sector, secsize);
1019 free(sector);
1020 }
1021}
1022
1023static void
1024eli_restore(struct gctl_req *req)
1025{
1026 struct g_eli_metadata md;
1027 const char *file, *prov;
1028 unsigned char *sector;
1029 unsigned secsize;
1030 off_t mediasize;
1031 int nargs, filefd, provfd;
1032
1033 nargs = gctl_get_int(req, "nargs");
1034 if (nargs != 2) {
1035 gctl_error(req, "Invalid number of arguments.");
1036 return;
1037 }
1038 file = gctl_get_ascii(req, "arg0");
1039 prov = gctl_get_ascii(req, "arg1");
1040
1041 provfd = filefd = -1;
1042 sector = NULL;
1043 secsize = 0;
1044
1045 filefd = open(file, O_RDONLY);
1046 if (filefd == -1) {
1047 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1048 goto out;
1049 }
1050 provfd = open(prov, O_WRONLY);
1051 if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1052 char devprov[MAXPATHLEN];
1053
1054 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1055 provfd = open(devprov, O_WRONLY);
1056 }
1057 if (provfd == -1) {
1058 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1059 return;
1060 }
1061
1062 mediasize = g_get_mediasize(prov);
1063 secsize = g_get_sectorsize(prov);
1064 if (mediasize == 0 || secsize == 0) {
1065 gctl_error(req, "Cannot get informations about %s: %s.", prov,
1066 strerror(errno));
1067 return;
1068 }
1069
1070 sector = malloc(secsize);
1071 if (sector == NULL) {
1072 gctl_error(req, "Cannot allocate memory.");
1073 return;
1074 }
1075
1076 /* Read metadata from the backup file. */
1077 if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1078 gctl_error(req, "Cannot read from %s: %s.", file,
1079 strerror(errno));
1080 goto out;
1081 }
1082 /* Check if this file contains geli metadata. */
1083 if (eli_metadata_decode(sector, &md) != 0) {
1084 gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1085 goto out;
1086 }
1087 /* Read metadata from the provider. */
1088 if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1089 (ssize_t)secsize) {
1090 gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1091 goto out;
1092 }
1093out:
1094 if (provfd > 0)
1095 close(provfd);
1096 if (filefd > 0)
1097 close(filefd);
1098 if (sector != NULL) {
1099 bzero(sector, secsize);
1100 free(sector);
1101 }
1102}
1103
1104static void
1105eli_clear(struct gctl_req *req)
1106{
1107 const char *name;
1108 int error, i, nargs;
1109
1110 nargs = gctl_get_int(req, "nargs");
1111 if (nargs < 1) {
1112 gctl_error(req, "Too few arguments.");
1113 return;
1114 }
1115
1116 for (i = 0; i < nargs; i++) {
1117 name = gctl_get_ascii(req, "arg%d", i);
1118 error = g_metadata_clear(name, G_ELI_MAGIC);
1119 if (error != 0) {
1120 fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1121 name, strerror(error));
1122 gctl_error(req, "Not fully done.");
1123 continue;
1124 }
1125 if (verbose)
1126 printf("Metadata cleared on %s.\n", name);
1127 }
1128}
1129
1130static void
1131eli_dump(struct gctl_req *req)
1132{
1133 struct g_eli_metadata md, tmpmd;
1134 const char *name;
1135 int error, i, nargs;
1136
1137 nargs = gctl_get_int(req, "nargs");
1138 if (nargs < 1) {
1139 gctl_error(req, "Too few arguments.");
1140 return;
1141 }
1142
1143 for (i = 0; i < nargs; i++) {
1144 name = gctl_get_ascii(req, "arg%d", i);
1145 error = g_metadata_read(name, (unsigned char *)&tmpmd,
1146 sizeof(tmpmd), G_ELI_MAGIC);
1147 if (error != 0) {
1148 fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1149 name, strerror(error));
1150 gctl_error(req, "Not fully done.");
1151 continue;
1152 }
1153 if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1154 fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1155 name);
1156 gctl_error(req, "Not fully done.");
1157 continue;
1158 }
1159 printf("Metadata on %s:\n", name);
1160 eli_metadata_dump(&md);
1161 printf("\n");
1162 }
1163}