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