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