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