geom_eli.c revision 166216
1139825Simp/*- 21541Srgrimes * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 31541Srgrimes * All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 141541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 151541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 181541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241541Srgrimes * SUCH DAMAGE. 251541Srgrimes */ 261541Srgrimes 271541Srgrimes#include <sys/cdefs.h> 281541Srgrimes__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 166216 2007-01-25 11:44:03Z pjd $"); 2914501Shsu 3050477Speter#include <stdio.h> 311541Srgrimes#include <stdint.h> 321541Srgrimes#include <stdlib.h> 331541Srgrimes#include <unistd.h> 341541Srgrimes#include <fcntl.h> 351541Srgrimes#include <readpassphrase.h> 3634924Sbde#include <string.h> 3765495Struckman#include <strings.h> 3876166Smarkm#include <libgeom.h> 3976166Smarkm#include <paths.h> 4076166Smarkm#include <errno.h> 4176166Smarkm#include <assert.h> 4234924Sbde 431541Srgrimes#include <sys/param.h> 441541Srgrimes#include <sys/mman.h> 451541Srgrimes#include <sys/resource.h> 46131437Sjhb#include <opencrypto/cryptodev.h> 47131437Sjhb#include <geom/eli/g_eli.h> 48131437Sjhb#include <geom/eli/pkcs5v2.h> 49131437Sjhb 50170305Sjeff#include "core/geom.h" 51131437Sjhb#include "misc/subr.h" 521541Srgrimes 531541Srgrimes 54170174Sjeffuint32_t lib_version = G_LIB_VERSION; 55131437Sjhbuint32_t version = G_ELI_VERSION; 56131437Sjhb 571541Srgrimesstatic char aalgo[] = "none"; 581541Srgrimesstatic char ealgo[] = "aes"; 59121636Sjhbstatic intmax_t keylen = 0; 60131437Sjhbstatic intmax_t keyno = -1; 61131437Sjhbstatic intmax_t iterations = -1; 62131437Sjhbstatic intmax_t sectorsize = 0; 63131437Sjhbstatic char keyfile[] = "", newkeyfile[] = ""; 64131437Sjhb 651541Srgrimesstatic void eli_main(struct gctl_req *req, unsigned flags); 661541Srgrimesstatic void eli_init(struct gctl_req *req); 67131437Sjhbstatic void eli_attach(struct gctl_req *req); 681541Srgrimesstatic void eli_configure(struct gctl_req *req); 691541Srgrimesstatic void eli_setkey(struct gctl_req *req); 70125525Sjhbstatic void eli_delkey(struct gctl_req *req); 71125525Sjhbstatic void eli_kill(struct gctl_req *req); 721541Srgrimesstatic void eli_backup(struct gctl_req *req); 731541Srgrimesstatic void eli_restore(struct gctl_req *req); 741541Srgrimesstatic void eli_clear(struct gctl_req *req); 75111163Stjrstatic void eli_dump(struct gctl_req *req); 761541Srgrimes 771541Srgrimes/* 781541Srgrimes * Available commands: 79125454Sjhb * 801541Srgrimes * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov 811541Srgrimes * label - alias for 'init' 82133125Srwatson * attach [-dprv] [-k keyfile] prov 8365495Struckman * detach [-fl] prov ... 84133125Srwatson * stop - alias for 'detach' 85133125Srwatson * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ... 86133125Srwatson * configure [-bB] prov ... 87177277Spjd * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov 88133125Srwatson * delkey [-afv] [-n keyno] prov 8965495Struckman * kill [-av] [prov ...] 9065495Struckman * backup [-v] prov file 91133125Srwatson * restore [-v] file prov 92177277Spjd * clear [-v] prov ... 93133125Srwatson * dump [-v] prov ... 94133125Srwatson */ 95133125Srwatsonstruct g_command class_commands[] = { 9665495Struckman { "init", G_FLAG_VERBOSE, eli_main, 9765495Struckman { 98125523Sjhb { 'a', "aalgo", aalgo, G_TYPE_STRING }, 99136152Sjhb { 'b', "boot", NULL, G_TYPE_BOOL }, 10083366Sjulian { 'e', "ealgo", ealgo, G_TYPE_STRING }, 10134924Sbde { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 102153489Sjhb { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 103153489Sjhb { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 104136152Sjhb { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 105136152Sjhb { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 106177277Spjd G_OPT_SENTINEL 107100591Sjdp }, 108132319Salfred "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" 10992719Salfred }, 110125495Sjhb { "label", G_FLAG_VERBOSE, eli_main, 111125495Sjhb { 112125495Sjhb { 'a', "aalgo", aalgo, G_TYPE_STRING }, 113125454Sjhb { 'b', "boot", NULL, G_TYPE_BOOL }, 114170174Sjeff { 'e', "ealgo", ealgo, G_TYPE_STRING }, 115125454Sjhb { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 1161541Srgrimes { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 117125454Sjhb { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 118125495Sjhb { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 119125495Sjhb { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 120136152Sjhb G_OPT_SENTINEL 121136152Sjhb }, 122170472Sattilio "- an alias for 'init'" 123170174Sjeff }, 124170472Sattilio { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 125170472Sattilio { 126170174Sjeff { 'd', "detach", NULL, G_TYPE_BOOL }, 12792719Salfred { 'k', "keyfile", keyfile, G_TYPE_STRING }, 12865495Struckman { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 12992719Salfred { 'r', "readonly", NULL, G_TYPE_BOOL }, 130125495Sjhb G_OPT_SENTINEL 131125495Sjhb }, 13292719Salfred "[-dprv] [-k keyfile] prov" 1334470Sbde }, 134125495Sjhb { "detach", 0, NULL, 135125495Sjhb { 136 { 'f', "force", NULL, G_TYPE_BOOL }, 137 { 'l', "last", NULL, G_TYPE_BOOL }, 138 G_OPT_SENTINEL 139 }, 140 "[-fl] prov ..." 141 }, 142 { "stop", 0, NULL, 143 { 144 { 'f', "force", NULL, G_TYPE_BOOL }, 145 { 'l', "last", NULL, G_TYPE_BOOL }, 146 G_OPT_SENTINEL 147 }, 148 "- an alias for 'detach'" 149 }, 150 { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 151 { 152 { 'a', "aalgo", aalgo, G_TYPE_STRING }, 153 { 'd', "detach", NULL, G_TYPE_BOOL }, 154 { 'e', "ealgo", ealgo, G_TYPE_STRING }, 155 { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 156 { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 157 G_OPT_SENTINEL 158 }, 159 "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..." 160 }, 161 { "configure", G_FLAG_VERBOSE, eli_main, 162 { 163 { 'b', "boot", NULL, G_TYPE_BOOL }, 164 { 'B', "noboot", NULL, G_TYPE_BOOL }, 165 G_OPT_SENTINEL 166 }, 167 "[-bB] prov ..." 168 }, 169 { "setkey", G_FLAG_VERBOSE, eli_main, 170 { 171 { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 172 { 'k', "keyfile", keyfile, G_TYPE_STRING }, 173 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 174 { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 175 { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 176 { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 177 G_OPT_SENTINEL 178 }, 179 "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov" 180 }, 181 { "delkey", G_FLAG_VERBOSE, eli_main, 182 { 183 { 'a', "all", NULL, G_TYPE_BOOL }, 184 { 'f', "force", NULL, G_TYPE_BOOL }, 185 { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 186 G_OPT_SENTINEL 187 }, 188 "[-afv] [-n keyno] prov" 189 }, 190 { "kill", G_FLAG_VERBOSE, eli_main, 191 { 192 { 'a', "all", NULL, G_TYPE_BOOL }, 193 G_OPT_SENTINEL 194 }, 195 "[-av] [prov ...]" 196 }, 197 { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 198 "[-v] prov file" 199 }, 200 { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 201 "[-v] file prov" 202 }, 203 { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 204 "[-v] prov ..." 205 }, 206 { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 207 "[-v] prov ..." 208 }, 209 G_CMD_SENTINEL 210}; 211 212static int verbose = 0; 213 214static int 215eli_protect(struct gctl_req *req) 216{ 217 struct rlimit rl; 218 219 /* Disable core dumps. */ 220 rl.rlim_cur = 0; 221 rl.rlim_max = 0; 222 if (setrlimit(RLIMIT_CORE, &rl) == -1) { 223 gctl_error(req, "Cannot disable core dumps: %s.", 224 strerror(errno)); 225 return (-1); 226 } 227 /* Disable swapping. */ 228 if (mlockall(MCL_FUTURE) == -1) { 229 gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 230 return (-1); 231 } 232 return (0); 233} 234 235static void 236eli_main(struct gctl_req *req, unsigned flags) 237{ 238 const char *name; 239 240 if (eli_protect(req) == -1) 241 return; 242 243 if ((flags & G_FLAG_VERBOSE) != 0) 244 verbose = 1; 245 246 name = gctl_get_ascii(req, "verb"); 247 if (name == NULL) { 248 gctl_error(req, "No '%s' argument.", "verb"); 249 return; 250 } 251 if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 252 eli_init(req); 253 else if (strcmp(name, "attach") == 0) 254 eli_attach(req); 255 else if (strcmp(name, "configure") == 0) 256 eli_configure(req); 257 else if (strcmp(name, "setkey") == 0) 258 eli_setkey(req); 259 else if (strcmp(name, "delkey") == 0) 260 eli_delkey(req); 261 else if (strcmp(name, "kill") == 0) 262 eli_kill(req); 263 else if (strcmp(name, "backup") == 0) 264 eli_backup(req); 265 else if (strcmp(name, "restore") == 0) 266 eli_restore(req); 267 else if (strcmp(name, "dump") == 0) 268 eli_dump(req); 269 else if (strcmp(name, "clear") == 0) 270 eli_clear(req); 271 else 272 gctl_error(req, "Unknown command: %s.", name); 273} 274 275static void 276arc4rand(unsigned char *buf, size_t size) 277{ 278 uint32_t *buf4; 279 size_t size4; 280 unsigned i; 281 282 buf4 = (uint32_t *)buf; 283 size4 = size / 4; 284 285 for (i = 0; i < size4; i++) 286 buf4[i] = arc4random(); 287 for (i *= 4; i < size; i++) 288 buf[i] = arc4random() % 0xff; 289} 290 291static int 292eli_is_attached(const char *prov) 293{ 294 char name[MAXPATHLEN]; 295 unsigned secsize; 296 297 /* 298 * Not the best way to do it, but the easiest. 299 * We try to open provider and check if it is a GEOM provider 300 * by asking about its sectorsize. 301 */ 302 snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 303 secsize = g_get_sectorsize(name); 304 if (secsize > 0) 305 return (1); 306 return (0); 307} 308 309static unsigned char * 310eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 311 int new) 312{ 313 struct hmac_ctx ctx; 314 const char *str; 315 int error, nopassphrase; 316 317 nopassphrase = 318 gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 319 320 g_eli_crypto_hmac_init(&ctx, NULL, 0); 321 322 str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile"); 323 if (str[0] == '\0' && nopassphrase) { 324 gctl_error(req, "No key components given."); 325 return (NULL); 326 } else if (str[0] != '\0') { 327 char buf[MAXPHYS]; 328 ssize_t done; 329 int fd; 330 331 if (strcmp(str, "-") == 0) 332 fd = STDIN_FILENO; 333 else { 334 fd = open(str, O_RDONLY); 335 if (fd == -1) { 336 gctl_error(req, "Cannot open keyfile %s: %s.", 337 str, strerror(errno)); 338 return (NULL); 339 } 340 } 341 while ((done = read(fd, buf, sizeof(buf))) > 0) 342 g_eli_crypto_hmac_update(&ctx, buf, done); 343 error = errno; 344 if (strcmp(str, "-") != 0) 345 close(fd); 346 bzero(buf, sizeof(buf)); 347 if (done == -1) { 348 gctl_error(req, "Cannot read keyfile %s: %s.", str, 349 strerror(error)); 350 return (NULL); 351 } 352 } 353 354 if (!nopassphrase) { 355 char buf1[BUFSIZ], buf2[BUFSIZ], *p; 356 357 if (!new && md->md_iterations == -1) { 358 gctl_error(req, "Missing -p flag."); 359 return (NULL); 360 } 361 for (;;) { 362 p = readpassphrase( 363 new ? "Enter new passphrase:" : "Enter passphrase:", 364 buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY); 365 if (p == NULL) { 366 bzero(buf1, sizeof(buf1)); 367 gctl_error(req, "Cannot read passphrase: %s.", 368 strerror(errno)); 369 return (NULL); 370 } 371 372 if (new) { 373 p = readpassphrase("Reenter new passphrase: ", 374 buf2, sizeof(buf2), 375 RPP_ECHO_OFF | RPP_REQUIRE_TTY); 376 if (p == NULL) { 377 bzero(buf1, sizeof(buf1)); 378 gctl_error(req, 379 "Cannot read passphrase: %s.", 380 strerror(errno)); 381 return (NULL); 382 } 383 384 if (strcmp(buf1, buf2) != 0) { 385 bzero(buf2, sizeof(buf2)); 386 fprintf(stderr, "They didn't match.\n"); 387 continue; 388 } 389 bzero(buf2, sizeof(buf2)); 390 } 391 break; 392 } 393 /* 394 * Field md_iterations equal to -1 means "choose some sane 395 * value for me". 396 */ 397 if (md->md_iterations == -1) { 398 assert(new); 399 if (verbose) 400 printf("Calculating number of iterations...\n"); 401 md->md_iterations = pkcs5v2_calculate(2000000); 402 assert(md->md_iterations > 0); 403 if (verbose) { 404 printf("Done, using %d iterations.\n", 405 md->md_iterations); 406 } 407 } 408 /* 409 * If md_iterations is equal to 0, user don't want PKCS#5v2. 410 */ 411 if (md->md_iterations == 0) { 412 g_eli_crypto_hmac_update(&ctx, md->md_salt, 413 sizeof(md->md_salt)); 414 g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1)); 415 } else /* if (md->md_iterations > 0) */ { 416 unsigned char dkey[G_ELI_USERKEYLEN]; 417 418 pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 419 sizeof(md->md_salt), buf1, md->md_iterations); 420 g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); 421 bzero(dkey, sizeof(dkey)); 422 } 423 bzero(buf1, sizeof(buf1)); 424 } 425 g_eli_crypto_hmac_final(&ctx, key, 0); 426 return (key); 427} 428 429static int 430eli_metadata_read(struct gctl_req *req, const char *prov, 431 struct g_eli_metadata *md) 432{ 433 unsigned char sector[sizeof(struct g_eli_metadata)]; 434 int error; 435 436 if (g_get_sectorsize(prov) == 0) { 437 int fd; 438 439 /* This is a file probably. */ 440 fd = open(prov, O_RDONLY); 441 if (fd == -1) { 442 gctl_error(req, "Cannot open %s: %s.", prov, 443 strerror(errno)); 444 return (-1); 445 } 446 if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 447 gctl_error(req, "Cannot read metadata from %s: %s.", 448 prov, strerror(errno)); 449 close(fd); 450 return (-1); 451 } 452 close(fd); 453 } else { 454 /* This is a GEOM provider. */ 455 error = g_metadata_read(prov, sector, sizeof(sector), 456 G_ELI_MAGIC); 457 if (error != 0) { 458 gctl_error(req, "Cannot read metadata from %s: %s.", 459 prov, strerror(error)); 460 return (-1); 461 } 462 } 463 if (eli_metadata_decode(sector, md) != 0) { 464 gctl_error(req, "MD5 hash mismatch for %s.", prov); 465 return (-1); 466 } 467 return (0); 468} 469 470static int 471eli_metadata_store(struct gctl_req *req, const char *prov, 472 struct g_eli_metadata *md) 473{ 474 unsigned char sector[sizeof(struct g_eli_metadata)]; 475 int error; 476 477 eli_metadata_encode(md, sector); 478 if (g_get_sectorsize(prov) == 0) { 479 int fd; 480 481 /* This is a file probably. */ 482 fd = open(prov, O_WRONLY | O_TRUNC); 483 if (fd == -1) { 484 gctl_error(req, "Cannot open %s: %s.", prov, 485 strerror(errno)); 486 bzero(sector, sizeof(sector)); 487 return (-1); 488 } 489 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 490 gctl_error(req, "Cannot write metadata to %s: %s.", 491 prov, strerror(errno)); 492 bzero(sector, sizeof(sector)); 493 close(fd); 494 return (-1); 495 } 496 close(fd); 497 } else { 498 /* This is a GEOM provider. */ 499 error = g_metadata_store(prov, sector, sizeof(sector)); 500 if (error != 0) { 501 gctl_error(req, "Cannot write metadata to %s: %s.", 502 prov, strerror(errno)); 503 bzero(sector, sizeof(sector)); 504 return (-1); 505 } 506 } 507 bzero(sector, sizeof(sector)); 508 return (0); 509} 510 511static void 512eli_init(struct gctl_req *req) 513{ 514 struct g_eli_metadata md; 515 unsigned char sector[sizeof(struct g_eli_metadata)]; 516 unsigned char key[G_ELI_USERKEYLEN]; 517 const char *str, *prov; 518 unsigned secsize; 519 off_t mediasize; 520 intmax_t val; 521 int error, nargs; 522 523 nargs = gctl_get_int(req, "nargs"); 524 if (nargs != 1) { 525 gctl_error(req, "Invalid number of arguments."); 526 return; 527 } 528 prov = gctl_get_ascii(req, "arg0"); 529 mediasize = g_get_mediasize(prov); 530 secsize = g_get_sectorsize(prov); 531 if (mediasize == 0 || secsize == 0) { 532 gctl_error(req, "Cannot get informations about %s: %s.", prov, 533 strerror(errno)); 534 return; 535 } 536 537 bzero(&md, sizeof(md)); 538 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 539 md.md_version = G_ELI_VERSION; 540 md.md_flags = 0; 541 if (gctl_get_int(req, "boot")) 542 md.md_flags |= G_ELI_FLAG_BOOT; 543 md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 544 str = gctl_get_ascii(req, "aalgo"); 545 if (strcmp(str, "none") != 0) { 546 md.md_aalgo = g_eli_str2aalgo(str); 547 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 548 md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 549 md.md_flags |= G_ELI_FLAG_AUTH; 550 } else { 551 /* 552 * For backward compatibility, check if the -a option 553 * was used to provide encryption algorithm. 554 */ 555 md.md_ealgo = g_eli_str2ealgo(str); 556 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 557 md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 558 gctl_error(req, 559 "Invalid authentication algorithm."); 560 return; 561 } else { 562 fprintf(stderr, "warning: The -e option, not " 563 "the -a option is now used to specify " 564 "encryption algorithm to use.\n"); 565 } 566 } 567 } 568 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 569 md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 570 str = gctl_get_ascii(req, "ealgo"); 571 md.md_ealgo = g_eli_str2ealgo(str); 572 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 573 md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 574 gctl_error(req, "Invalid encryption algorithm."); 575 return; 576 } 577 } 578 val = gctl_get_intmax(req, "keylen"); 579 md.md_keylen = val; 580 md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); 581 if (md.md_keylen == 0) { 582 gctl_error(req, "Invalid key length."); 583 return; 584 } 585 md.md_provsize = mediasize; 586 587 val = gctl_get_intmax(req, "iterations"); 588 if (val != -1) { 589 int nonewpassphrase; 590 591 /* 592 * Don't allow to set iterations when there will be no 593 * passphrase. 594 */ 595 nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 596 if (nonewpassphrase) { 597 gctl_error(req, 598 "Options -i and -P are mutually exclusive."); 599 return; 600 } 601 } 602 md.md_iterations = val; 603 604 val = gctl_get_intmax(req, "sectorsize"); 605 if (val == 0) 606 md.md_sectorsize = secsize; 607 else { 608 if (val < 0 || (val % secsize) != 0) { 609 gctl_error(req, "Invalid sector size."); 610 return; 611 } 612 md.md_sectorsize = val; 613 } 614 615 md.md_keys = 0x01; 616 arc4rand(md.md_salt, sizeof(md.md_salt)); 617 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 618 619 /* Generate user key. */ 620 if (eli_genkey(req, &md, key, 1) == NULL) { 621 bzero(key, sizeof(key)); 622 bzero(&md, sizeof(md)); 623 return; 624 } 625 626 /* Encrypt the first and the only Master Key. */ 627 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); 628 bzero(key, sizeof(key)); 629 if (error != 0) { 630 bzero(&md, sizeof(md)); 631 gctl_error(req, "Cannot encrypt Master Key: %s.", 632 strerror(error)); 633 return; 634 } 635 636 eli_metadata_encode(&md, sector); 637 bzero(&md, sizeof(md)); 638 error = g_metadata_store(prov, sector, sizeof(sector)); 639 bzero(sector, sizeof(sector)); 640 if (error != 0) { 641 gctl_error(req, "Cannot store metadata on %s: %s.", prov, 642 strerror(error)); 643 return; 644 } 645 if (verbose) 646 printf("Metadata value stored on %s.\n", prov); 647} 648 649static void 650eli_attach(struct gctl_req *req) 651{ 652 struct g_eli_metadata md; 653 unsigned char key[G_ELI_USERKEYLEN]; 654 const char *prov; 655 int nargs; 656 657 nargs = gctl_get_int(req, "nargs"); 658 if (nargs != 1) { 659 gctl_error(req, "Invalid number of arguments."); 660 return; 661 } 662 prov = gctl_get_ascii(req, "arg0"); 663 664 if (eli_metadata_read(req, prov, &md) == -1) 665 return; 666 667 if (eli_genkey(req, &md, key, 0) == NULL) { 668 bzero(key, sizeof(key)); 669 return; 670 } 671 672 gctl_ro_param(req, "key", sizeof(key), key); 673 if (gctl_issue(req) == NULL) { 674 if (verbose) 675 printf("Attched to %s.\n", prov); 676 } 677 bzero(key, sizeof(key)); 678} 679 680static void 681eli_configure_detached(struct gctl_req *req, const char *prov, int boot) 682{ 683 struct g_eli_metadata md; 684 685 if (eli_metadata_read(req, prov, &md) == -1) 686 return; 687 688 if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) { 689 if (verbose) 690 printf("BOOT flag already configured for %s.\n", prov); 691 } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) { 692 if (verbose) 693 printf("BOOT flag not configured for %s.\n", prov); 694 } else { 695 if (boot) 696 md.md_flags |= G_ELI_FLAG_BOOT; 697 else 698 md.md_flags &= ~G_ELI_FLAG_BOOT; 699 eli_metadata_store(req, prov, &md); 700 } 701 bzero(&md, sizeof(md)); 702} 703 704static void 705eli_configure(struct gctl_req *req) 706{ 707 const char *prov; 708 int i, nargs, boot, noboot; 709 710 nargs = gctl_get_int(req, "nargs"); 711 if (nargs == 0) { 712 gctl_error(req, "Too few arguments."); 713 return; 714 } 715 716 boot = gctl_get_int(req, "boot"); 717 noboot = gctl_get_int(req, "noboot"); 718 719 if (boot && noboot) { 720 gctl_error(req, "Options -b and -B are mutually exclusive."); 721 return; 722 } 723 if (!boot && !noboot) { 724 gctl_error(req, "No option given."); 725 return; 726 } 727 728 /* First attached providers. */ 729 gctl_issue(req); 730 /* Now the rest. */ 731 for (i = 0; i < nargs; i++) { 732 prov = gctl_get_ascii(req, "arg%d", i); 733 if (!eli_is_attached(prov)) 734 eli_configure_detached(req, prov, boot); 735 } 736} 737 738static void 739eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 740{ 741 unsigned char key[G_ELI_USERKEYLEN]; 742 intmax_t val, old = 0; 743 int error; 744 745 val = gctl_get_intmax(req, "iterations"); 746 /* Check if iterations number should be changed. */ 747 if (val != -1) 748 md->md_iterations = val; 749 else 750 old = md->md_iterations; 751 752 /* Generate key for Master Key encryption. */ 753 if (eli_genkey(req, md, key, 1) == NULL) { 754 bzero(key, sizeof(key)); 755 return; 756 } 757 /* 758 * If number of iterations has changed, but wasn't given as a 759 * command-line argument, update the request. 760 */ 761 if (val == -1 && md->md_iterations != old) { 762 error = gctl_change_param(req, "iterations", sizeof(intmax_t), 763 &md->md_iterations); 764 assert(error == 0); 765 } 766 767 gctl_ro_param(req, "key", sizeof(key), key); 768 gctl_issue(req); 769 bzero(key, sizeof(key)); 770} 771 772static void 773eli_setkey_detached(struct gctl_req *req, const char *prov, 774 struct g_eli_metadata *md) 775{ 776 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 777 unsigned char *mkeydst; 778 intmax_t val; 779 unsigned nkey; 780 int error; 781 782 if (md->md_keys == 0) { 783 gctl_error(req, "No valid keys on %s.", prov); 784 return; 785 } 786 787 /* Generate key for Master Key decryption. */ 788 if (eli_genkey(req, md, key, 0) == NULL) { 789 bzero(key, sizeof(key)); 790 return; 791 } 792 793 /* Decrypt Master Key. */ 794 error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 795 bzero(key, sizeof(key)); 796 if (error != 0) { 797 bzero(md, sizeof(*md)); 798 if (error == -1) 799 gctl_error(req, "Wrong key for %s.", prov); 800 else /* if (error > 0) */ { 801 gctl_error(req, "Cannot decrypt Master Key: %s.", 802 strerror(error)); 803 } 804 return; 805 } 806 if (verbose) 807 printf("Decrypted Master Key %u.\n", nkey); 808 809 val = gctl_get_intmax(req, "keyno"); 810 if (val != -1) 811 nkey = val; 812#if 0 813 else 814 ; /* Use the key number which was found during decryption. */ 815#endif 816 if (nkey >= G_ELI_MAXMKEYS) { 817 gctl_error(req, "Invalid '%s' argument.", "keyno"); 818 return; 819 } 820 821 val = gctl_get_intmax(req, "iterations"); 822 /* Check if iterations number should and can be changed. */ 823 if (val != -1) { 824 if (bitcount32(md->md_keys) != 1) { 825 gctl_error(req, "To be able to use '-i' option, only " 826 "one key can be defined."); 827 return; 828 } 829 if (md->md_keys != (1 << nkey)) { 830 gctl_error(req, "Only already defined key can be " 831 "changed when '-i' option is used."); 832 return; 833 } 834 md->md_iterations = val; 835 } 836 837 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 838 md->md_keys |= (1 << nkey); 839 840 bcopy(mkey, mkeydst, sizeof(mkey)); 841 bzero(mkey, sizeof(mkey)); 842 843 /* Generate key for Master Key encryption. */ 844 if (eli_genkey(req, md, key, 1) == NULL) { 845 bzero(key, sizeof(key)); 846 bzero(md, sizeof(*md)); 847 return; 848 } 849 850 /* Encrypt the Master-Key with the new key. */ 851 error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); 852 bzero(key, sizeof(key)); 853 if (error != 0) { 854 bzero(md, sizeof(*md)); 855 gctl_error(req, "Cannot encrypt Master Key: %s.", 856 strerror(error)); 857 return; 858 } 859 860 /* Store metadata with fresh key. */ 861 eli_metadata_store(req, prov, md); 862 bzero(md, sizeof(*md)); 863} 864 865static void 866eli_setkey(struct gctl_req *req) 867{ 868 struct g_eli_metadata md; 869 const char *prov; 870 int nargs; 871 872 nargs = gctl_get_int(req, "nargs"); 873 if (nargs != 1) { 874 gctl_error(req, "Invalid number of arguments."); 875 return; 876 } 877 prov = gctl_get_ascii(req, "arg0"); 878 879 if (eli_metadata_read(req, prov, &md) == -1) 880 return; 881 882 if (eli_is_attached(prov)) 883 eli_setkey_attached(req, &md); 884 else 885 eli_setkey_detached(req, prov, &md); 886} 887 888static void 889eli_delkey_attached(struct gctl_req *req, const char *prov __unused) 890{ 891 892 gctl_issue(req); 893} 894 895static void 896eli_delkey_detached(struct gctl_req *req, const char *prov) 897{ 898 struct g_eli_metadata md; 899 unsigned char *mkeydst; 900 intmax_t val; 901 unsigned nkey; 902 int all, force; 903 904 if (eli_metadata_read(req, prov, &md) == -1) 905 return; 906 907 all = gctl_get_int(req, "all"); 908 if (all) 909 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 910 else { 911 force = gctl_get_int(req, "force"); 912 val = gctl_get_intmax(req, "keyno"); 913 if (val == -1) { 914 gctl_error(req, "Key number has to be specified."); 915 return; 916 } 917 nkey = val; 918 if (nkey >= G_ELI_MAXMKEYS) { 919 gctl_error(req, "Invalid '%s' argument.", "keyno"); 920 return; 921 } 922 if (!(md.md_keys & (1 << nkey)) && !force) { 923 gctl_error(req, "Master Key %u is not set.", nkey); 924 return; 925 } 926 md.md_keys &= ~(1 << nkey); 927 if (md.md_keys == 0 && !force) { 928 gctl_error(req, "This is the last Master Key. Use '-f' " 929 "option if you really want to remove it."); 930 return; 931 } 932 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 933 arc4rand(mkeydst, G_ELI_MKEYLEN); 934 } 935 936 eli_metadata_store(req, prov, &md); 937 bzero(&md, sizeof(md)); 938} 939 940static void 941eli_delkey(struct gctl_req *req) 942{ 943 const char *prov; 944 int nargs; 945 946 nargs = gctl_get_int(req, "nargs"); 947 if (nargs != 1) { 948 gctl_error(req, "Invalid number of arguments."); 949 return; 950 } 951 prov = gctl_get_ascii(req, "arg0"); 952 953 if (eli_is_attached(prov)) 954 eli_delkey_attached(req, prov); 955 else 956 eli_delkey_detached(req, prov); 957} 958 959static void 960eli_kill_detached(struct gctl_req *req, const char *prov) 961{ 962 struct g_eli_metadata md; 963 int error; 964 965 /* 966 * NOTE: Maybe we should verify if this is geli provider first, 967 * but 'kill' command is quite critical so better don't waste 968 * the time. 969 */ 970#if 0 971 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 972 G_ELI_MAGIC); 973 if (error != 0) { 974 gctl_error(req, "Cannot read metadata from %s: %s.", prov, 975 strerror(error)); 976 return; 977 } 978#endif 979 980 arc4rand((unsigned char *)&md, sizeof(md)); 981 error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md)); 982 if (error != 0) { 983 gctl_error(req, "Cannot write metadata to %s: %s.", prov, 984 strerror(error)); 985 } 986} 987 988static void 989eli_kill(struct gctl_req *req) 990{ 991 const char *prov; 992 int i, nargs, all; 993 994 nargs = gctl_get_int(req, "nargs"); 995 all = gctl_get_int(req, "all"); 996 if (!all && nargs == 0) { 997 gctl_error(req, "Too few arguments."); 998 return; 999 } 1000 /* 1001 * How '-a' option combine with a list of providers: 1002 * Delete Master Keys from all attached providers: 1003 * geli kill -a 1004 * Delete Master Keys from all attached provider and from 1005 * detached da0 and da1: 1006 * geli kill -a da0 da1 1007 * Delete Master Keys from (attached or detached) da0 and da1: 1008 * geli kill da0 da1 1009 */ 1010 1011 /* First detached provider. */ 1012 for (i = 0; i < nargs; i++) { 1013 prov = gctl_get_ascii(req, "arg%d", i); 1014 if (!eli_is_attached(prov)) 1015 eli_kill_detached(req, prov); 1016 } 1017 /* Now attached providers. */ 1018 gctl_issue(req); 1019} 1020 1021static void 1022eli_backup(struct gctl_req *req) 1023{ 1024 struct g_eli_metadata md; 1025 const char *file, *prov; 1026 unsigned secsize; 1027 unsigned char *sector; 1028 off_t mediasize; 1029 int nargs, filefd, provfd; 1030 1031 nargs = gctl_get_int(req, "nargs"); 1032 if (nargs != 2) { 1033 gctl_error(req, "Invalid number of arguments."); 1034 return; 1035 } 1036 prov = gctl_get_ascii(req, "arg0"); 1037 file = gctl_get_ascii(req, "arg1"); 1038 1039 provfd = filefd = -1; 1040 sector = NULL; 1041 secsize = 0; 1042 1043 provfd = open(prov, O_RDONLY); 1044 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1045 char devprov[MAXPATHLEN]; 1046 1047 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1048 provfd = open(devprov, O_RDONLY); 1049 } 1050 if (provfd == -1) { 1051 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1052 return; 1053 } 1054 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1055 if (filefd == -1) { 1056 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1057 goto out; 1058 } 1059 1060 mediasize = g_get_mediasize(prov); 1061 secsize = g_get_sectorsize(prov); 1062 if (mediasize == 0 || secsize == 0) { 1063 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1064 strerror(errno)); 1065 return; 1066 } 1067 1068 sector = malloc(secsize); 1069 if (sector == NULL) { 1070 gctl_error(req, "Cannot allocate memory."); 1071 return; 1072 } 1073 1074 /* Read metadata from the provider. */ 1075 if (pread(provfd, sector, secsize, mediasize - secsize) != 1076 (ssize_t)secsize) { 1077 gctl_error(req, "Cannot read metadata: %s.", strerror(errno)); 1078 goto out; 1079 } 1080 /* Check if this is geli provider. */ 1081 if (eli_metadata_decode(sector, &md) != 0) { 1082 gctl_error(req, "MD5 hash mismatch: not a geli provider?"); 1083 goto out; 1084 } 1085 /* Write metadata to the destination file. */ 1086 if (write(filefd, sector, secsize) != (ssize_t)secsize) { 1087 gctl_error(req, "Cannot write to %s: %s.", file, 1088 strerror(errno)); 1089 goto out; 1090 } 1091out: 1092 if (provfd > 0) 1093 close(provfd); 1094 if (filefd > 0) 1095 close(filefd); 1096 if (sector != NULL) { 1097 bzero(sector, secsize); 1098 free(sector); 1099 } 1100} 1101 1102static void 1103eli_restore(struct gctl_req *req) 1104{ 1105 struct g_eli_metadata md; 1106 const char *file, *prov; 1107 unsigned char *sector; 1108 unsigned secsize; 1109 off_t mediasize; 1110 int nargs, filefd, provfd; 1111 1112 nargs = gctl_get_int(req, "nargs"); 1113 if (nargs != 2) { 1114 gctl_error(req, "Invalid number of arguments."); 1115 return; 1116 } 1117 file = gctl_get_ascii(req, "arg0"); 1118 prov = gctl_get_ascii(req, "arg1"); 1119 1120 provfd = filefd = -1; 1121 sector = NULL; 1122 secsize = 0; 1123 1124 filefd = open(file, O_RDONLY); 1125 if (filefd == -1) { 1126 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1127 goto out; 1128 } 1129 provfd = open(prov, O_WRONLY); 1130 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1131 char devprov[MAXPATHLEN]; 1132 1133 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1134 provfd = open(devprov, O_WRONLY); 1135 } 1136 if (provfd == -1) { 1137 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1138 return; 1139 } 1140 1141 mediasize = g_get_mediasize(prov); 1142 secsize = g_get_sectorsize(prov); 1143 if (mediasize == 0 || secsize == 0) { 1144 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1145 strerror(errno)); 1146 return; 1147 } 1148 1149 sector = malloc(secsize); 1150 if (sector == NULL) { 1151 gctl_error(req, "Cannot allocate memory."); 1152 return; 1153 } 1154 1155 /* Read metadata from the backup file. */ 1156 if (read(filefd, sector, secsize) != (ssize_t)secsize) { 1157 gctl_error(req, "Cannot read from %s: %s.", file, 1158 strerror(errno)); 1159 goto out; 1160 } 1161 /* Check if this file contains geli metadata. */ 1162 if (eli_metadata_decode(sector, &md) != 0) { 1163 gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); 1164 goto out; 1165 } 1166 /* Write metadata from the provider. */ 1167 if (pwrite(provfd, sector, secsize, mediasize - secsize) != 1168 (ssize_t)secsize) { 1169 gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1170 goto out; 1171 } 1172out: 1173 if (provfd > 0) 1174 close(provfd); 1175 if (filefd > 0) 1176 close(filefd); 1177 if (sector != NULL) { 1178 bzero(sector, secsize); 1179 free(sector); 1180 } 1181} 1182 1183static void 1184eli_clear(struct gctl_req *req) 1185{ 1186 const char *name; 1187 int error, i, nargs; 1188 1189 nargs = gctl_get_int(req, "nargs"); 1190 if (nargs < 1) { 1191 gctl_error(req, "Too few arguments."); 1192 return; 1193 } 1194 1195 for (i = 0; i < nargs; i++) { 1196 name = gctl_get_ascii(req, "arg%d", i); 1197 error = g_metadata_clear(name, G_ELI_MAGIC); 1198 if (error != 0) { 1199 fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1200 name, strerror(error)); 1201 gctl_error(req, "Not fully done."); 1202 continue; 1203 } 1204 if (verbose) 1205 printf("Metadata cleared on %s.\n", name); 1206 } 1207} 1208 1209static void 1210eli_dump(struct gctl_req *req) 1211{ 1212 struct g_eli_metadata md, tmpmd; 1213 const char *name; 1214 int error, i, nargs; 1215 1216 nargs = gctl_get_int(req, "nargs"); 1217 if (nargs < 1) { 1218 gctl_error(req, "Too few arguments."); 1219 return; 1220 } 1221 1222 for (i = 0; i < nargs; i++) { 1223 name = gctl_get_ascii(req, "arg%d", i); 1224 error = g_metadata_read(name, (unsigned char *)&tmpmd, 1225 sizeof(tmpmd), G_ELI_MAGIC); 1226 if (error != 0) { 1227 fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1228 name, strerror(error)); 1229 gctl_error(req, "Not fully done."); 1230 continue; 1231 } 1232 if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1233 fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1234 name); 1235 gctl_error(req, "Not fully done."); 1236 continue; 1237 } 1238 printf("Metadata on %s:\n", name); 1239 eli_metadata_dump(&md); 1240 printf("\n"); 1241 } 1242} 1243