]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/geom/class/eli/geom_eli.c
MFV r308954:
[FreeBSD/FreeBSD.git] / sbin / geom / class / eli / geom_eli.c
1 /*-
2  * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/mman.h>
32 #include <sys/sysctl.h>
33 #include <sys/resource.h>
34 #include <opencrypto/cryptodev.h>
35
36 #include <assert.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <libgeom.h>
41 #include <paths.h>
42 #include <readpassphrase.h>
43 #include <stdbool.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <strings.h>
49 #include <unistd.h>
50
51 #include <geom/eli/g_eli.h>
52 #include <geom/eli/pkcs5v2.h>
53
54 #include "core/geom.h"
55 #include "misc/subr.h"
56
57
58 uint32_t lib_version = G_LIB_VERSION;
59 uint32_t version = G_ELI_VERSION;
60
61 #define GELI_BACKUP_DIR "/var/backups/"
62 #define GELI_ENC_ALGO   "aes"
63
64 static void eli_main(struct gctl_req *req, unsigned flags);
65 static void eli_init(struct gctl_req *req);
66 static void eli_attach(struct gctl_req *req);
67 static void eli_configure(struct gctl_req *req);
68 static void eli_setkey(struct gctl_req *req);
69 static void eli_delkey(struct gctl_req *req);
70 static void eli_resume(struct gctl_req *req);
71 static void eli_kill(struct gctl_req *req);
72 static void eli_backup(struct gctl_req *req);
73 static void eli_restore(struct gctl_req *req);
74 static void eli_resize(struct gctl_req *req);
75 static void eli_version(struct gctl_req *req);
76 static void eli_clear(struct gctl_req *req);
77 static void eli_dump(struct gctl_req *req);
78
79 static int eli_backup_create(struct gctl_req *req, const char *prov,
80     const char *file);
81
82 /*
83  * Available commands:
84  *
85  * init [-bgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov
86  * label - alias for 'init'
87  * attach [-dprv] [-j passfile] [-k keyfile] prov
88  * detach [-fl] prov ...
89  * stop - alias for 'detach'
90  * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov
91  * configure [-bBgGtT] prov ...
92  * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
93  * delkey [-afv] [-n keyno] prov
94  * suspend [-v] -a | prov ...
95  * resume [-pv] [-j passfile] [-k keyfile] prov
96  * kill [-av] [prov ...]
97  * backup [-v] prov file
98  * restore [-fv] file prov
99  * resize [-v] -s oldsize prov
100  * version [prov ...]
101  * clear [-v] prov ...
102  * dump [-v] prov ...
103  */
104 struct g_command class_commands[] = {
105         { "init", G_FLAG_VERBOSE, eli_main,
106             {
107                 { 'a', "aalgo", "", G_TYPE_STRING },
108                 { 'b', "boot", NULL, G_TYPE_BOOL },
109                 { 'B', "backupfile", "", G_TYPE_STRING },
110                 { 'e', "ealgo", "", G_TYPE_STRING },
111                 { 'g', "geliboot", NULL, G_TYPE_BOOL },
112                 { 'i', "iterations", "-1", G_TYPE_NUMBER },
113                 { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
114                 { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
115                 { 'l', "keylen", "0", G_TYPE_NUMBER },
116                 { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
117                 { 's', "sectorsize", "0", G_TYPE_NUMBER },
118                 { 'T', "notrim", NULL, G_TYPE_BOOL },
119                 { 'V', "mdversion", "-1", G_TYPE_NUMBER },
120                 G_OPT_SENTINEL
121             },
122             "[-bgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov"
123         },
124         { "label", G_FLAG_VERBOSE, eli_main,
125             {
126                 { 'a', "aalgo", "", G_TYPE_STRING },
127                 { 'b', "boot", NULL, G_TYPE_BOOL },
128                 { 'B', "backupfile", "", G_TYPE_STRING },
129                 { 'e', "ealgo", "", G_TYPE_STRING },
130                 { 'g', "geliboot", NULL, G_TYPE_BOOL },
131                 { 'i', "iterations", "-1", G_TYPE_NUMBER },
132                 { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
133                 { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
134                 { 'l', "keylen", "0", G_TYPE_NUMBER },
135                 { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
136                 { 's', "sectorsize", "0", G_TYPE_NUMBER },
137                 { 'V', "mdversion", "-1", G_TYPE_NUMBER },
138                 G_OPT_SENTINEL
139             },
140             "- an alias for 'init'"
141         },
142         { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
143             {
144                 { 'd', "detach", NULL, G_TYPE_BOOL },
145                 { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
146                 { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
147                 { 'p', "nopassphrase", NULL, G_TYPE_BOOL },
148                 { 'r', "readonly", NULL, G_TYPE_BOOL },
149                 G_OPT_SENTINEL
150             },
151             "[-dprv] [-j passfile] [-k keyfile] prov"
152         },
153         { "detach", 0, NULL,
154             {
155                 { 'f', "force", NULL, G_TYPE_BOOL },
156                 { 'l', "last", NULL, G_TYPE_BOOL },
157                 G_OPT_SENTINEL
158             },
159             "[-fl] prov ..."
160         },
161         { "stop", 0, NULL,
162             {
163                 { 'f', "force", NULL, G_TYPE_BOOL },
164                 { 'l', "last", NULL, G_TYPE_BOOL },
165                 G_OPT_SENTINEL
166             },
167             "- an alias for 'detach'"
168         },
169         { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
170             {
171                 { 'a', "aalgo", "", G_TYPE_STRING },
172                 { 'd', "detach", NULL, G_TYPE_BOOL },
173                 { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
174                 { 'l', "keylen", "0", G_TYPE_NUMBER },
175                 { 's', "sectorsize", "0", G_TYPE_NUMBER },
176                 { 'T', "notrim", NULL, G_TYPE_BOOL },
177                 G_OPT_SENTINEL
178             },
179             "[-dT] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov"
180         },
181         { "configure", G_FLAG_VERBOSE, eli_main,
182             {
183                 { 'b', "boot", NULL, G_TYPE_BOOL },
184                 { 'B', "noboot", NULL, G_TYPE_BOOL },
185                 { 'g', "geliboot", NULL, G_TYPE_BOOL },
186                 { 'G', "nogeliboot", NULL, G_TYPE_BOOL },
187                 { 't', "trim", NULL, G_TYPE_BOOL },
188                 { 'T', "notrim", NULL, G_TYPE_BOOL },
189                 G_OPT_SENTINEL
190             },
191             "[-bBgGtT] prov ..."
192         },
193         { "setkey", G_FLAG_VERBOSE, eli_main,
194             {
195                 { 'i', "iterations", "-1", G_TYPE_NUMBER },
196                 { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
197                 { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
198                 { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
199                 { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
200                 { 'n', "keyno", "-1", G_TYPE_NUMBER },
201                 { 'p', "nopassphrase", NULL, G_TYPE_BOOL },
202                 { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
203                 G_OPT_SENTINEL
204             },
205             "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
206         },
207         { "delkey", G_FLAG_VERBOSE, eli_main,
208             {
209                 { 'a', "all", NULL, G_TYPE_BOOL },
210                 { 'f', "force", NULL, G_TYPE_BOOL },
211                 { 'n', "keyno", "-1", G_TYPE_NUMBER },
212                 G_OPT_SENTINEL
213             },
214             "[-afv] [-n keyno] prov"
215         },
216         { "suspend", G_FLAG_VERBOSE, NULL,
217             {
218                 { 'a', "all", NULL, G_TYPE_BOOL },
219                 G_OPT_SENTINEL
220             },
221             "[-v] -a | prov ..."
222         },
223         { "resume", G_FLAG_VERBOSE, eli_main,
224             {
225                 { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
226                 { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
227                 { 'p', "nopassphrase", NULL, G_TYPE_BOOL },
228                 G_OPT_SENTINEL
229             },
230             "[-pv] [-j passfile] [-k keyfile] prov"
231         },
232         { "kill", G_FLAG_VERBOSE, eli_main,
233             {
234                 { 'a', "all", NULL, G_TYPE_BOOL },
235                 G_OPT_SENTINEL
236             },
237             "[-av] [prov ...]"
238         },
239         { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
240             "[-v] prov file"
241         },
242         { "restore", G_FLAG_VERBOSE, eli_main,
243             {
244                 { 'f', "force", NULL, G_TYPE_BOOL },
245                 G_OPT_SENTINEL
246             },
247             "[-fv] file prov"
248         },
249         { "resize", G_FLAG_VERBOSE, eli_main,
250             {
251                 { 's', "oldsize", NULL, G_TYPE_NUMBER },
252                 G_OPT_SENTINEL
253             },
254             "[-v] -s oldsize prov"
255         },
256         { "version", G_FLAG_LOADKLD, eli_main, G_NULL_OPTS,
257             "[prov ...]"
258         },
259         { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
260             "[-v] prov ..."
261         },
262         { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
263             "[-v] prov ..."
264         },
265         G_CMD_SENTINEL
266 };
267
268 static int verbose = 0;
269
270 #define BUFSIZE 1024
271
272 static int
273 eli_protect(struct gctl_req *req)
274 {
275         struct rlimit rl;
276
277         /* Disable core dumps. */
278         rl.rlim_cur = 0;
279         rl.rlim_max = 0;
280         if (setrlimit(RLIMIT_CORE, &rl) == -1) {
281                 gctl_error(req, "Cannot disable core dumps: %s.",
282                     strerror(errno));
283                 return (-1);
284         }
285         /* Disable swapping. */
286         if (mlockall(MCL_FUTURE) == -1) {
287                 gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
288                 return (-1);
289         }
290         return (0);
291 }
292
293 static void
294 eli_main(struct gctl_req *req, unsigned int flags)
295 {
296         const char *name;
297
298         if (eli_protect(req) == -1)
299                 return;
300
301         if ((flags & G_FLAG_VERBOSE) != 0)
302                 verbose = 1;
303
304         name = gctl_get_ascii(req, "verb");
305         if (name == NULL) {
306                 gctl_error(req, "No '%s' argument.", "verb");
307                 return;
308         }
309         if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
310                 eli_init(req);
311         else if (strcmp(name, "attach") == 0)
312                 eli_attach(req);
313         else if (strcmp(name, "configure") == 0)
314                 eli_configure(req);
315         else if (strcmp(name, "setkey") == 0)
316                 eli_setkey(req);
317         else if (strcmp(name, "delkey") == 0)
318                 eli_delkey(req);
319         else if (strcmp(name, "resume") == 0)
320                 eli_resume(req);
321         else if (strcmp(name, "kill") == 0)
322                 eli_kill(req);
323         else if (strcmp(name, "backup") == 0)
324                 eli_backup(req);
325         else if (strcmp(name, "restore") == 0)
326                 eli_restore(req);
327         else if (strcmp(name, "resize") == 0)
328                 eli_resize(req);
329         else if (strcmp(name, "version") == 0)
330                 eli_version(req);
331         else if (strcmp(name, "dump") == 0)
332                 eli_dump(req);
333         else if (strcmp(name, "clear") == 0)
334                 eli_clear(req);
335         else
336                 gctl_error(req, "Unknown command: %s.", name);
337 }
338
339 static bool
340 eli_is_attached(const char *prov)
341 {
342         char name[MAXPATHLEN];
343
344         /*
345          * Not the best way to do it, but the easiest.
346          * We try to open provider and check if it is a GEOM provider
347          * by asking about its sectorsize.
348          */
349         snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
350         return (g_get_sectorsize(name) > 0);
351 }
352
353 static int
354 eli_genkey_files(struct gctl_req *req, bool new, const char *type,
355     struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize)
356 {
357         char *p, buf[BUFSIZE], argname[16];
358         const char *file;
359         int error, fd, i;
360         ssize_t done;
361
362         assert((strcmp(type, "keyfile") == 0 && ctxp != NULL &&
363             passbuf == NULL && passbufsize == 0) ||
364             (strcmp(type, "passfile") == 0 && ctxp == NULL &&
365             passbuf != NULL && passbufsize > 0));
366         assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0');
367
368         for (i = 0; ; i++) {
369                 snprintf(argname, sizeof(argname), "%s%s%d",
370                     new ? "new" : "", type, i);
371
372                 /* No more {key,pass}files? */
373                 if (!gctl_has_param(req, argname))
374                         return (i);
375
376                 file = gctl_get_ascii(req, "%s", argname);
377                 assert(file != NULL);
378
379                 if (strcmp(file, "-") == 0)
380                         fd = STDIN_FILENO;
381                 else {
382                         fd = open(file, O_RDONLY);
383                         if (fd == -1) {
384                                 gctl_error(req, "Cannot open %s %s: %s.",
385                                     type, file, strerror(errno));
386                                 return (-1);
387                         }
388                 }
389                 if (strcmp(type, "keyfile") == 0) {
390                         while ((done = read(fd, buf, sizeof(buf))) > 0)
391                                 g_eli_crypto_hmac_update(ctxp, buf, done);
392                 } else /* if (strcmp(type, "passfile") == 0) */ {
393                         assert(strcmp(type, "passfile") == 0);
394
395                         while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) {
396                                 buf[done] = '\0';
397                                 p = strchr(buf, '\n');
398                                 if (p != NULL) {
399                                         *p = '\0';
400                                         done = p - buf;
401                                 }
402                                 if (strlcat(passbuf, buf, passbufsize) >=
403                                     passbufsize) {
404                                         gctl_error(req,
405                                             "Passphrase in %s too long.", file);
406                                         bzero(buf, sizeof(buf));
407                                         return (-1);
408                                 }
409                                 if (p != NULL)
410                                         break;
411                         }
412                 }
413                 error = errno;
414                 if (strcmp(file, "-") != 0)
415                         close(fd);
416                 bzero(buf, sizeof(buf));
417                 if (done == -1) {
418                         gctl_error(req, "Cannot read %s %s: %s.",
419                             type, file, strerror(error));
420                         return (-1);
421                 }
422         }
423         /* NOTREACHED */
424 }
425
426 static int
427 eli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf,
428     size_t passbufsize)
429 {
430         char *p;
431
432         for (;;) {
433                 p = readpassphrase(
434                     new ? "Enter new passphrase: " : "Enter passphrase: ",
435                     passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY);
436                 if (p == NULL) {
437                         bzero(passbuf, passbufsize);
438                         gctl_error(req, "Cannot read passphrase: %s.",
439                             strerror(errno));
440                         return (-1);
441                 }
442
443                 if (new) {
444                         char tmpbuf[BUFSIZE];
445
446                         p = readpassphrase("Reenter new passphrase: ",
447                             tmpbuf, sizeof(tmpbuf),
448                             RPP_ECHO_OFF | RPP_REQUIRE_TTY);
449                         if (p == NULL) {
450                                 bzero(passbuf, passbufsize);
451                                 gctl_error(req,
452                                     "Cannot read passphrase: %s.",
453                                     strerror(errno));
454                                 return (-1);
455                         }
456
457                         if (strcmp(passbuf, tmpbuf) != 0) {
458                                 bzero(passbuf, passbufsize);
459                                 fprintf(stderr, "They didn't match.\n");
460                                 continue;
461                         }
462                         bzero(tmpbuf, sizeof(tmpbuf));
463                 }
464                 return (0);
465         }
466         /* NOTREACHED */
467 }
468
469 static int
470 eli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new,
471     struct hmac_ctx *ctxp)
472 {
473         char passbuf[BUFSIZE];
474         bool nopassphrase;
475         int nfiles;
476
477         nopassphrase =
478             gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
479         if (nopassphrase) {
480                 if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) {
481                         gctl_error(req,
482                             "Options -%c and -%c are mutually exclusive.",
483                             new ? 'J' : 'j', new ? 'P' : 'p');
484                         return (-1);
485                 }
486                 return (0);
487         }
488
489         if (!new && md->md_iterations == -1) {
490                 gctl_error(req, "Missing -p flag.");
491                 return (-1);
492         }
493         passbuf[0] = '\0';
494         nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf,
495             sizeof(passbuf));
496         if (nfiles == -1)
497                 return (-1);
498         else if (nfiles == 0) {
499                 if (eli_genkey_passphrase_prompt(req, new, passbuf,
500                     sizeof(passbuf)) == -1) {
501                         return (-1);
502                 }
503         }
504         /*
505          * Field md_iterations equal to -1 means "choose some sane
506          * value for me".
507          */
508         if (md->md_iterations == -1) {
509                 assert(new);
510                 if (verbose)
511                         printf("Calculating number of iterations...\n");
512                 md->md_iterations = pkcs5v2_calculate(2000000);
513                 assert(md->md_iterations > 0);
514                 if (verbose) {
515                         printf("Done, using %d iterations.\n",
516                             md->md_iterations);
517                 }
518         }
519         /*
520          * If md_iterations is equal to 0, user doesn't want PKCS#5v2.
521          */
522         if (md->md_iterations == 0) {
523                 g_eli_crypto_hmac_update(ctxp, md->md_salt,
524                     sizeof(md->md_salt));
525                 g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf));
526         } else /* if (md->md_iterations > 0) */ {
527                 unsigned char dkey[G_ELI_USERKEYLEN];
528
529                 pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
530                     sizeof(md->md_salt), passbuf, md->md_iterations);
531                 g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey));
532                 bzero(dkey, sizeof(dkey));
533         }
534         bzero(passbuf, sizeof(passbuf));
535
536         return (0);
537 }
538
539 static unsigned char *
540 eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
541     bool new)
542 {
543         struct hmac_ctx ctx;
544         bool nopassphrase;
545         int nfiles;
546
547         nopassphrase =
548             gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
549
550         g_eli_crypto_hmac_init(&ctx, NULL, 0);
551
552         nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0);
553         if (nfiles == -1)
554                 return (NULL);
555         else if (nfiles == 0 && nopassphrase) {
556                 gctl_error(req, "No key components given.");
557                 return (NULL);
558         }
559
560         if (eli_genkey_passphrase(req, md, new, &ctx) == -1)
561                 return (NULL);
562
563         g_eli_crypto_hmac_final(&ctx, key, 0);
564
565         return (key);
566 }
567
568 static int
569 eli_metadata_read(struct gctl_req *req, const char *prov,
570     struct g_eli_metadata *md)
571 {
572         unsigned char sector[sizeof(struct g_eli_metadata)];
573         int error;
574
575         if (g_get_sectorsize(prov) == 0) {
576                 int fd;
577
578                 /* This is a file probably. */
579                 fd = open(prov, O_RDONLY);
580                 if (fd == -1) {
581                         gctl_error(req, "Cannot open %s: %s.", prov,
582                             strerror(errno));
583                         return (-1);
584                 }
585                 if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
586                         gctl_error(req, "Cannot read metadata from %s: %s.",
587                             prov, strerror(errno));
588                         close(fd);
589                         return (-1);
590                 }
591                 close(fd);
592         } else {
593                 /* This is a GEOM provider. */
594                 error = g_metadata_read(prov, sector, sizeof(sector),
595                     G_ELI_MAGIC);
596                 if (error != 0) {
597                         gctl_error(req, "Cannot read metadata from %s: %s.",
598                             prov, strerror(error));
599                         return (-1);
600                 }
601         }
602         error = eli_metadata_decode(sector, md);
603         switch (error) {
604         case 0:
605                 break;
606         case EOPNOTSUPP:
607                 gctl_error(req,
608                     "Provider's %s metadata version %u is too new.\n"
609                     "geli: The highest supported version is %u.",
610                     prov, (unsigned int)md->md_version, G_ELI_VERSION);
611                 return (-1);
612         case EINVAL:
613                 gctl_error(req, "Inconsistent provider's %s metadata.", prov);
614                 return (-1);
615         default:
616                 gctl_error(req,
617                     "Unexpected error while decoding provider's %s metadata: %s.",
618                     prov, strerror(error));
619                 return (-1);
620         }
621         return (0);
622 }
623
624 static int
625 eli_metadata_store(struct gctl_req *req, const char *prov,
626     struct g_eli_metadata *md)
627 {
628         unsigned char sector[sizeof(struct g_eli_metadata)];
629         int error;
630
631         eli_metadata_encode(md, sector);
632         if (g_get_sectorsize(prov) == 0) {
633                 int fd;
634
635                 /* This is a file probably. */
636                 fd = open(prov, O_WRONLY | O_TRUNC);
637                 if (fd == -1) {
638                         gctl_error(req, "Cannot open %s: %s.", prov,
639                             strerror(errno));
640                         bzero(sector, sizeof(sector));
641                         return (-1);
642                 }
643                 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
644                         gctl_error(req, "Cannot write metadata to %s: %s.",
645                             prov, strerror(errno));
646                         bzero(sector, sizeof(sector));
647                         close(fd);
648                         return (-1);
649                 }
650                 close(fd);
651         } else {
652                 /* This is a GEOM provider. */
653                 error = g_metadata_store(prov, sector, sizeof(sector));
654                 if (error != 0) {
655                         gctl_error(req, "Cannot write metadata to %s: %s.",
656                             prov, strerror(errno));
657                         bzero(sector, sizeof(sector));
658                         return (-1);
659                 }
660         }
661         bzero(sector, sizeof(sector));
662         return (0);
663 }
664
665 static void
666 eli_init(struct gctl_req *req)
667 {
668         struct g_eli_metadata md;
669         unsigned char sector[sizeof(struct g_eli_metadata)] __aligned(4);
670         unsigned char key[G_ELI_USERKEYLEN];
671         char backfile[MAXPATHLEN];
672         const char *str, *prov;
673         unsigned int secsize, version;
674         off_t mediasize;
675         intmax_t val;
676         int error, nargs;
677
678         nargs = gctl_get_int(req, "nargs");
679         if (nargs != 1) {
680                 gctl_error(req, "Invalid number of arguments.");
681                 return;
682         }
683         prov = gctl_get_ascii(req, "arg0");
684         mediasize = g_get_mediasize(prov);
685         secsize = g_get_sectorsize(prov);
686         if (mediasize == 0 || secsize == 0) {
687                 gctl_error(req, "Cannot get informations about %s: %s.", prov,
688                     strerror(errno));
689                 return;
690         }
691
692         bzero(&md, sizeof(md));
693         strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
694         val = gctl_get_intmax(req, "mdversion");
695         if (val == -1) {
696                 version = G_ELI_VERSION;
697         } else if (val < 0 || val > G_ELI_VERSION) {
698                 gctl_error(req,
699                     "Invalid version specified should be between %u and %u.",
700                     G_ELI_VERSION_00, G_ELI_VERSION);
701                 return;
702         } else {
703                 version = val;
704         }
705         md.md_version = version;
706         md.md_flags = 0;
707         if (gctl_get_int(req, "boot"))
708                 md.md_flags |= G_ELI_FLAG_BOOT;
709         if (gctl_get_int(req, "geliboot"))
710                 md.md_flags |= G_ELI_FLAG_GELIBOOT;
711         if (gctl_get_int(req, "notrim"))
712                 md.md_flags |= G_ELI_FLAG_NODELETE;
713         md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
714         str = gctl_get_ascii(req, "aalgo");
715         if (*str != '\0') {
716                 if (version < G_ELI_VERSION_01) {
717                         gctl_error(req,
718                             "Data authentication is supported starting from version %u.",
719                             G_ELI_VERSION_01);
720                         return;
721                 }
722                 md.md_aalgo = g_eli_str2aalgo(str);
723                 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
724                     md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
725                         md.md_flags |= G_ELI_FLAG_AUTH;
726                 } else {
727                         /*
728                          * For backward compatibility, check if the -a option
729                          * was used to provide encryption algorithm.
730                          */
731                         md.md_ealgo = g_eli_str2ealgo(str);
732                         if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
733                             md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
734                                 gctl_error(req,
735                                     "Invalid authentication algorithm.");
736                                 return;
737                         } else {
738                                 fprintf(stderr, "warning: The -e option, not "
739                                     "the -a option is now used to specify "
740                                     "encryption algorithm to use.\n");
741                         }
742                 }
743         }
744         if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
745             md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
746                 str = gctl_get_ascii(req, "ealgo");
747                 if (*str == '\0') {
748                         if (version < G_ELI_VERSION_05)
749                                 str = "aes-cbc";
750                         else
751                                 str = GELI_ENC_ALGO;
752                 }
753                 md.md_ealgo = g_eli_str2ealgo(str);
754                 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
755                     md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
756                         gctl_error(req, "Invalid encryption algorithm.");
757                         return;
758                 }
759                 if (md.md_ealgo == CRYPTO_CAMELLIA_CBC &&
760                     version < G_ELI_VERSION_04) {
761                         gctl_error(req,
762                             "Camellia-CBC algorithm is supported starting from version %u.",
763                             G_ELI_VERSION_04);
764                         return;
765                 }
766                 if (md.md_ealgo == CRYPTO_AES_XTS &&
767                     version < G_ELI_VERSION_05) {
768                         gctl_error(req,
769                             "AES-XTS algorithm is supported starting from version %u.",
770                             G_ELI_VERSION_05);
771                         return;
772                 }
773         }
774         val = gctl_get_intmax(req, "keylen");
775         md.md_keylen = val;
776         md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
777         if (md.md_keylen == 0) {
778                 gctl_error(req, "Invalid key length.");
779                 return;
780         }
781         md.md_provsize = mediasize;
782
783         val = gctl_get_intmax(req, "iterations");
784         if (val != -1) {
785                 int nonewpassphrase;
786
787                 /*
788                  * Don't allow to set iterations when there will be no
789                  * passphrase.
790                  */
791                 nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
792                 if (nonewpassphrase) {
793                         gctl_error(req,
794                             "Options -i and -P are mutually exclusive.");
795                         return;
796                 }
797         }
798         md.md_iterations = val;
799
800         val = gctl_get_intmax(req, "sectorsize");
801         if (val == 0)
802                 md.md_sectorsize = secsize;
803         else {
804                 if (val < 0 || (val % secsize) != 0 || !powerof2(val)) {
805                         gctl_error(req, "Invalid sector size.");
806                         return;
807                 }
808                 if (val > sysconf(_SC_PAGE_SIZE)) {
809                         fprintf(stderr,
810                             "warning: Using sectorsize bigger than the page size!\n");
811                 }
812                 md.md_sectorsize = val;
813         }
814
815         md.md_keys = 0x01;
816         arc4random_buf(md.md_salt, sizeof(md.md_salt));
817         arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
818
819         /* Generate user key. */
820         if (eli_genkey(req, &md, key, true) == NULL) {
821                 bzero(key, sizeof(key));
822                 bzero(&md, sizeof(md));
823                 return;
824         }
825
826         /* Encrypt the first and the only Master Key. */
827         error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
828         bzero(key, sizeof(key));
829         if (error != 0) {
830                 bzero(&md, sizeof(md));
831                 gctl_error(req, "Cannot encrypt Master Key: %s.",
832                     strerror(error));
833                 return;
834         }
835
836         eli_metadata_encode(&md, sector);
837         bzero(&md, sizeof(md));
838         error = g_metadata_store(prov, sector, sizeof(sector));
839         bzero(sector, sizeof(sector));
840         if (error != 0) {
841                 gctl_error(req, "Cannot store metadata on %s: %s.", prov,
842                     strerror(error));
843                 return;
844         }
845         if (verbose)
846                 printf("Metadata value stored on %s.\n", prov);
847         /* Backup metadata to a file. */
848         str = gctl_get_ascii(req, "backupfile");
849         if (str[0] != '\0') {
850                 /* Backupfile given be the user, just copy it. */
851                 strlcpy(backfile, str, sizeof(backfile));
852         } else {
853                 /* Generate file name automatically. */
854                 const char *p = prov;
855                 unsigned int i;
856
857                 if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
858                         p += sizeof(_PATH_DEV) - 1;
859                 snprintf(backfile, sizeof(backfile), "%s%s.eli",
860                     GELI_BACKUP_DIR, p);
861                 /* Replace all / with _. */
862                 for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
863                         if (backfile[i] == '/')
864                                 backfile[i] = '_';
865                 }
866         }
867         if (strcmp(backfile, "none") != 0 &&
868             eli_backup_create(req, prov, backfile) == 0) {
869                 printf("\nMetadata backup can be found in %s and\n", backfile);
870                 printf("can be restored with the following command:\n");
871                 printf("\n\t# geli restore %s %s\n\n", backfile, prov);
872         }
873 }
874
875 static void
876 eli_attach(struct gctl_req *req)
877 {
878         struct g_eli_metadata md;
879         unsigned char key[G_ELI_USERKEYLEN];
880         const char *prov;
881         off_t mediasize;
882         int nargs;
883
884         nargs = gctl_get_int(req, "nargs");
885         if (nargs != 1) {
886                 gctl_error(req, "Invalid number of arguments.");
887                 return;
888         }
889         prov = gctl_get_ascii(req, "arg0");
890
891         if (eli_metadata_read(req, prov, &md) == -1)
892                 return;
893
894         mediasize = g_get_mediasize(prov);
895         if (md.md_provsize != (uint64_t)mediasize) {
896                 gctl_error(req, "Provider size mismatch.");
897                 return;
898         }
899
900         if (eli_genkey(req, &md, key, false) == NULL) {
901                 bzero(key, sizeof(key));
902                 return;
903         }
904
905         gctl_ro_param(req, "key", sizeof(key), key);
906         if (gctl_issue(req) == NULL) {
907                 if (verbose)
908                         printf("Attached to %s.\n", prov);
909         }
910         bzero(key, sizeof(key));
911 }
912
913 static void
914 eli_configure_detached(struct gctl_req *req, const char *prov, int boot,
915  int geliboot, int trim)
916 {
917         struct g_eli_metadata md;
918         bool changed = 0;
919
920         if (eli_metadata_read(req, prov, &md) == -1)
921                 return;
922
923         if (boot == 1 && (md.md_flags & G_ELI_FLAG_BOOT)) {
924                 if (verbose)
925                         printf("BOOT flag already configured for %s.\n", prov);
926         } else if (boot == 0 && !(md.md_flags & G_ELI_FLAG_BOOT)) {
927                 if (verbose)
928                         printf("BOOT flag not configured for %s.\n", prov);
929         } else if (boot >= 0) {
930                 if (boot)
931                         md.md_flags |= G_ELI_FLAG_BOOT;
932                 else
933                         md.md_flags &= ~G_ELI_FLAG_BOOT;
934                 changed = 1;
935         }
936
937         if (geliboot == 1 && (md.md_flags & G_ELI_FLAG_GELIBOOT)) {
938                 if (verbose)
939                         printf("GELIBOOT flag already configured for %s.\n", prov);
940         } else if (geliboot == 0 && !(md.md_flags & G_ELI_FLAG_GELIBOOT)) {
941                 if (verbose)
942                         printf("GELIBOOT flag not configured for %s.\n", prov);
943         } else if (geliboot >= 0) {
944                 if (geliboot)
945                         md.md_flags |= G_ELI_FLAG_GELIBOOT;
946                 else
947                         md.md_flags &= ~G_ELI_FLAG_GELIBOOT;
948                 changed = 1;
949         }
950
951         if (trim == 0 && (md.md_flags & G_ELI_FLAG_NODELETE)) {
952                 if (verbose)
953                         printf("TRIM disable flag already configured for %s.\n", prov);
954         } else if (trim == 1 && !(md.md_flags & G_ELI_FLAG_NODELETE)) {
955                 if (verbose)
956                         printf("TRIM disable flag not configured for %s.\n", prov);
957         } else if (trim >= 0) {
958                 if (trim)
959                         md.md_flags &= ~G_ELI_FLAG_NODELETE;
960                 else
961                         md.md_flags |= G_ELI_FLAG_NODELETE;
962                 changed = 1;
963         }
964
965         if (changed)
966                 eli_metadata_store(req, prov, &md);
967         bzero(&md, sizeof(md));
968 }
969
970 static void
971 eli_configure(struct gctl_req *req)
972 {
973         const char *prov;
974         bool boot, noboot, geliboot, nogeliboot, trim, notrim;
975         int doboot, dogeliboot, dotrim;
976         int i, nargs;
977
978         nargs = gctl_get_int(req, "nargs");
979         if (nargs == 0) {
980                 gctl_error(req, "Too few arguments.");
981                 return;
982         }
983
984         boot = gctl_get_int(req, "boot");
985         noboot = gctl_get_int(req, "noboot");
986         geliboot = gctl_get_int(req, "geliboot");
987         nogeliboot = gctl_get_int(req, "nogeliboot");
988         trim = gctl_get_int(req, "trim");
989         notrim = gctl_get_int(req, "notrim");
990
991         doboot = -1;
992         if (boot && noboot) {
993                 gctl_error(req, "Options -b and -B are mutually exclusive.");
994                 return;
995         }
996         if (boot)
997                 doboot = 1;
998         else if (noboot)
999                 doboot = 0;
1000
1001         dogeliboot = -1;
1002         if (geliboot && nogeliboot) {
1003                 gctl_error(req, "Options -g and -G are mutually exclusive.");
1004                 return;
1005         }
1006         if (geliboot)
1007                 dogeliboot = 1;
1008         else if (nogeliboot)
1009                 dogeliboot = 0;
1010
1011         dotrim = -1;
1012         if (trim && notrim) {
1013                 gctl_error(req, "Options -t and -T are mutually exclusive.");
1014                 return;
1015         }
1016         if (trim)
1017                 dotrim = 1;
1018         else if (notrim)
1019                 dotrim = 0;
1020
1021         if (doboot == -1 && dogeliboot == -1 && dotrim == -1) {
1022                 gctl_error(req, "No option given.");
1023                 return;
1024         }
1025
1026         /* First attached providers. */
1027         gctl_issue(req);
1028         /* Now the rest. */
1029         for (i = 0; i < nargs; i++) {
1030                 prov = gctl_get_ascii(req, "arg%d", i);
1031                 if (!eli_is_attached(prov))
1032                         eli_configure_detached(req, prov, doboot, dogeliboot, dotrim);
1033         }
1034 }
1035
1036 static void
1037 eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
1038 {
1039         unsigned char key[G_ELI_USERKEYLEN];
1040         intmax_t val, old = 0;
1041         int error;
1042
1043         val = gctl_get_intmax(req, "iterations");
1044         /* Check if iterations number should be changed. */
1045         if (val != -1)
1046                 md->md_iterations = val;
1047         else
1048                 old = md->md_iterations;
1049
1050         /* Generate key for Master Key encryption. */
1051         if (eli_genkey(req, md, key, true) == NULL) {
1052                 bzero(key, sizeof(key));
1053                 return;
1054         }
1055         /*
1056          * If number of iterations has changed, but wasn't given as a
1057          * command-line argument, update the request.
1058          */
1059         if (val == -1 && md->md_iterations != old) {
1060                 error = gctl_change_param(req, "iterations", sizeof(intmax_t),
1061                     &md->md_iterations);
1062                 assert(error == 0);
1063         }
1064
1065         gctl_ro_param(req, "key", sizeof(key), key);
1066         gctl_issue(req);
1067         bzero(key, sizeof(key));
1068 }
1069
1070 static void
1071 eli_setkey_detached(struct gctl_req *req, const char *prov,
1072  struct g_eli_metadata *md)
1073 {
1074         unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
1075         unsigned char *mkeydst;
1076         unsigned int nkey;
1077         intmax_t val;
1078         int error;
1079
1080         if (md->md_keys == 0) {
1081                 gctl_error(req, "No valid keys on %s.", prov);
1082                 return;
1083         }
1084
1085         /* Generate key for Master Key decryption. */
1086         if (eli_genkey(req, md, key, false) == NULL) {
1087                 bzero(key, sizeof(key));
1088                 return;
1089         }
1090
1091         /* Decrypt Master Key. */
1092         error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
1093         bzero(key, sizeof(key));
1094         if (error != 0) {
1095                 bzero(md, sizeof(*md));
1096                 if (error == -1)
1097                         gctl_error(req, "Wrong key for %s.", prov);
1098                 else /* if (error > 0) */ {
1099                         gctl_error(req, "Cannot decrypt Master Key: %s.",
1100                             strerror(error));
1101                 }
1102                 return;
1103         }
1104         if (verbose)
1105                 printf("Decrypted Master Key %u.\n", nkey);
1106
1107         val = gctl_get_intmax(req, "keyno");
1108         if (val != -1)
1109                 nkey = val;
1110 #if 0
1111         else
1112                 ; /* Use the key number which was found during decryption. */
1113 #endif
1114         if (nkey >= G_ELI_MAXMKEYS) {
1115                 gctl_error(req, "Invalid '%s' argument.", "keyno");
1116                 return;
1117         }
1118
1119         val = gctl_get_intmax(req, "iterations");
1120         /* Check if iterations number should and can be changed. */
1121         if (val != -1) {
1122                 if (bitcount32(md->md_keys) != 1) {
1123                         gctl_error(req, "To be able to use '-i' option, only "
1124                             "one key can be defined.");
1125                         return;
1126                 }
1127                 if (md->md_keys != (1 << nkey)) {
1128                         gctl_error(req, "Only already defined key can be "
1129                             "changed when '-i' option is used.");
1130                         return;
1131                 }
1132                 md->md_iterations = val;
1133         }
1134
1135         mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
1136         md->md_keys |= (1 << nkey);
1137
1138         bcopy(mkey, mkeydst, sizeof(mkey));
1139         bzero(mkey, sizeof(mkey));
1140
1141         /* Generate key for Master Key encryption. */
1142         if (eli_genkey(req, md, key, true) == NULL) {
1143                 bzero(key, sizeof(key));
1144                 bzero(md, sizeof(*md));
1145                 return;
1146         }
1147
1148         /* Encrypt the Master-Key with the new key. */
1149         error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
1150         bzero(key, sizeof(key));
1151         if (error != 0) {
1152                 bzero(md, sizeof(*md));
1153                 gctl_error(req, "Cannot encrypt Master Key: %s.",
1154                     strerror(error));
1155                 return;
1156         }
1157
1158         /* Store metadata with fresh key. */
1159         eli_metadata_store(req, prov, md);
1160         bzero(md, sizeof(*md));
1161 }
1162
1163 static void
1164 eli_setkey(struct gctl_req *req)
1165 {
1166         struct g_eli_metadata md;
1167         const char *prov;
1168         int nargs;
1169
1170         nargs = gctl_get_int(req, "nargs");
1171         if (nargs != 1) {
1172                 gctl_error(req, "Invalid number of arguments.");
1173                 return;
1174         }
1175         prov = gctl_get_ascii(req, "arg0");
1176
1177         if (eli_metadata_read(req, prov, &md) == -1)
1178                 return;
1179
1180         if (eli_is_attached(prov))
1181                 eli_setkey_attached(req, &md);
1182         else
1183                 eli_setkey_detached(req, prov, &md);
1184
1185         if (req->error == NULL || req->error[0] == '\0') {
1186                 printf("Note, that the master key encrypted with old keys "
1187                     "and/or passphrase may still exists in a metadata backup "
1188                     "file.\n");
1189         }
1190 }
1191
1192 static void
1193 eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
1194 {
1195
1196         gctl_issue(req);
1197 }
1198
1199 static void
1200 eli_delkey_detached(struct gctl_req *req, const char *prov)
1201 {
1202         struct g_eli_metadata md;
1203         unsigned char *mkeydst;
1204         unsigned int nkey;
1205         intmax_t val;
1206         bool all, force;
1207
1208         if (eli_metadata_read(req, prov, &md) == -1)
1209                 return;
1210
1211         all = gctl_get_int(req, "all");
1212         if (all)
1213                 arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
1214         else {
1215                 force = gctl_get_int(req, "force");
1216                 val = gctl_get_intmax(req, "keyno");
1217                 if (val == -1) {
1218                         gctl_error(req, "Key number has to be specified.");
1219                         return;
1220                 }
1221                 nkey = val;
1222                 if (nkey >= G_ELI_MAXMKEYS) {
1223                         gctl_error(req, "Invalid '%s' argument.", "keyno");
1224                         return;
1225                 }
1226                 if (!(md.md_keys & (1 << nkey)) && !force) {
1227                         gctl_error(req, "Master Key %u is not set.", nkey);
1228                         return;
1229                 }
1230                 md.md_keys &= ~(1 << nkey);
1231                 if (md.md_keys == 0 && !force) {
1232                         gctl_error(req, "This is the last Master Key. Use '-f' "
1233                             "option if you really want to remove it.");
1234                         return;
1235                 }
1236                 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
1237                 arc4random_buf(mkeydst, G_ELI_MKEYLEN);
1238         }
1239
1240         eli_metadata_store(req, prov, &md);
1241         bzero(&md, sizeof(md));
1242 }
1243
1244 static void
1245 eli_delkey(struct gctl_req *req)
1246 {
1247         const char *prov;
1248         int nargs;
1249
1250         nargs = gctl_get_int(req, "nargs");
1251         if (nargs != 1) {
1252                 gctl_error(req, "Invalid number of arguments.");
1253                 return;
1254         }
1255         prov = gctl_get_ascii(req, "arg0");
1256
1257         if (eli_is_attached(prov))
1258                 eli_delkey_attached(req, prov);
1259         else
1260                 eli_delkey_detached(req, prov);
1261 }
1262
1263 static void
1264 eli_resume(struct gctl_req *req)
1265 {
1266         struct g_eli_metadata md;
1267         unsigned char key[G_ELI_USERKEYLEN];
1268         const char *prov;
1269         off_t mediasize;
1270         int nargs;
1271
1272         nargs = gctl_get_int(req, "nargs");
1273         if (nargs != 1) {
1274                 gctl_error(req, "Invalid number of arguments.");
1275                 return;
1276         }
1277         prov = gctl_get_ascii(req, "arg0");
1278
1279         if (eli_metadata_read(req, prov, &md) == -1)
1280                 return;
1281
1282         mediasize = g_get_mediasize(prov);
1283         if (md.md_provsize != (uint64_t)mediasize) {
1284                 gctl_error(req, "Provider size mismatch.");
1285                 return;
1286         }
1287
1288         if (eli_genkey(req, &md, key, false) == NULL) {
1289                 bzero(key, sizeof(key));
1290                 return;
1291         }
1292
1293         gctl_ro_param(req, "key", sizeof(key), key);
1294         if (gctl_issue(req) == NULL) {
1295                 if (verbose)
1296                         printf("Resumed %s.\n", prov);
1297         }
1298         bzero(key, sizeof(key));
1299 }
1300
1301 static int
1302 eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset)
1303 {
1304         unsigned int overwrites;
1305         unsigned char *sector;
1306         ssize_t size;
1307         int error;
1308
1309         size = sizeof(overwrites);
1310         if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size,
1311             NULL, 0) == -1 || overwrites == 0) {
1312                 overwrites = G_ELI_OVERWRITES;
1313         }
1314
1315         size = g_sectorsize(fd);
1316         if (size <= 0) {
1317                 gctl_error(req, "Cannot obtain provider sector size %s: %s.",
1318                     prov, strerror(errno));
1319                 return (-1);
1320         }
1321         sector = malloc(size);
1322         if (sector == NULL) {
1323                 gctl_error(req, "Cannot allocate %zd bytes of memory.", size);
1324                 return (-1);
1325         }
1326
1327         error = 0;
1328         do {
1329                 arc4random_buf(sector, size);
1330                 if (pwrite(fd, sector, size, offset) != size) {
1331                         if (error == 0)
1332                                 error = errno;
1333                 }
1334                 (void)g_flush(fd);
1335         } while (--overwrites > 0);
1336         free(sector);
1337         if (error != 0) {
1338                 gctl_error(req, "Cannot trash metadata on provider %s: %s.",
1339                     prov, strerror(error));
1340                 return (-1);
1341         }
1342         return (0);
1343 }
1344
1345 static void
1346 eli_kill_detached(struct gctl_req *req, const char *prov)
1347 {
1348         off_t offset;
1349         int fd;
1350
1351         /*
1352          * NOTE: Maybe we should verify if this is geli provider first,
1353          *       but 'kill' command is quite critical so better don't waste
1354          *       the time.
1355          */
1356 #if 0
1357         error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
1358             G_ELI_MAGIC);
1359         if (error != 0) {
1360                 gctl_error(req, "Cannot read metadata from %s: %s.", prov,
1361                     strerror(error));
1362                 return;
1363         }
1364 #endif
1365
1366         fd = g_open(prov, 1);
1367         if (fd == -1) {
1368                 gctl_error(req, "Cannot open provider %s: %s.", prov,
1369                     strerror(errno));
1370                 return;
1371         }
1372         offset = g_mediasize(fd) - g_sectorsize(fd);
1373         if (offset <= 0) {
1374                 gctl_error(req,
1375                     "Cannot obtain media size or sector size for provider %s: %s.",
1376                     prov, strerror(errno));
1377                 (void)g_close(fd);
1378                 return;
1379         }
1380         (void)eli_trash_metadata(req, prov, fd, offset);
1381         (void)g_close(fd);
1382 }
1383
1384 static void
1385 eli_kill(struct gctl_req *req)
1386 {
1387         const char *prov;
1388         int i, nargs, all;
1389
1390         nargs = gctl_get_int(req, "nargs");
1391         all = gctl_get_int(req, "all");
1392         if (!all && nargs == 0) {
1393                 gctl_error(req, "Too few arguments.");
1394                 return;
1395         }
1396         /*
1397          * How '-a' option combine with a list of providers:
1398          * Delete Master Keys from all attached providers:
1399          * geli kill -a
1400          * Delete Master Keys from all attached providers and from
1401          * detached da0 and da1:
1402          * geli kill -a da0 da1
1403          * Delete Master Keys from (attached or detached) da0 and da1:
1404          * geli kill da0 da1
1405          */
1406
1407         /* First detached providers. */
1408         for (i = 0; i < nargs; i++) {
1409                 prov = gctl_get_ascii(req, "arg%d", i);
1410                 if (!eli_is_attached(prov))
1411                         eli_kill_detached(req, prov);
1412         }
1413         /* Now attached providers. */
1414         gctl_issue(req);
1415 }
1416
1417 static int
1418 eli_backup_create(struct gctl_req *req, const char *prov, const char *file)
1419 {
1420         unsigned char *sector;
1421         ssize_t secsize;
1422         int error, filefd, ret;
1423
1424         ret = -1;
1425         filefd = -1;
1426         sector = NULL;
1427         secsize = 0;
1428
1429         secsize = g_get_sectorsize(prov);
1430         if (secsize == 0) {
1431                 gctl_error(req, "Cannot get informations about %s: %s.", prov,
1432                     strerror(errno));
1433                 goto out;
1434         }
1435         sector = malloc(secsize);
1436         if (sector == NULL) {
1437                 gctl_error(req, "Cannot allocate memory.");
1438                 goto out;
1439         }
1440         /* Read metadata from the provider. */
1441         error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC);
1442         if (error != 0) {
1443                 gctl_error(req, "Unable to read metadata from %s: %s.", prov,
1444                     strerror(error));
1445                 goto out;
1446         }
1447
1448         filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1449         if (filefd == -1) {
1450                 gctl_error(req, "Unable to open %s: %s.", file,
1451                     strerror(errno));
1452                 goto out;
1453         }
1454         /* Write metadata to the destination file. */
1455         if (write(filefd, sector, secsize) != secsize) {
1456                 gctl_error(req, "Unable to write to %s: %s.", file,
1457                     strerror(errno));
1458                 (void)close(filefd);
1459                 (void)unlink(file);
1460                 goto out;
1461         }
1462         (void)fsync(filefd);
1463         (void)close(filefd);
1464         /* Success. */
1465         ret = 0;
1466 out:
1467         if (sector != NULL) {
1468                 bzero(sector, secsize);
1469                 free(sector);
1470         }
1471         return (ret);
1472 }
1473
1474 static void
1475 eli_backup(struct gctl_req *req)
1476 {
1477         const char *file, *prov;
1478         int nargs;
1479
1480         nargs = gctl_get_int(req, "nargs");
1481         if (nargs != 2) {
1482                 gctl_error(req, "Invalid number of arguments.");
1483                 return;
1484         }
1485         prov = gctl_get_ascii(req, "arg0");
1486         file = gctl_get_ascii(req, "arg1");
1487
1488         eli_backup_create(req, prov, file);
1489 }
1490
1491 static void
1492 eli_restore(struct gctl_req *req)
1493 {
1494         struct g_eli_metadata md;
1495         const char *file, *prov;
1496         off_t mediasize;
1497         int nargs;
1498
1499         nargs = gctl_get_int(req, "nargs");
1500         if (nargs != 2) {
1501                 gctl_error(req, "Invalid number of arguments.");
1502                 return;
1503         }
1504         file = gctl_get_ascii(req, "arg0");
1505         prov = gctl_get_ascii(req, "arg1");
1506
1507         /* Read metadata from the backup file. */
1508         if (eli_metadata_read(req, file, &md) == -1)
1509                 return;
1510         /* Obtain provider's mediasize. */
1511         mediasize = g_get_mediasize(prov);
1512         if (mediasize == 0) {
1513                 gctl_error(req, "Cannot get informations about %s: %s.", prov,
1514                     strerror(errno));
1515                 return;
1516         }
1517         /* Check if the provider size has changed since we did the backup. */
1518         if (md.md_provsize != (uint64_t)mediasize) {
1519                 if (gctl_get_int(req, "force")) {
1520                         md.md_provsize = mediasize;
1521                 } else {
1522                         gctl_error(req, "Provider size mismatch: "
1523                             "wrong backup file?");
1524                         return;
1525                 }
1526         }
1527         /* Write metadata to the provider. */
1528         (void)eli_metadata_store(req, prov, &md);
1529 }
1530
1531 static void
1532 eli_resize(struct gctl_req *req)
1533 {
1534         struct g_eli_metadata md;
1535         const char *prov;
1536         unsigned char *sector;
1537         ssize_t secsize;
1538         off_t mediasize, oldsize;
1539         int error, nargs, provfd;
1540
1541         nargs = gctl_get_int(req, "nargs");
1542         if (nargs != 1) {
1543                 gctl_error(req, "Invalid number of arguments.");
1544                 return;
1545         }
1546         prov = gctl_get_ascii(req, "arg0");
1547
1548         provfd = -1;
1549         sector = NULL;
1550         secsize = 0;
1551
1552         provfd = g_open(prov, 1);
1553         if (provfd == -1) {
1554                 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1555                 goto out;
1556         }
1557
1558         mediasize = g_mediasize(provfd);
1559         secsize = g_sectorsize(provfd);
1560         if (mediasize == -1 || secsize == -1) {
1561                 gctl_error(req, "Cannot get information about %s: %s.", prov,
1562                     strerror(errno));
1563                 goto out;
1564         }
1565
1566         sector = malloc(secsize);
1567         if (sector == NULL) {
1568                 gctl_error(req, "Cannot allocate memory.");
1569                 goto out;
1570         }
1571
1572         oldsize = gctl_get_intmax(req, "oldsize");
1573         if (oldsize < 0 || oldsize > mediasize) {
1574                 gctl_error(req, "Invalid oldsize: Out of range.");
1575                 goto out;
1576         }
1577         if (oldsize == mediasize) {
1578                 gctl_error(req, "Size hasn't changed.");
1579                 goto out;
1580         }
1581
1582         /* Read metadata from the 'oldsize' offset. */
1583         if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
1584                 gctl_error(req, "Cannot read old metadata: %s.",
1585                     strerror(errno));
1586                 goto out;
1587         }
1588
1589         /* Check if this sector contains geli metadata. */
1590         error = eli_metadata_decode(sector, &md);
1591         switch (error) {
1592         case 0:
1593                 break;
1594         case EOPNOTSUPP:
1595                 gctl_error(req,
1596                     "Provider's %s metadata version %u is too new.\n"
1597                     "geli: The highest supported version is %u.",
1598                     prov, (unsigned int)md.md_version, G_ELI_VERSION);
1599                 goto out;
1600         case EINVAL:
1601                 gctl_error(req, "Inconsistent provider's %s metadata.", prov);
1602                 goto out;
1603         default:
1604                 gctl_error(req,
1605                     "Unexpected error while decoding provider's %s metadata: %s.",
1606                     prov, strerror(error));
1607                 goto out;
1608         }
1609
1610         /*
1611          * If the old metadata doesn't have a correct provider size, refuse
1612          * to resize.
1613          */
1614         if (md.md_provsize != (uint64_t)oldsize) {
1615                 gctl_error(req, "Provider size mismatch at oldsize.");
1616                 goto out;
1617         }
1618
1619         /*
1620          * Update the old metadata with the current provider size and write
1621          * it back to the correct place on the provider.
1622          */
1623         md.md_provsize = mediasize;
1624         /* Write metadata to the provider. */
1625         (void)eli_metadata_store(req, prov, &md);
1626         /* Now trash the old metadata. */
1627         (void)eli_trash_metadata(req, prov, provfd, oldsize - secsize);
1628 out:
1629         if (provfd != -1)
1630                 (void)g_close(provfd);
1631         if (sector != NULL) {
1632                 bzero(sector, secsize);
1633                 free(sector);
1634         }
1635 }
1636
1637 static void
1638 eli_version(struct gctl_req *req)
1639 {
1640         struct g_eli_metadata md;
1641         const char *name;
1642         unsigned int version;
1643         int error, i, nargs;
1644
1645         nargs = gctl_get_int(req, "nargs");
1646
1647         if (nargs == 0) {
1648                 unsigned int kernver;
1649                 ssize_t size;
1650
1651                 size = sizeof(kernver);
1652                 if (sysctlbyname("kern.geom.eli.version", &kernver, &size,
1653                     NULL, 0) == -1) {
1654                         warn("Unable to obtain GELI kernel version");
1655                 } else {
1656                         printf("kernel: %u\n", kernver);
1657                 }
1658                 printf("userland: %u\n", G_ELI_VERSION);
1659                 return;
1660         }
1661
1662         for (i = 0; i < nargs; i++) {
1663                 name = gctl_get_ascii(req, "arg%d", i);
1664                 error = g_metadata_read(name, (unsigned char *)&md,
1665                     sizeof(md), G_ELI_MAGIC);
1666                 if (error != 0) {
1667                         warn("%s: Unable to read metadata: %s.", name,
1668                             strerror(error));
1669                         gctl_error(req, "Not fully done.");
1670                         continue;
1671                 }
1672                 version = le32dec(&md.md_version);
1673                 printf("%s: %u\n", name, version);
1674         }
1675 }
1676
1677 static void
1678 eli_clear(struct gctl_req *req)
1679 {
1680         const char *name;
1681         int error, i, nargs;
1682
1683         nargs = gctl_get_int(req, "nargs");
1684         if (nargs < 1) {
1685                 gctl_error(req, "Too few arguments.");
1686                 return;
1687         }
1688
1689         for (i = 0; i < nargs; i++) {
1690                 name = gctl_get_ascii(req, "arg%d", i);
1691                 error = g_metadata_clear(name, G_ELI_MAGIC);
1692                 if (error != 0) {
1693                         fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1694                             name, strerror(error));
1695                         gctl_error(req, "Not fully done.");
1696                         continue;
1697                 }
1698                 if (verbose)
1699                         printf("Metadata cleared on %s.\n", name);
1700         }
1701 }
1702
1703 static void
1704 eli_dump(struct gctl_req *req)
1705 {
1706         struct g_eli_metadata md;
1707         const char *name;
1708         int i, nargs;
1709
1710         nargs = gctl_get_int(req, "nargs");
1711         if (nargs < 1) {
1712                 gctl_error(req, "Too few arguments.");
1713                 return;
1714         }
1715
1716         for (i = 0; i < nargs; i++) {
1717                 name = gctl_get_ascii(req, "arg%d", i);
1718                 if (eli_metadata_read(NULL, name, &md) == -1) {
1719                         gctl_error(req, "Not fully done.");
1720                         continue;
1721                 }
1722                 printf("Metadata on %s:\n", name);
1723                 eli_metadata_dump(&md);
1724                 printf("\n");
1725         }
1726 }