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