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: stable/11/sbin/geom/class/eli/geom_eli.c 348588 2019-06-03 21:04:23Z jhb $"); 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 60uint32_t lib_version = G_LIB_VERSION; 61uint32_t version = G_ELI_VERSION; 62 63#define GELI_BACKUP_DIR "/var/backups/" 64#define GELI_ENC_ALGO "aes" 65 66static void eli_main(struct gctl_req *req, unsigned flags); 67static void eli_init(struct gctl_req *req); 68static void eli_attach(struct gctl_req *req); 69static void eli_configure(struct gctl_req *req); 70static void eli_setkey(struct gctl_req *req); 71static void eli_delkey(struct gctl_req *req); 72static void eli_resume(struct gctl_req *req); 73static void eli_kill(struct gctl_req *req); 74static void eli_backup(struct gctl_req *req); 75static void eli_restore(struct gctl_req *req); 76static void eli_resize(struct gctl_req *req); 77static void eli_version(struct gctl_req *req); 78static void eli_clear(struct gctl_req *req); 79static void eli_dump(struct gctl_req *req); 80 81static 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 */ 106struct 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 276static int verbose = 0; 277 278#define BUFSIZE 1024 279 280static int 281eli_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 301static void 302eli_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 347static bool 348eli_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 361static int 362eli_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 434static int 435eli_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 477static int 478eli_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 547static unsigned char * 548eli_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 576static int 577eli_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 632static int 633eli_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 673static void 674eli_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 if (md.md_flags & G_ELI_FLAG_AUTH) { 785 switch (md.md_aalgo) { 786 case CRYPTO_MD5_HMAC: 787 gctl_error(req, 788 "The %s authentication algorithm is deprecated.", 789 g_eli_algo2str(md.md_aalgo)); 790 return; 791 } 792 } 793 switch (md.md_ealgo) { 794 case CRYPTO_3DES_CBC: 795 case CRYPTO_BLF_CBC: 796 gctl_error(req, "The %s encryption algorithm is deprecated.", 797 g_eli_algo2str(md.md_ealgo)); 798 return; 799 } 800 val = gctl_get_intmax(req, "keylen"); 801 md.md_keylen = val; 802 md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); 803 if (md.md_keylen == 0) { 804 gctl_error(req, "Invalid key length."); 805 return; 806 } 807 md.md_provsize = mediasize; 808 809 val = gctl_get_intmax(req, "iterations"); 810 if (val != -1) { 811 int nonewpassphrase; 812 813 /* 814 * Don't allow to set iterations when there will be no 815 * passphrase. 816 */ 817 nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 818 if (nonewpassphrase) { 819 gctl_error(req, 820 "Options -i and -P are mutually exclusive."); 821 return; 822 } 823 } 824 md.md_iterations = val; 825 826 val = gctl_get_intmax(req, "sectorsize"); 827 if (val == 0) 828 md.md_sectorsize = secsize; 829 else { 830 if (val < 0 || (val % secsize) != 0 || !powerof2(val)) { 831 gctl_error(req, "Invalid sector size."); 832 return; 833 } 834 if (val > sysconf(_SC_PAGE_SIZE)) { 835 fprintf(stderr, 836 "warning: Using sectorsize bigger than the page size!\n"); 837 } 838 md.md_sectorsize = val; 839 } 840 841 md.md_keys = 0x01; 842 arc4random_buf(md.md_salt, sizeof(md.md_salt)); 843 arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys)); 844 845 /* Generate user key. */ 846 if (eli_genkey(req, &md, key, true) == NULL) { 847 bzero(key, sizeof(key)); 848 bzero(&md, sizeof(md)); 849 return; 850 } 851 852 /* Encrypt the first and the only Master Key. */ 853 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); 854 bzero(key, sizeof(key)); 855 if (error != 0) { 856 bzero(&md, sizeof(md)); 857 gctl_error(req, "Cannot encrypt Master Key: %s.", 858 strerror(error)); 859 return; 860 } 861 862 eli_metadata_encode(&md, sector); 863 bzero(&md, sizeof(md)); 864 error = g_metadata_store(prov, sector, sizeof(sector)); 865 bzero(sector, sizeof(sector)); 866 if (error != 0) { 867 gctl_error(req, "Cannot store metadata on %s: %s.", prov, 868 strerror(error)); 869 return; 870 } 871 if (verbose) 872 printf("Metadata value stored on %s.\n", prov); 873 /* Backup metadata to a file. */ 874 str = gctl_get_ascii(req, "backupfile"); 875 if (str[0] != '\0') { 876 /* Backupfile given be the user, just copy it. */ 877 strlcpy(backfile, str, sizeof(backfile)); 878 } else { 879 /* Generate file name automatically. */ 880 const char *p = prov; 881 unsigned int i; 882 883 if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 884 p += sizeof(_PATH_DEV) - 1; 885 snprintf(backfile, sizeof(backfile), "%s%s.eli", 886 GELI_BACKUP_DIR, p); 887 /* Replace all / with _. */ 888 for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) { 889 if (backfile[i] == '/') 890 backfile[i] = '_'; 891 } 892 } 893 if (strcmp(backfile, "none") != 0 && 894 eli_backup_create(req, prov, backfile) == 0) { 895 printf("\nMetadata backup can be found in %s and\n", backfile); 896 printf("can be restored with the following command:\n"); 897 printf("\n\t# geli restore %s %s\n\n", backfile, prov); 898 } 899} 900 901static void 902eli_attach(struct gctl_req *req) 903{ 904 struct g_eli_metadata md; 905 unsigned char key[G_ELI_USERKEYLEN]; 906 const char *prov; 907 off_t mediasize; 908 int nargs; 909 910 nargs = gctl_get_int(req, "nargs"); 911 if (nargs != 1) { 912 gctl_error(req, "Invalid number of arguments."); 913 return; 914 } 915 prov = gctl_get_ascii(req, "arg0"); 916 917 if (eli_metadata_read(req, prov, &md) == -1) 918 return; 919 920 mediasize = g_get_mediasize(prov); 921 if (md.md_provsize != (uint64_t)mediasize) { 922 gctl_error(req, "Provider size mismatch."); 923 return; 924 } 925 926 if (eli_genkey(req, &md, key, false) == NULL) { 927 bzero(key, sizeof(key)); 928 return; 929 } 930 931 gctl_ro_param(req, "key", sizeof(key), key); 932 if (gctl_issue(req) == NULL) { 933 if (verbose) 934 printf("Attached to %s.\n", prov); 935 } 936 bzero(key, sizeof(key)); 937} 938 939static void 940eli_configure_detached(struct gctl_req *req, const char *prov, int boot, 941 int geliboot, int displaypass, int trim) 942{ 943 struct g_eli_metadata md; 944 bool changed = 0; 945 946 if (eli_metadata_read(req, prov, &md) == -1) 947 return; 948 949 if (boot == 1 && (md.md_flags & G_ELI_FLAG_BOOT)) { 950 if (verbose) 951 printf("BOOT flag already configured for %s.\n", prov); 952 } else if (boot == 0 && !(md.md_flags & G_ELI_FLAG_BOOT)) { 953 if (verbose) 954 printf("BOOT flag not configured for %s.\n", prov); 955 } else if (boot >= 0) { 956 if (boot) 957 md.md_flags |= G_ELI_FLAG_BOOT; 958 else 959 md.md_flags &= ~G_ELI_FLAG_BOOT; 960 changed = 1; 961 } 962 963 if (geliboot == 1 && (md.md_flags & G_ELI_FLAG_GELIBOOT)) { 964 if (verbose) 965 printf("GELIBOOT flag already configured for %s.\n", prov); 966 } else if (geliboot == 0 && !(md.md_flags & G_ELI_FLAG_GELIBOOT)) { 967 if (verbose) 968 printf("GELIBOOT flag not configured for %s.\n", prov); 969 } else if (geliboot >= 0) { 970 if (geliboot) 971 md.md_flags |= G_ELI_FLAG_GELIBOOT; 972 else 973 md.md_flags &= ~G_ELI_FLAG_GELIBOOT; 974 changed = 1; 975 } 976 977 if (displaypass == 1 && (md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) { 978 if (verbose) 979 printf("GELIDISPLAYPASS flag already configured for %s.\n", prov); 980 } else if (displaypass == 0 && 981 !(md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) { 982 if (verbose) 983 printf("GELIDISPLAYPASS flag not configured for %s.\n", prov); 984 } else if (displaypass >= 0) { 985 if (displaypass) 986 md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS; 987 else 988 md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS; 989 changed = 1; 990 } 991 992 if (trim == 0 && (md.md_flags & G_ELI_FLAG_NODELETE)) { 993 if (verbose) 994 printf("TRIM disable flag already configured for %s.\n", prov); 995 } else if (trim == 1 && !(md.md_flags & G_ELI_FLAG_NODELETE)) { 996 if (verbose) 997 printf("TRIM disable flag not configured for %s.\n", prov); 998 } else if (trim >= 0) { 999 if (trim) 1000 md.md_flags &= ~G_ELI_FLAG_NODELETE; 1001 else 1002 md.md_flags |= G_ELI_FLAG_NODELETE; 1003 changed = 1; 1004 } 1005 1006 if (changed) 1007 eli_metadata_store(req, prov, &md); 1008 bzero(&md, sizeof(md)); 1009} 1010 1011static void 1012eli_configure(struct gctl_req *req) 1013{ 1014 const char *prov; 1015 bool boot, noboot, geliboot, nogeliboot, displaypass, nodisplaypass; 1016 bool trim, notrim; 1017 int doboot, dogeliboot, dodisplaypass, dotrim; 1018 int i, nargs; 1019 1020 nargs = gctl_get_int(req, "nargs"); 1021 if (nargs == 0) { 1022 gctl_error(req, "Too few arguments."); 1023 return; 1024 } 1025 1026 boot = gctl_get_int(req, "boot"); 1027 noboot = gctl_get_int(req, "noboot"); 1028 geliboot = gctl_get_int(req, "geliboot"); 1029 nogeliboot = gctl_get_int(req, "nogeliboot"); 1030 displaypass = gctl_get_int(req, "displaypass"); 1031 nodisplaypass = gctl_get_int(req, "nodisplaypass"); 1032 trim = gctl_get_int(req, "trim"); 1033 notrim = gctl_get_int(req, "notrim"); 1034 1035 doboot = -1; 1036 if (boot && noboot) { 1037 gctl_error(req, "Options -b and -B are mutually exclusive."); 1038 return; 1039 } 1040 if (boot) 1041 doboot = 1; 1042 else if (noboot) 1043 doboot = 0; 1044 1045 dogeliboot = -1; 1046 if (geliboot && nogeliboot) { 1047 gctl_error(req, "Options -g and -G are mutually exclusive."); 1048 return; 1049 } 1050 if (geliboot) 1051 dogeliboot = 1; 1052 else if (nogeliboot) 1053 dogeliboot = 0; 1054 1055 dodisplaypass = -1; 1056 if (displaypass && nodisplaypass) { 1057 gctl_error(req, "Options -d and -D are mutually exclusive."); 1058 return; 1059 } 1060 if (displaypass) 1061 dodisplaypass = 1; 1062 else if (nodisplaypass) 1063 dodisplaypass = 0; 1064 1065 dotrim = -1; 1066 if (trim && notrim) { 1067 gctl_error(req, "Options -t and -T are mutually exclusive."); 1068 return; 1069 } 1070 if (trim) 1071 dotrim = 1; 1072 else if (notrim) 1073 dotrim = 0; 1074 1075 if (doboot == -1 && dogeliboot == -1 && dodisplaypass == -1 && 1076 dotrim == -1) { 1077 gctl_error(req, "No option given."); 1078 return; 1079 } 1080 1081 /* First attached providers. */ 1082 gctl_issue(req); 1083 /* Now the rest. */ 1084 for (i = 0; i < nargs; i++) { 1085 prov = gctl_get_ascii(req, "arg%d", i); 1086 if (!eli_is_attached(prov)) { 1087 eli_configure_detached(req, prov, doboot, dogeliboot, 1088 dodisplaypass, dotrim); 1089 } 1090 } 1091} 1092 1093static void 1094eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 1095{ 1096 unsigned char key[G_ELI_USERKEYLEN]; 1097 intmax_t val, old = 0; 1098 int error; 1099 1100 val = gctl_get_intmax(req, "iterations"); 1101 /* Check if iterations number should be changed. */ 1102 if (val != -1) 1103 md->md_iterations = val; 1104 else 1105 old = md->md_iterations; 1106 1107 /* Generate key for Master Key encryption. */ 1108 if (eli_genkey(req, md, key, true) == NULL) { 1109 bzero(key, sizeof(key)); 1110 return; 1111 } 1112 /* 1113 * If number of iterations has changed, but wasn't given as a 1114 * command-line argument, update the request. 1115 */ 1116 if (val == -1 && md->md_iterations != old) { 1117 error = gctl_change_param(req, "iterations", sizeof(intmax_t), 1118 &md->md_iterations); 1119 assert(error == 0); 1120 } 1121 1122 gctl_ro_param(req, "key", sizeof(key), key); 1123 gctl_issue(req); 1124 bzero(key, sizeof(key)); 1125} 1126 1127static void 1128eli_setkey_detached(struct gctl_req *req, const char *prov, 1129 struct g_eli_metadata *md) 1130{ 1131 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 1132 unsigned char *mkeydst; 1133 unsigned int nkey; 1134 intmax_t val; 1135 int error; 1136 1137 if (md->md_keys == 0) { 1138 gctl_error(req, "No valid keys on %s.", prov); 1139 return; 1140 } 1141 1142 /* Generate key for Master Key decryption. */ 1143 if (eli_genkey(req, md, key, false) == NULL) { 1144 bzero(key, sizeof(key)); 1145 return; 1146 } 1147 1148 /* Decrypt Master Key. */ 1149 error = g_eli_mkey_decrypt_any(md, key, mkey, &nkey); 1150 bzero(key, sizeof(key)); 1151 if (error != 0) { 1152 bzero(md, sizeof(*md)); 1153 if (error == -1) 1154 gctl_error(req, "Wrong key for %s.", prov); 1155 else /* if (error > 0) */ { 1156 gctl_error(req, "Cannot decrypt Master Key: %s.", 1157 strerror(error)); 1158 } 1159 return; 1160 } 1161 if (verbose) 1162 printf("Decrypted Master Key %u.\n", nkey); 1163 1164 val = gctl_get_intmax(req, "keyno"); 1165 if (val != -1) 1166 nkey = val; 1167#if 0 1168 else 1169 ; /* Use the key number which was found during decryption. */ 1170#endif 1171 if (nkey >= G_ELI_MAXMKEYS) { 1172 gctl_error(req, "Invalid '%s' argument.", "keyno"); 1173 return; 1174 } 1175 1176 val = gctl_get_intmax(req, "iterations"); 1177 /* Check if iterations number should and can be changed. */ 1178 if (val != -1 && md->md_iterations == -1) { 1179 md->md_iterations = val; 1180 } else if (val != -1 && val != md->md_iterations) { 1181 if (bitcount32(md->md_keys) != 1) { 1182 gctl_error(req, "To be able to use '-i' option, only " 1183 "one key can be defined."); 1184 return; 1185 } 1186 if (md->md_keys != (1 << nkey)) { 1187 gctl_error(req, "Only already defined key can be " 1188 "changed when '-i' option is used."); 1189 return; 1190 } 1191 md->md_iterations = val; 1192 } 1193 1194 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 1195 md->md_keys |= (1 << nkey); 1196 1197 bcopy(mkey, mkeydst, sizeof(mkey)); 1198 bzero(mkey, sizeof(mkey)); 1199 1200 /* Generate key for Master Key encryption. */ 1201 if (eli_genkey(req, md, key, true) == NULL) { 1202 bzero(key, sizeof(key)); 1203 bzero(md, sizeof(*md)); 1204 return; 1205 } 1206 1207 /* Encrypt the Master-Key with the new key. */ 1208 error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); 1209 bzero(key, sizeof(key)); 1210 if (error != 0) { 1211 bzero(md, sizeof(*md)); 1212 gctl_error(req, "Cannot encrypt Master Key: %s.", 1213 strerror(error)); 1214 return; 1215 } 1216 1217 /* Store metadata with fresh key. */ 1218 eli_metadata_store(req, prov, md); 1219 bzero(md, sizeof(*md)); 1220} 1221 1222static void 1223eli_setkey(struct gctl_req *req) 1224{ 1225 struct g_eli_metadata md; 1226 const char *prov; 1227 int nargs; 1228 1229 nargs = gctl_get_int(req, "nargs"); 1230 if (nargs != 1) { 1231 gctl_error(req, "Invalid number of arguments."); 1232 return; 1233 } 1234 prov = gctl_get_ascii(req, "arg0"); 1235 1236 if (eli_metadata_read(req, prov, &md) == -1) 1237 return; 1238 1239 if (eli_is_attached(prov)) 1240 eli_setkey_attached(req, &md); 1241 else 1242 eli_setkey_detached(req, prov, &md); 1243 1244 if (req->error == NULL || req->error[0] == '\0') { 1245 printf("Note, that the master key encrypted with old keys " 1246 "and/or passphrase may still exists in a metadata backup " 1247 "file.\n"); 1248 } 1249} 1250 1251static void 1252eli_delkey_attached(struct gctl_req *req, const char *prov __unused) 1253{ 1254 1255 gctl_issue(req); 1256} 1257 1258static void 1259eli_delkey_detached(struct gctl_req *req, const char *prov) 1260{ 1261 struct g_eli_metadata md; 1262 unsigned char *mkeydst; 1263 unsigned int nkey; 1264 intmax_t val; 1265 bool all, force; 1266 1267 if (eli_metadata_read(req, prov, &md) == -1) 1268 return; 1269 1270 all = gctl_get_int(req, "all"); 1271 if (all) 1272 arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys)); 1273 else { 1274 force = gctl_get_int(req, "force"); 1275 val = gctl_get_intmax(req, "keyno"); 1276 if (val == -1) { 1277 gctl_error(req, "Key number has to be specified."); 1278 return; 1279 } 1280 nkey = val; 1281 if (nkey >= G_ELI_MAXMKEYS) { 1282 gctl_error(req, "Invalid '%s' argument.", "keyno"); 1283 return; 1284 } 1285 if (!(md.md_keys & (1 << nkey)) && !force) { 1286 gctl_error(req, "Master Key %u is not set.", nkey); 1287 return; 1288 } 1289 md.md_keys &= ~(1 << nkey); 1290 if (md.md_keys == 0 && !force) { 1291 gctl_error(req, "This is the last Master Key. Use '-f' " 1292 "option if you really want to remove it."); 1293 return; 1294 } 1295 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 1296 arc4random_buf(mkeydst, G_ELI_MKEYLEN); 1297 } 1298 1299 eli_metadata_store(req, prov, &md); 1300 bzero(&md, sizeof(md)); 1301} 1302 1303static void 1304eli_delkey(struct gctl_req *req) 1305{ 1306 const char *prov; 1307 int nargs; 1308 1309 nargs = gctl_get_int(req, "nargs"); 1310 if (nargs != 1) { 1311 gctl_error(req, "Invalid number of arguments."); 1312 return; 1313 } 1314 prov = gctl_get_ascii(req, "arg0"); 1315 1316 if (eli_is_attached(prov)) 1317 eli_delkey_attached(req, prov); 1318 else 1319 eli_delkey_detached(req, prov); 1320} 1321 1322static void 1323eli_resume(struct gctl_req *req) 1324{ 1325 struct g_eli_metadata md; 1326 unsigned char key[G_ELI_USERKEYLEN]; 1327 const char *prov; 1328 off_t mediasize; 1329 int nargs; 1330 1331 nargs = gctl_get_int(req, "nargs"); 1332 if (nargs != 1) { 1333 gctl_error(req, "Invalid number of arguments."); 1334 return; 1335 } 1336 prov = gctl_get_ascii(req, "arg0"); 1337 1338 if (eli_metadata_read(req, prov, &md) == -1) 1339 return; 1340 1341 mediasize = g_get_mediasize(prov); 1342 if (md.md_provsize != (uint64_t)mediasize) { 1343 gctl_error(req, "Provider size mismatch."); 1344 return; 1345 } 1346 1347 if (eli_genkey(req, &md, key, false) == NULL) { 1348 bzero(key, sizeof(key)); 1349 return; 1350 } 1351 1352 gctl_ro_param(req, "key", sizeof(key), key); 1353 if (gctl_issue(req) == NULL) { 1354 if (verbose) 1355 printf("Resumed %s.\n", prov); 1356 } 1357 bzero(key, sizeof(key)); 1358} 1359 1360static int 1361eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset) 1362{ 1363 unsigned int overwrites; 1364 unsigned char *sector; 1365 ssize_t size; 1366 int error; 1367 1368 size = sizeof(overwrites); 1369 if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size, 1370 NULL, 0) == -1 || overwrites == 0) { 1371 overwrites = G_ELI_OVERWRITES; 1372 } 1373 1374 size = g_sectorsize(fd); 1375 if (size <= 0) { 1376 gctl_error(req, "Cannot obtain provider sector size %s: %s.", 1377 prov, strerror(errno)); 1378 return (-1); 1379 } 1380 sector = malloc(size); 1381 if (sector == NULL) { 1382 gctl_error(req, "Cannot allocate %zd bytes of memory.", size); 1383 return (-1); 1384 } 1385 1386 error = 0; 1387 do { 1388 arc4random_buf(sector, size); 1389 if (pwrite(fd, sector, size, offset) != size) { 1390 if (error == 0) 1391 error = errno; 1392 } 1393 (void)g_flush(fd); 1394 } while (--overwrites > 0); 1395 free(sector); 1396 if (error != 0) { 1397 gctl_error(req, "Cannot trash metadata on provider %s: %s.", 1398 prov, strerror(error)); 1399 return (-1); 1400 } 1401 return (0); 1402} 1403 1404static void 1405eli_kill_detached(struct gctl_req *req, const char *prov) 1406{ 1407 off_t offset; 1408 int fd; 1409 1410 /* 1411 * NOTE: Maybe we should verify if this is geli provider first, 1412 * but 'kill' command is quite critical so better don't waste 1413 * the time. 1414 */ 1415#if 0 1416 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 1417 G_ELI_MAGIC); 1418 if (error != 0) { 1419 gctl_error(req, "Cannot read metadata from %s: %s.", prov, 1420 strerror(error)); 1421 return; 1422 } 1423#endif 1424 1425 fd = g_open(prov, 1); 1426 if (fd == -1) { 1427 gctl_error(req, "Cannot open provider %s: %s.", prov, 1428 strerror(errno)); 1429 return; 1430 } 1431 offset = g_mediasize(fd) - g_sectorsize(fd); 1432 if (offset <= 0) { 1433 gctl_error(req, 1434 "Cannot obtain media size or sector size for provider %s: %s.", 1435 prov, strerror(errno)); 1436 (void)g_close(fd); 1437 return; 1438 } 1439 (void)eli_trash_metadata(req, prov, fd, offset); 1440 (void)g_close(fd); 1441} 1442 1443static void 1444eli_kill(struct gctl_req *req) 1445{ 1446 const char *prov; 1447 int i, nargs, all; 1448 1449 nargs = gctl_get_int(req, "nargs"); 1450 all = gctl_get_int(req, "all"); 1451 if (!all && nargs == 0) { 1452 gctl_error(req, "Too few arguments."); 1453 return; 1454 } 1455 /* 1456 * How '-a' option combine with a list of providers: 1457 * Delete Master Keys from all attached providers: 1458 * geli kill -a 1459 * Delete Master Keys from all attached providers and from 1460 * detached da0 and da1: 1461 * geli kill -a da0 da1 1462 * Delete Master Keys from (attached or detached) da0 and da1: 1463 * geli kill da0 da1 1464 */ 1465 1466 /* First detached providers. */ 1467 for (i = 0; i < nargs; i++) { 1468 prov = gctl_get_ascii(req, "arg%d", i); 1469 if (!eli_is_attached(prov)) 1470 eli_kill_detached(req, prov); 1471 } 1472 /* Now attached providers. */ 1473 gctl_issue(req); 1474} 1475 1476static int 1477eli_backup_create(struct gctl_req *req, const char *prov, const char *file) 1478{ 1479 unsigned char *sector; 1480 ssize_t secsize; 1481 int error, filefd, ret; 1482 1483 ret = -1; 1484 filefd = -1; 1485 sector = NULL; 1486 secsize = 0; 1487 1488 secsize = g_get_sectorsize(prov); 1489 if (secsize == 0) { 1490 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1491 strerror(errno)); 1492 goto out; 1493 } 1494 sector = malloc(secsize); 1495 if (sector == NULL) { 1496 gctl_error(req, "Cannot allocate memory."); 1497 goto out; 1498 } 1499 /* Read metadata from the provider. */ 1500 error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC); 1501 if (error != 0) { 1502 gctl_error(req, "Unable to read metadata from %s: %s.", prov, 1503 strerror(error)); 1504 goto out; 1505 } 1506 1507 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1508 if (filefd == -1) { 1509 gctl_error(req, "Unable to open %s: %s.", file, 1510 strerror(errno)); 1511 goto out; 1512 } 1513 /* Write metadata to the destination file. */ 1514 if (write(filefd, sector, secsize) != secsize) { 1515 gctl_error(req, "Unable to write to %s: %s.", file, 1516 strerror(errno)); 1517 (void)close(filefd); 1518 (void)unlink(file); 1519 goto out; 1520 } 1521 (void)fsync(filefd); 1522 (void)close(filefd); 1523 /* Success. */ 1524 ret = 0; 1525out: 1526 if (sector != NULL) { 1527 bzero(sector, secsize); 1528 free(sector); 1529 } 1530 return (ret); 1531} 1532 1533static void 1534eli_backup(struct gctl_req *req) 1535{ 1536 const char *file, *prov; 1537 int nargs; 1538 1539 nargs = gctl_get_int(req, "nargs"); 1540 if (nargs != 2) { 1541 gctl_error(req, "Invalid number of arguments."); 1542 return; 1543 } 1544 prov = gctl_get_ascii(req, "arg0"); 1545 file = gctl_get_ascii(req, "arg1"); 1546 1547 eli_backup_create(req, prov, file); 1548} 1549 1550static void 1551eli_restore(struct gctl_req *req) 1552{ 1553 struct g_eli_metadata md; 1554 const char *file, *prov; 1555 off_t mediasize; 1556 int nargs; 1557 1558 nargs = gctl_get_int(req, "nargs"); 1559 if (nargs != 2) { 1560 gctl_error(req, "Invalid number of arguments."); 1561 return; 1562 } 1563 file = gctl_get_ascii(req, "arg0"); 1564 prov = gctl_get_ascii(req, "arg1"); 1565 1566 /* Read metadata from the backup file. */ 1567 if (eli_metadata_read(req, file, &md) == -1) 1568 return; 1569 /* Obtain provider's mediasize. */ 1570 mediasize = g_get_mediasize(prov); 1571 if (mediasize == 0) { 1572 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1573 strerror(errno)); 1574 return; 1575 } 1576 /* Check if the provider size has changed since we did the backup. */ 1577 if (md.md_provsize != (uint64_t)mediasize) { 1578 if (gctl_get_int(req, "force")) { 1579 md.md_provsize = mediasize; 1580 } else { 1581 gctl_error(req, "Provider size mismatch: " 1582 "wrong backup file?"); 1583 return; 1584 } 1585 } 1586 /* Write metadata to the provider. */ 1587 (void)eli_metadata_store(req, prov, &md); 1588} 1589 1590static void 1591eli_resize(struct gctl_req *req) 1592{ 1593 struct g_eli_metadata md; 1594 const char *prov; 1595 unsigned char *sector; 1596 ssize_t secsize; 1597 off_t mediasize, oldsize; 1598 int error, nargs, provfd; 1599 1600 nargs = gctl_get_int(req, "nargs"); 1601 if (nargs != 1) { 1602 gctl_error(req, "Invalid number of arguments."); 1603 return; 1604 } 1605 prov = gctl_get_ascii(req, "arg0"); 1606 1607 provfd = -1; 1608 sector = NULL; 1609 secsize = 0; 1610 1611 provfd = g_open(prov, 1); 1612 if (provfd == -1) { 1613 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1614 goto out; 1615 } 1616 1617 mediasize = g_mediasize(provfd); 1618 secsize = g_sectorsize(provfd); 1619 if (mediasize == -1 || secsize == -1) { 1620 gctl_error(req, "Cannot get information about %s: %s.", prov, 1621 strerror(errno)); 1622 goto out; 1623 } 1624 1625 sector = malloc(secsize); 1626 if (sector == NULL) { 1627 gctl_error(req, "Cannot allocate memory."); 1628 goto out; 1629 } 1630 1631 oldsize = gctl_get_intmax(req, "oldsize"); 1632 if (oldsize < 0 || oldsize > mediasize) { 1633 gctl_error(req, "Invalid oldsize: Out of range."); 1634 goto out; 1635 } 1636 if (oldsize == mediasize) { 1637 gctl_error(req, "Size hasn't changed."); 1638 goto out; 1639 } 1640 1641 /* Read metadata from the 'oldsize' offset. */ 1642 if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) { 1643 gctl_error(req, "Cannot read old metadata: %s.", 1644 strerror(errno)); 1645 goto out; 1646 } 1647 1648 /* Check if this sector contains geli metadata. */ 1649 error = eli_metadata_decode(sector, &md); 1650 switch (error) { 1651 case 0: 1652 break; 1653 case EOPNOTSUPP: 1654 gctl_error(req, 1655 "Provider's %s metadata version %u is too new.\n" 1656 "geli: The highest supported version is %u.", 1657 prov, (unsigned int)md.md_version, G_ELI_VERSION); 1658 goto out; 1659 case EINVAL: 1660 gctl_error(req, "Inconsistent provider's %s metadata.", prov); 1661 goto out; 1662 default: 1663 gctl_error(req, 1664 "Unexpected error while decoding provider's %s metadata: %s.", 1665 prov, strerror(error)); 1666 goto out; 1667 } 1668 1669 /* 1670 * If the old metadata doesn't have a correct provider size, refuse 1671 * to resize. 1672 */ 1673 if (md.md_provsize != (uint64_t)oldsize) { 1674 gctl_error(req, "Provider size mismatch at oldsize."); 1675 goto out; 1676 } 1677 1678 /* 1679 * Update the old metadata with the current provider size and write 1680 * it back to the correct place on the provider. 1681 */ 1682 md.md_provsize = mediasize; 1683 /* Write metadata to the provider. */ 1684 (void)eli_metadata_store(req, prov, &md); 1685 /* Now trash the old metadata. */ 1686 (void)eli_trash_metadata(req, prov, provfd, oldsize - secsize); 1687out: 1688 if (provfd != -1) 1689 (void)g_close(provfd); 1690 if (sector != NULL) { 1691 bzero(sector, secsize); 1692 free(sector); 1693 } 1694} 1695 1696static void 1697eli_version(struct gctl_req *req) 1698{ 1699 struct g_eli_metadata md; 1700 const char *name; 1701 unsigned int version; 1702 int error, i, nargs; 1703 1704 nargs = gctl_get_int(req, "nargs"); 1705 1706 if (nargs == 0) { 1707 unsigned int kernver; 1708 ssize_t size; 1709 1710 size = sizeof(kernver); 1711 if (sysctlbyname("kern.geom.eli.version", &kernver, &size, 1712 NULL, 0) == -1) { 1713 warn("Unable to obtain GELI kernel version"); 1714 } else { 1715 printf("kernel: %u\n", kernver); 1716 } 1717 printf("userland: %u\n", G_ELI_VERSION); 1718 return; 1719 } 1720 1721 for (i = 0; i < nargs; i++) { 1722 name = gctl_get_ascii(req, "arg%d", i); 1723 error = g_metadata_read(name, (unsigned char *)&md, 1724 sizeof(md), G_ELI_MAGIC); 1725 if (error != 0) { 1726 warn("%s: Unable to read metadata: %s.", name, 1727 strerror(error)); 1728 gctl_error(req, "Not fully done."); 1729 continue; 1730 } 1731 version = le32dec(&md.md_version); 1732 printf("%s: %u\n", name, version); 1733 } 1734} 1735 1736static void 1737eli_clear(struct gctl_req *req) 1738{ 1739 const char *name; 1740 int error, i, nargs; 1741 1742 nargs = gctl_get_int(req, "nargs"); 1743 if (nargs < 1) { 1744 gctl_error(req, "Too few arguments."); 1745 return; 1746 } 1747 1748 for (i = 0; i < nargs; i++) { 1749 name = gctl_get_ascii(req, "arg%d", i); 1750 error = g_metadata_clear(name, G_ELI_MAGIC); 1751 if (error != 0) { 1752 fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1753 name, strerror(error)); 1754 gctl_error(req, "Not fully done."); 1755 continue; 1756 } 1757 if (verbose) 1758 printf("Metadata cleared on %s.\n", name); 1759 } 1760} 1761 1762static void 1763eli_dump(struct gctl_req *req) 1764{ 1765 struct g_eli_metadata md; 1766 const char *name; 1767 int i, nargs; 1768 1769 nargs = gctl_get_int(req, "nargs"); 1770 if (nargs < 1) { 1771 gctl_error(req, "Too few arguments."); 1772 return; 1773 } 1774 1775 for (i = 0; i < nargs; i++) { 1776 name = gctl_get_ascii(req, "arg%d", i); 1777 if (eli_metadata_read(NULL, name, &md) == -1) { 1778 gctl_error(req, "Not fully done."); 1779 continue; 1780 } 1781 printf("Metadata on %s:\n", name); 1782 eli_metadata_dump(&md); 1783 printf("\n"); 1784 } 1785} 1786