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