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