geom_eli.c revision 213056
1148456Spjd/*- 2182452Spjd * Copyright (c) 2004-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3148456Spjd * All rights reserved. 4148456Spjd * 5148456Spjd * Redistribution and use in source and binary forms, with or without 6148456Spjd * modification, are permitted provided that the following conditions 7148456Spjd * are met: 8148456Spjd * 1. Redistributions of source code must retain the above copyright 9148456Spjd * notice, this list of conditions and the following disclaimer. 10148456Spjd * 2. Redistributions in binary form must reproduce the above copyright 11148456Spjd * notice, this list of conditions and the following disclaimer in the 12148456Spjd * documentation and/or other materials provided with the distribution. 13155175Spjd * 14148456Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15148456Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16148456Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17148456Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18148456Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19148456Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20148456Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21148456Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22148456Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23148456Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24148456Spjd * SUCH DAMAGE. 25148456Spjd */ 26148456Spjd 27148456Spjd#include <sys/cdefs.h> 28148456Spjd__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 213056 2010-09-23 10:50:17Z pjd $"); 29148456Spjd 30148456Spjd#include <stdio.h> 31148456Spjd#include <stdint.h> 32148456Spjd#include <stdlib.h> 33148456Spjd#include <unistd.h> 34148456Spjd#include <fcntl.h> 35148456Spjd#include <readpassphrase.h> 36148456Spjd#include <string.h> 37148456Spjd#include <strings.h> 38148456Spjd#include <libgeom.h> 39148456Spjd#include <paths.h> 40148456Spjd#include <errno.h> 41148456Spjd#include <assert.h> 42148456Spjd 43148456Spjd#include <sys/param.h> 44148456Spjd#include <sys/mman.h> 45148456Spjd#include <sys/resource.h> 46148456Spjd#include <opencrypto/cryptodev.h> 47148456Spjd#include <geom/eli/g_eli.h> 48148456Spjd#include <geom/eli/pkcs5v2.h> 49148456Spjd 50148456Spjd#include "core/geom.h" 51148456Spjd#include "misc/subr.h" 52148456Spjd 53148456Spjd 54148456Spjduint32_t lib_version = G_LIB_VERSION; 55148456Spjduint32_t version = G_ELI_VERSION; 56148456Spjd 57182452Spjd#define GELI_BACKUP_DIR "/var/backups/" 58212547Spjd#define GELI_ENC_ALGO "aes" 59182452Spjd 60148456Spjdstatic void eli_main(struct gctl_req *req, unsigned flags); 61148456Spjdstatic void eli_init(struct gctl_req *req); 62148456Spjdstatic void eli_attach(struct gctl_req *req); 63162353Spjdstatic void eli_configure(struct gctl_req *req); 64148456Spjdstatic void eli_setkey(struct gctl_req *req); 65148456Spjdstatic void eli_delkey(struct gctl_req *req); 66148456Spjdstatic void eli_kill(struct gctl_req *req); 67148456Spjdstatic void eli_backup(struct gctl_req *req); 68148456Spjdstatic void eli_restore(struct gctl_req *req); 69212934Sbrianstatic void eli_resize(struct gctl_req *req); 70148456Spjdstatic void eli_clear(struct gctl_req *req); 71148456Spjdstatic void eli_dump(struct gctl_req *req); 72148456Spjd 73182452Spjdstatic int eli_backup_create(struct gctl_req *req, const char *prov, 74182452Spjd const char *file); 75182452Spjd 76148456Spjd/* 77148456Spjd * Available commands: 78148456Spjd * 79182452Spjd * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov 80148456Spjd * label - alias for 'init' 81161127Spjd * attach [-dprv] [-k keyfile] prov 82148456Spjd * detach [-fl] prov ... 83148456Spjd * stop - alias for 'detach' 84181639Spjd * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov 85162353Spjd * configure [-bB] prov ... 86148456Spjd * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov 87148456Spjd * delkey [-afv] [-n keyno] prov 88148456Spjd * kill [-av] [prov ...] 89148456Spjd * backup [-v] prov file 90212934Sbrian * restore [-fv] file prov 91212934Sbrian * resize [-v] -s oldsize prov 92148456Spjd * clear [-v] prov ... 93148456Spjd * dump [-v] prov ... 94148456Spjd */ 95148456Spjdstruct g_command class_commands[] = { 96148456Spjd { "init", G_FLAG_VERBOSE, eli_main, 97148456Spjd { 98212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 99162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 100212547Spjd { 'B', "backupfile", "", G_TYPE_STRING }, 101212547Spjd { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, 102212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 103212547Spjd { 'K', "newkeyfile", "", G_TYPE_STRING }, 104212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 105162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 106212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 107148456Spjd G_OPT_SENTINEL 108148456Spjd }, 109212554Spjd "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" 110148456Spjd }, 111148456Spjd { "label", G_FLAG_VERBOSE, eli_main, 112148456Spjd { 113212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 114162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 115212547Spjd { 'B', "backupfile", "", G_TYPE_STRING }, 116212547Spjd { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, 117212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 118212547Spjd { 'K', "newkeyfile", "", G_TYPE_STRING }, 119212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 120162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 121212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 122148456Spjd G_OPT_SENTINEL 123148456Spjd }, 124212554Spjd "- an alias for 'init'" 125148456Spjd }, 126148456Spjd { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 127148456Spjd { 128162868Spjd { 'd', "detach", NULL, G_TYPE_BOOL }, 129212547Spjd { 'k', "keyfile", "", G_TYPE_STRING }, 130162868Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 131162868Spjd { 'r', "readonly", NULL, G_TYPE_BOOL }, 132148456Spjd G_OPT_SENTINEL 133148456Spjd }, 134212554Spjd "[-dprv] [-k keyfile] prov" 135148456Spjd }, 136148456Spjd { "detach", 0, NULL, 137148456Spjd { 138162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 139162868Spjd { 'l', "last", NULL, G_TYPE_BOOL }, 140148456Spjd G_OPT_SENTINEL 141148456Spjd }, 142212554Spjd "[-fl] prov ..." 143148456Spjd }, 144148456Spjd { "stop", 0, NULL, 145148456Spjd { 146162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 147162868Spjd { 'l', "last", NULL, G_TYPE_BOOL }, 148148456Spjd G_OPT_SENTINEL 149148456Spjd }, 150212554Spjd "- an alias for 'detach'" 151148456Spjd }, 152148456Spjd { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 153148456Spjd { 154212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 155162868Spjd { 'd', "detach", NULL, G_TYPE_BOOL }, 156212547Spjd { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, 157212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 158212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 159148456Spjd G_OPT_SENTINEL 160148456Spjd }, 161212554Spjd "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov" 162148456Spjd }, 163162353Spjd { "configure", G_FLAG_VERBOSE, eli_main, 164162353Spjd { 165162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 166162868Spjd { 'B', "noboot", NULL, G_TYPE_BOOL }, 167162353Spjd G_OPT_SENTINEL 168162353Spjd }, 169212554Spjd "[-bB] prov ..." 170162353Spjd }, 171148456Spjd { "setkey", G_FLAG_VERBOSE, eli_main, 172148456Spjd { 173212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 174212547Spjd { 'k', "keyfile", "", G_TYPE_STRING }, 175212547Spjd { 'K', "newkeyfile", "", G_TYPE_STRING }, 176212554Spjd { 'n', "keyno", "-1", G_TYPE_NUMBER }, 177162868Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 178162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 179148456Spjd G_OPT_SENTINEL 180148456Spjd }, 181212554Spjd "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov" 182148456Spjd }, 183148456Spjd { "delkey", G_FLAG_VERBOSE, eli_main, 184148456Spjd { 185162868Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 186162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 187212554Spjd { 'n', "keyno", "-1", G_TYPE_NUMBER }, 188148456Spjd G_OPT_SENTINEL 189148456Spjd }, 190212554Spjd "[-afv] [-n keyno] prov" 191148456Spjd }, 192148456Spjd { "kill", G_FLAG_VERBOSE, eli_main, 193148456Spjd { 194162868Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 195148456Spjd G_OPT_SENTINEL 196148456Spjd }, 197212554Spjd "[-av] [prov ...]" 198148456Spjd }, 199212554Spjd { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 200148456Spjd "[-v] prov file" 201148456Spjd }, 202212934Sbrian { "restore", G_FLAG_VERBOSE, eli_main, 203212934Sbrian { 204212934Sbrian { 'f', "force", NULL, G_TYPE_BOOL }, 205212934Sbrian G_OPT_SENTINEL 206212934Sbrian }, 207212934Sbrian "[-fv] file prov" 208148456Spjd }, 209212934Sbrian { "resize", G_FLAG_VERBOSE, eli_main, 210212934Sbrian { 211212934Sbrian { 's', "oldsize", NULL, G_TYPE_NUMBER }, 212212934Sbrian G_OPT_SENTINEL 213212934Sbrian }, 214212934Sbrian "[-v] -s oldsize prov" 215212934Sbrian }, 216212554Spjd { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 217148456Spjd "[-v] prov ..." 218148456Spjd }, 219212554Spjd { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 220148456Spjd "[-v] prov ..." 221148456Spjd }, 222148456Spjd G_CMD_SENTINEL 223148456Spjd}; 224148456Spjd 225148456Spjdstatic int verbose = 0; 226148456Spjd 227148456Spjdstatic int 228148456Spjdeli_protect(struct gctl_req *req) 229148456Spjd{ 230148456Spjd struct rlimit rl; 231148456Spjd 232148456Spjd /* Disable core dumps. */ 233148456Spjd rl.rlim_cur = 0; 234148456Spjd rl.rlim_max = 0; 235148456Spjd if (setrlimit(RLIMIT_CORE, &rl) == -1) { 236148456Spjd gctl_error(req, "Cannot disable core dumps: %s.", 237148456Spjd strerror(errno)); 238148456Spjd return (-1); 239148456Spjd } 240148456Spjd /* Disable swapping. */ 241148456Spjd if (mlockall(MCL_FUTURE) == -1) { 242148456Spjd gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 243148456Spjd return (-1); 244148456Spjd } 245148456Spjd return (0); 246148456Spjd} 247148456Spjd 248148456Spjdstatic void 249148456Spjdeli_main(struct gctl_req *req, unsigned flags) 250148456Spjd{ 251148456Spjd const char *name; 252148456Spjd 253148456Spjd if (eli_protect(req) == -1) 254148456Spjd return; 255148456Spjd 256148456Spjd if ((flags & G_FLAG_VERBOSE) != 0) 257148456Spjd verbose = 1; 258148456Spjd 259153190Spjd name = gctl_get_ascii(req, "verb"); 260148456Spjd if (name == NULL) { 261148456Spjd gctl_error(req, "No '%s' argument.", "verb"); 262148456Spjd return; 263148456Spjd } 264148456Spjd if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 265148456Spjd eli_init(req); 266148456Spjd else if (strcmp(name, "attach") == 0) 267148456Spjd eli_attach(req); 268162353Spjd else if (strcmp(name, "configure") == 0) 269162353Spjd eli_configure(req); 270148456Spjd else if (strcmp(name, "setkey") == 0) 271148456Spjd eli_setkey(req); 272148456Spjd else if (strcmp(name, "delkey") == 0) 273148456Spjd eli_delkey(req); 274148456Spjd else if (strcmp(name, "kill") == 0) 275148456Spjd eli_kill(req); 276148456Spjd else if (strcmp(name, "backup") == 0) 277148456Spjd eli_backup(req); 278148456Spjd else if (strcmp(name, "restore") == 0) 279148456Spjd eli_restore(req); 280212934Sbrian else if (strcmp(name, "resize") == 0) 281212934Sbrian eli_resize(req); 282148456Spjd else if (strcmp(name, "dump") == 0) 283148456Spjd eli_dump(req); 284148456Spjd else if (strcmp(name, "clear") == 0) 285148456Spjd eli_clear(req); 286148456Spjd else 287148456Spjd gctl_error(req, "Unknown command: %s.", name); 288148456Spjd} 289148456Spjd 290148456Spjdstatic void 291148456Spjdarc4rand(unsigned char *buf, size_t size) 292148456Spjd{ 293148456Spjd uint32_t *buf4; 294148456Spjd size_t size4; 295148456Spjd unsigned i; 296148456Spjd 297148456Spjd buf4 = (uint32_t *)buf; 298148456Spjd size4 = size / 4; 299148456Spjd 300148456Spjd for (i = 0; i < size4; i++) 301148456Spjd buf4[i] = arc4random(); 302148456Spjd for (i *= 4; i < size; i++) 303148456Spjd buf[i] = arc4random() % 0xff; 304148456Spjd} 305148456Spjd 306148456Spjdstatic int 307148456Spjdeli_is_attached(const char *prov) 308148456Spjd{ 309148456Spjd char name[MAXPATHLEN]; 310148456Spjd unsigned secsize; 311148456Spjd 312148456Spjd /* 313148456Spjd * Not the best way to do it, but the easiest. 314148456Spjd * We try to open provider and check if it is a GEOM provider 315148456Spjd * by asking about its sectorsize. 316148456Spjd */ 317148456Spjd snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 318148456Spjd secsize = g_get_sectorsize(name); 319148456Spjd if (secsize > 0) 320148456Spjd return (1); 321148456Spjd return (0); 322148456Spjd} 323148456Spjd 324148456Spjdstatic unsigned char * 325148456Spjdeli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 326148456Spjd int new) 327148456Spjd{ 328148456Spjd struct hmac_ctx ctx; 329148456Spjd const char *str; 330153190Spjd int error, nopassphrase; 331148456Spjd 332153190Spjd nopassphrase = 333153190Spjd gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 334148456Spjd 335148456Spjd g_eli_crypto_hmac_init(&ctx, NULL, 0); 336148456Spjd 337153190Spjd str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile"); 338155183Spjd if (str[0] == '\0' && nopassphrase) { 339155183Spjd gctl_error(req, "No key components given."); 340155183Spjd return (NULL); 341155183Spjd } else if (str[0] != '\0') { 342148456Spjd char buf[MAXPHYS]; 343148456Spjd ssize_t done; 344148456Spjd int fd; 345148456Spjd 346148456Spjd if (strcmp(str, "-") == 0) 347148456Spjd fd = STDIN_FILENO; 348148456Spjd else { 349148456Spjd fd = open(str, O_RDONLY); 350148456Spjd if (fd == -1) { 351148456Spjd gctl_error(req, "Cannot open keyfile %s: %s.", 352148456Spjd str, strerror(errno)); 353148456Spjd return (NULL); 354148456Spjd } 355148456Spjd } 356148456Spjd while ((done = read(fd, buf, sizeof(buf))) > 0) 357148456Spjd g_eli_crypto_hmac_update(&ctx, buf, done); 358148456Spjd error = errno; 359148456Spjd if (strcmp(str, "-") != 0) 360148456Spjd close(fd); 361148456Spjd bzero(buf, sizeof(buf)); 362148456Spjd if (done == -1) { 363148456Spjd gctl_error(req, "Cannot read keyfile %s: %s.", str, 364148456Spjd strerror(error)); 365148456Spjd return (NULL); 366148456Spjd } 367148456Spjd } 368148456Spjd 369153190Spjd if (!nopassphrase) { 370148456Spjd char buf1[BUFSIZ], buf2[BUFSIZ], *p; 371148456Spjd 372149047Spjd if (!new && md->md_iterations == -1) { 373149047Spjd gctl_error(req, "Missing -p flag."); 374149047Spjd return (NULL); 375149047Spjd } 376148456Spjd for (;;) { 377148456Spjd p = readpassphrase( 378148456Spjd new ? "Enter new passphrase:" : "Enter passphrase:", 379148456Spjd buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY); 380148456Spjd if (p == NULL) { 381148456Spjd bzero(buf1, sizeof(buf1)); 382148456Spjd gctl_error(req, "Cannot read passphrase: %s.", 383148456Spjd strerror(errno)); 384148456Spjd return (NULL); 385148456Spjd } 386148456Spjd 387148456Spjd if (new) { 388148456Spjd p = readpassphrase("Reenter new passphrase: ", 389148456Spjd buf2, sizeof(buf2), 390148456Spjd RPP_ECHO_OFF | RPP_REQUIRE_TTY); 391148456Spjd if (p == NULL) { 392148456Spjd bzero(buf1, sizeof(buf1)); 393148456Spjd gctl_error(req, 394148456Spjd "Cannot read passphrase: %s.", 395148456Spjd strerror(errno)); 396148456Spjd return (NULL); 397148456Spjd } 398148456Spjd 399148456Spjd if (strcmp(buf1, buf2) != 0) { 400148456Spjd bzero(buf2, sizeof(buf2)); 401148456Spjd fprintf(stderr, "They didn't match.\n"); 402148456Spjd continue; 403148456Spjd } 404148456Spjd bzero(buf2, sizeof(buf2)); 405148456Spjd } 406148456Spjd break; 407148456Spjd } 408148456Spjd /* 409148456Spjd * Field md_iterations equal to -1 means "choose some sane 410148456Spjd * value for me". 411148456Spjd */ 412148456Spjd if (md->md_iterations == -1) { 413148456Spjd assert(new); 414148456Spjd if (verbose) 415148456Spjd printf("Calculating number of iterations...\n"); 416148456Spjd md->md_iterations = pkcs5v2_calculate(2000000); 417148456Spjd assert(md->md_iterations > 0); 418148456Spjd if (verbose) { 419148456Spjd printf("Done, using %d iterations.\n", 420148456Spjd md->md_iterations); 421148456Spjd } 422148456Spjd } 423148456Spjd /* 424161052Spjd * If md_iterations is equal to 0, user don't want PKCS#5v2. 425148456Spjd */ 426148456Spjd if (md->md_iterations == 0) { 427148456Spjd g_eli_crypto_hmac_update(&ctx, md->md_salt, 428148456Spjd sizeof(md->md_salt)); 429148456Spjd g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1)); 430148456Spjd } else /* if (md->md_iterations > 0) */ { 431148456Spjd unsigned char dkey[G_ELI_USERKEYLEN]; 432148456Spjd 433148456Spjd pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 434148456Spjd sizeof(md->md_salt), buf1, md->md_iterations); 435148456Spjd g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); 436148456Spjd bzero(dkey, sizeof(dkey)); 437148456Spjd } 438148456Spjd bzero(buf1, sizeof(buf1)); 439148456Spjd } 440148456Spjd g_eli_crypto_hmac_final(&ctx, key, 0); 441148456Spjd return (key); 442148456Spjd} 443148456Spjd 444148456Spjdstatic int 445148456Spjdeli_metadata_read(struct gctl_req *req, const char *prov, 446148456Spjd struct g_eli_metadata *md) 447148456Spjd{ 448148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 449148456Spjd int error; 450148456Spjd 451148456Spjd if (g_get_sectorsize(prov) == 0) { 452148456Spjd int fd; 453148456Spjd 454148456Spjd /* This is a file probably. */ 455148456Spjd fd = open(prov, O_RDONLY); 456148456Spjd if (fd == -1) { 457148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 458148456Spjd strerror(errno)); 459148456Spjd return (-1); 460148456Spjd } 461148456Spjd if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 462148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 463148456Spjd prov, strerror(errno)); 464148456Spjd close(fd); 465148456Spjd return (-1); 466148456Spjd } 467148456Spjd close(fd); 468148456Spjd } else { 469148456Spjd /* This is a GEOM provider. */ 470148456Spjd error = g_metadata_read(prov, sector, sizeof(sector), 471148456Spjd G_ELI_MAGIC); 472148456Spjd if (error != 0) { 473148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 474148456Spjd prov, strerror(error)); 475148456Spjd return (-1); 476148456Spjd } 477148456Spjd } 478148456Spjd if (eli_metadata_decode(sector, md) != 0) { 479148456Spjd gctl_error(req, "MD5 hash mismatch for %s.", prov); 480148456Spjd return (-1); 481148456Spjd } 482148456Spjd return (0); 483148456Spjd} 484148456Spjd 485148456Spjdstatic int 486148456Spjdeli_metadata_store(struct gctl_req *req, const char *prov, 487148456Spjd struct g_eli_metadata *md) 488148456Spjd{ 489148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 490148456Spjd int error; 491148456Spjd 492148456Spjd eli_metadata_encode(md, sector); 493148456Spjd if (g_get_sectorsize(prov) == 0) { 494148456Spjd int fd; 495148456Spjd 496148456Spjd /* This is a file probably. */ 497148456Spjd fd = open(prov, O_WRONLY | O_TRUNC); 498148456Spjd if (fd == -1) { 499148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 500148456Spjd strerror(errno)); 501148456Spjd bzero(sector, sizeof(sector)); 502148456Spjd return (-1); 503148456Spjd } 504148456Spjd if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 505148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 506148456Spjd prov, strerror(errno)); 507148456Spjd bzero(sector, sizeof(sector)); 508148456Spjd close(fd); 509148456Spjd return (-1); 510148456Spjd } 511148456Spjd close(fd); 512148456Spjd } else { 513148456Spjd /* This is a GEOM provider. */ 514148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 515148456Spjd if (error != 0) { 516148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 517148456Spjd prov, strerror(errno)); 518148456Spjd bzero(sector, sizeof(sector)); 519148456Spjd return (-1); 520148456Spjd } 521148456Spjd } 522148456Spjd bzero(sector, sizeof(sector)); 523148456Spjd return (0); 524148456Spjd} 525148456Spjd 526148456Spjdstatic void 527148456Spjdeli_init(struct gctl_req *req) 528148456Spjd{ 529148456Spjd struct g_eli_metadata md; 530148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 531148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 532182452Spjd char backfile[MAXPATHLEN]; 533148456Spjd const char *str, *prov; 534148456Spjd unsigned secsize; 535148456Spjd off_t mediasize; 536153190Spjd intmax_t val; 537155536Spjd int error, nargs; 538148456Spjd 539153190Spjd nargs = gctl_get_int(req, "nargs"); 540153190Spjd if (nargs != 1) { 541158214Spjd gctl_error(req, "Invalid number of arguments."); 542148456Spjd return; 543148456Spjd } 544153190Spjd prov = gctl_get_ascii(req, "arg0"); 545148456Spjd mediasize = g_get_mediasize(prov); 546148456Spjd secsize = g_get_sectorsize(prov); 547148456Spjd if (mediasize == 0 || secsize == 0) { 548148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 549148456Spjd strerror(errno)); 550148456Spjd return; 551148456Spjd } 552148456Spjd 553148456Spjd bzero(&md, sizeof(md)); 554148456Spjd strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 555148456Spjd md.md_version = G_ELI_VERSION; 556148456Spjd md.md_flags = 0; 557155536Spjd if (gctl_get_int(req, "boot")) 558148456Spjd md.md_flags |= G_ELI_FLAG_BOOT; 559159361Spjd md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 560159308Spjd str = gctl_get_ascii(req, "aalgo"); 561212547Spjd if (*str != '\0') { 562159308Spjd md.md_aalgo = g_eli_str2aalgo(str); 563159361Spjd if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 564159361Spjd md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 565159361Spjd md.md_flags |= G_ELI_FLAG_AUTH; 566159361Spjd } else { 567159361Spjd /* 568159361Spjd * For backward compatibility, check if the -a option 569159361Spjd * was used to provide encryption algorithm. 570159361Spjd */ 571159361Spjd md.md_ealgo = g_eli_str2ealgo(str); 572159361Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 573159361Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 574159361Spjd gctl_error(req, 575159361Spjd "Invalid authentication algorithm."); 576159361Spjd return; 577159361Spjd } else { 578159361Spjd fprintf(stderr, "warning: The -e option, not " 579159361Spjd "the -a option is now used to specify " 580159361Spjd "encryption algorithm to use.\n"); 581159361Spjd } 582159308Spjd } 583159308Spjd } 584159308Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 585159308Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 586159361Spjd str = gctl_get_ascii(req, "ealgo"); 587159361Spjd md.md_ealgo = g_eli_str2ealgo(str); 588159361Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 589159361Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 590159361Spjd gctl_error(req, "Invalid encryption algorithm."); 591159361Spjd return; 592159361Spjd } 593148456Spjd } 594153190Spjd val = gctl_get_intmax(req, "keylen"); 595153190Spjd md.md_keylen = val; 596159308Spjd md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); 597148456Spjd if (md.md_keylen == 0) { 598148456Spjd gctl_error(req, "Invalid key length."); 599148456Spjd return; 600148456Spjd } 601148456Spjd md.md_provsize = mediasize; 602148456Spjd 603153190Spjd val = gctl_get_intmax(req, "iterations"); 604155536Spjd if (val != -1) { 605155536Spjd int nonewpassphrase; 606155536Spjd 607155536Spjd /* 608155536Spjd * Don't allow to set iterations when there will be no 609155536Spjd * passphrase. 610155536Spjd */ 611155536Spjd nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 612155536Spjd if (nonewpassphrase) { 613155536Spjd gctl_error(req, 614155536Spjd "Options -i and -P are mutually exclusive."); 615155536Spjd return; 616155536Spjd } 617155536Spjd } 618153190Spjd md.md_iterations = val; 619148456Spjd 620153190Spjd val = gctl_get_intmax(req, "sectorsize"); 621153190Spjd if (val == 0) 622148456Spjd md.md_sectorsize = secsize; 623148456Spjd else { 624153190Spjd if (val < 0 || (val % secsize) != 0) { 625148456Spjd gctl_error(req, "Invalid sector size."); 626148456Spjd return; 627148456Spjd } 628167229Spjd if (val > sysconf(_SC_PAGE_SIZE)) { 629167229Spjd gctl_error(req, "warning: Using sectorsize bigger than " 630167229Spjd "the page size!"); 631167229Spjd } 632153190Spjd md.md_sectorsize = val; 633148456Spjd } 634148456Spjd 635148456Spjd md.md_keys = 0x01; 636148456Spjd arc4rand(md.md_salt, sizeof(md.md_salt)); 637148456Spjd arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 638148456Spjd 639148456Spjd /* Generate user key. */ 640148456Spjd if (eli_genkey(req, &md, key, 1) == NULL) { 641148456Spjd bzero(key, sizeof(key)); 642148456Spjd bzero(&md, sizeof(md)); 643148456Spjd return; 644148456Spjd } 645148456Spjd 646148456Spjd /* Encrypt the first and the only Master Key. */ 647159308Spjd error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); 648148456Spjd bzero(key, sizeof(key)); 649148456Spjd if (error != 0) { 650148456Spjd bzero(&md, sizeof(md)); 651148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 652148456Spjd strerror(error)); 653148456Spjd return; 654148456Spjd } 655148456Spjd 656148456Spjd eli_metadata_encode(&md, sector); 657148456Spjd bzero(&md, sizeof(md)); 658148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 659148456Spjd bzero(sector, sizeof(sector)); 660148456Spjd if (error != 0) { 661148456Spjd gctl_error(req, "Cannot store metadata on %s: %s.", prov, 662148456Spjd strerror(error)); 663148456Spjd return; 664148456Spjd } 665148456Spjd if (verbose) 666148456Spjd printf("Metadata value stored on %s.\n", prov); 667182452Spjd /* Backup metadata to a file. */ 668182452Spjd str = gctl_get_ascii(req, "backupfile"); 669182452Spjd if (str[0] != '\0') { 670182452Spjd /* Backupfile given be the user, just copy it. */ 671182452Spjd strlcpy(backfile, str, sizeof(backfile)); 672182452Spjd } else { 673182452Spjd /* Generate file name automatically. */ 674182452Spjd const char *p = prov; 675182452Spjd unsigned int i; 676182452Spjd 677182452Spjd if (strncmp(p, _PATH_DEV, strlen(_PATH_DEV)) == 0) 678182452Spjd p += strlen(_PATH_DEV); 679182452Spjd snprintf(backfile, sizeof(backfile), "%s%s.eli", 680182452Spjd GELI_BACKUP_DIR, p); 681182452Spjd /* Replace all / with _. */ 682182452Spjd for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) { 683182452Spjd if (backfile[i] == '/') 684182452Spjd backfile[i] = '_'; 685182452Spjd } 686182452Spjd } 687182452Spjd if (strcmp(backfile, "none") != 0 && 688182452Spjd eli_backup_create(req, prov, backfile) == 0) { 689182452Spjd printf("\nMetadata backup can be found in %s and\n", backfile); 690182452Spjd printf("can be restored with the following command:\n"); 691182452Spjd printf("\n\t# geli restore %s %s\n\n", backfile, prov); 692182452Spjd } 693148456Spjd} 694148456Spjd 695148456Spjdstatic void 696148456Spjdeli_attach(struct gctl_req *req) 697148456Spjd{ 698148456Spjd struct g_eli_metadata md; 699148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 700148456Spjd const char *prov; 701212934Sbrian off_t mediasize; 702153190Spjd int nargs; 703148456Spjd 704153190Spjd nargs = gctl_get_int(req, "nargs"); 705153190Spjd if (nargs != 1) { 706158214Spjd gctl_error(req, "Invalid number of arguments."); 707148456Spjd return; 708148456Spjd } 709153190Spjd prov = gctl_get_ascii(req, "arg0"); 710148456Spjd 711148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 712148456Spjd return; 713148456Spjd 714212934Sbrian mediasize = g_get_mediasize(prov); 715212934Sbrian if (md.md_provsize != (uint64_t)mediasize) { 716212934Sbrian gctl_error(req, "Provider size mismatch."); 717212934Sbrian return; 718212934Sbrian } 719212934Sbrian 720148456Spjd if (eli_genkey(req, &md, key, 0) == NULL) { 721148456Spjd bzero(key, sizeof(key)); 722148456Spjd return; 723148456Spjd } 724148456Spjd 725148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 726148456Spjd if (gctl_issue(req) == NULL) { 727148456Spjd if (verbose) 728166892Spjd printf("Attached to %s.\n", prov); 729148456Spjd } 730148456Spjd bzero(key, sizeof(key)); 731148456Spjd} 732148456Spjd 733148456Spjdstatic void 734162353Spjdeli_configure_detached(struct gctl_req *req, const char *prov, int boot) 735162353Spjd{ 736162353Spjd struct g_eli_metadata md; 737162353Spjd 738162353Spjd if (eli_metadata_read(req, prov, &md) == -1) 739162353Spjd return; 740162353Spjd 741162353Spjd if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) { 742162353Spjd if (verbose) 743162353Spjd printf("BOOT flag already configured for %s.\n", prov); 744162353Spjd } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) { 745162353Spjd if (verbose) 746162353Spjd printf("BOOT flag not configured for %s.\n", prov); 747162353Spjd } else { 748162353Spjd if (boot) 749162353Spjd md.md_flags |= G_ELI_FLAG_BOOT; 750162353Spjd else 751162353Spjd md.md_flags &= ~G_ELI_FLAG_BOOT; 752162353Spjd eli_metadata_store(req, prov, &md); 753162353Spjd } 754162353Spjd bzero(&md, sizeof(md)); 755162353Spjd} 756162353Spjd 757162353Spjdstatic void 758162353Spjdeli_configure(struct gctl_req *req) 759162353Spjd{ 760162353Spjd const char *prov; 761162353Spjd int i, nargs, boot, noboot; 762162353Spjd 763162353Spjd nargs = gctl_get_int(req, "nargs"); 764162353Spjd if (nargs == 0) { 765162353Spjd gctl_error(req, "Too few arguments."); 766162353Spjd return; 767162353Spjd } 768162353Spjd 769162353Spjd boot = gctl_get_int(req, "boot"); 770162353Spjd noboot = gctl_get_int(req, "noboot"); 771162353Spjd 772162353Spjd if (boot && noboot) { 773162353Spjd gctl_error(req, "Options -b and -B are mutually exclusive."); 774162353Spjd return; 775162353Spjd } 776162353Spjd if (!boot && !noboot) { 777162353Spjd gctl_error(req, "No option given."); 778162353Spjd return; 779162353Spjd } 780162353Spjd 781162353Spjd /* First attached providers. */ 782162353Spjd gctl_issue(req); 783162353Spjd /* Now the rest. */ 784162353Spjd for (i = 0; i < nargs; i++) { 785162353Spjd prov = gctl_get_ascii(req, "arg%d", i); 786162353Spjd if (!eli_is_attached(prov)) 787162353Spjd eli_configure_detached(req, prov, boot); 788162353Spjd } 789162353Spjd} 790162353Spjd 791162353Spjdstatic void 792155101Spjdeli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 793148456Spjd{ 794148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 795166216Spjd intmax_t val, old = 0; 796166216Spjd int error; 797148456Spjd 798153190Spjd val = gctl_get_intmax(req, "iterations"); 799149304Spjd /* Check if iterations number should be changed. */ 800153190Spjd if (val != -1) 801153190Spjd md->md_iterations = val; 802166216Spjd else 803166216Spjd old = md->md_iterations; 804148456Spjd 805148456Spjd /* Generate key for Master Key encryption. */ 806149304Spjd if (eli_genkey(req, md, key, 1) == NULL) { 807148456Spjd bzero(key, sizeof(key)); 808148456Spjd return; 809148456Spjd } 810166216Spjd /* 811166216Spjd * If number of iterations has changed, but wasn't given as a 812166216Spjd * command-line argument, update the request. 813166216Spjd */ 814166216Spjd if (val == -1 && md->md_iterations != old) { 815166216Spjd error = gctl_change_param(req, "iterations", sizeof(intmax_t), 816166216Spjd &md->md_iterations); 817166216Spjd assert(error == 0); 818166216Spjd } 819148456Spjd 820148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 821148456Spjd gctl_issue(req); 822148456Spjd bzero(key, sizeof(key)); 823148456Spjd} 824148456Spjd 825148456Spjdstatic void 826149304Spjdeli_setkey_detached(struct gctl_req *req, const char *prov, 827149304Spjd struct g_eli_metadata *md) 828148456Spjd{ 829148456Spjd unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 830148456Spjd unsigned char *mkeydst; 831153190Spjd intmax_t val; 832148456Spjd unsigned nkey; 833148456Spjd int error; 834148456Spjd 835149928Spjd if (md->md_keys == 0) { 836149928Spjd gctl_error(req, "No valid keys on %s.", prov); 837149928Spjd return; 838149928Spjd } 839149928Spjd 840148456Spjd /* Generate key for Master Key decryption. */ 841149304Spjd if (eli_genkey(req, md, key, 0) == NULL) { 842148456Spjd bzero(key, sizeof(key)); 843148456Spjd return; 844148456Spjd } 845148456Spjd 846148456Spjd /* Decrypt Master Key. */ 847149304Spjd error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 848148456Spjd bzero(key, sizeof(key)); 849148456Spjd if (error != 0) { 850149304Spjd bzero(md, sizeof(*md)); 851148456Spjd if (error == -1) 852148456Spjd gctl_error(req, "Wrong key for %s.", prov); 853148456Spjd else /* if (error > 0) */ { 854148456Spjd gctl_error(req, "Cannot decrypt Master Key: %s.", 855148456Spjd strerror(error)); 856148456Spjd } 857148456Spjd return; 858148456Spjd } 859148456Spjd if (verbose) 860148456Spjd printf("Decrypted Master Key %u.\n", nkey); 861148456Spjd 862153190Spjd val = gctl_get_intmax(req, "keyno"); 863153190Spjd if (val != -1) 864153190Spjd nkey = val; 865148456Spjd#if 0 866148456Spjd else 867148456Spjd ; /* Use the key number which was found during decryption. */ 868148456Spjd#endif 869148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 870148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 871148456Spjd return; 872148456Spjd } 873148456Spjd 874153190Spjd val = gctl_get_intmax(req, "iterations"); 875149304Spjd /* Check if iterations number should and can be changed. */ 876153190Spjd if (val != -1) { 877149304Spjd if (bitcount32(md->md_keys) != 1) { 878149304Spjd gctl_error(req, "To be able to use '-i' option, only " 879149304Spjd "one key can be defined."); 880149304Spjd return; 881149304Spjd } 882149304Spjd if (md->md_keys != (1 << nkey)) { 883149304Spjd gctl_error(req, "Only already defined key can be " 884149304Spjd "changed when '-i' option is used."); 885149304Spjd return; 886149304Spjd } 887153190Spjd md->md_iterations = val; 888149304Spjd } 889148456Spjd 890149304Spjd mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 891149304Spjd md->md_keys |= (1 << nkey); 892149304Spjd 893148456Spjd bcopy(mkey, mkeydst, sizeof(mkey)); 894148456Spjd bzero(mkey, sizeof(mkey)); 895148456Spjd 896148456Spjd /* Generate key for Master Key encryption. */ 897149304Spjd if (eli_genkey(req, md, key, 1) == NULL) { 898148456Spjd bzero(key, sizeof(key)); 899149304Spjd bzero(md, sizeof(*md)); 900148456Spjd return; 901148456Spjd } 902148456Spjd 903148456Spjd /* Encrypt the Master-Key with the new key. */ 904159308Spjd error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); 905148456Spjd bzero(key, sizeof(key)); 906148456Spjd if (error != 0) { 907149304Spjd bzero(md, sizeof(*md)); 908148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 909148456Spjd strerror(error)); 910148456Spjd return; 911148456Spjd } 912148456Spjd 913148456Spjd /* Store metadata with fresh key. */ 914149304Spjd eli_metadata_store(req, prov, md); 915149304Spjd bzero(md, sizeof(*md)); 916148456Spjd} 917148456Spjd 918148456Spjdstatic void 919148456Spjdeli_setkey(struct gctl_req *req) 920148456Spjd{ 921149304Spjd struct g_eli_metadata md; 922148456Spjd const char *prov; 923153190Spjd int nargs; 924148456Spjd 925153190Spjd nargs = gctl_get_int(req, "nargs"); 926153190Spjd if (nargs != 1) { 927158214Spjd gctl_error(req, "Invalid number of arguments."); 928148456Spjd return; 929148456Spjd } 930153190Spjd prov = gctl_get_ascii(req, "arg0"); 931148456Spjd 932149304Spjd if (eli_metadata_read(req, prov, &md) == -1) 933149304Spjd return; 934149304Spjd 935148456Spjd if (eli_is_attached(prov)) 936155101Spjd eli_setkey_attached(req, &md); 937148456Spjd else 938149304Spjd eli_setkey_detached(req, prov, &md); 939182452Spjd 940182452Spjd if (req->error == NULL || req->error[0] == '\0') { 941182452Spjd printf("Note, that the master key encrypted with old keys " 942182452Spjd "and/or passphrase may still exists in a metadata backup " 943182452Spjd "file.\n"); 944182452Spjd } 945148456Spjd} 946148456Spjd 947148456Spjdstatic void 948148456Spjdeli_delkey_attached(struct gctl_req *req, const char *prov __unused) 949148456Spjd{ 950148456Spjd 951148456Spjd gctl_issue(req); 952148456Spjd} 953148456Spjd 954148456Spjdstatic void 955148456Spjdeli_delkey_detached(struct gctl_req *req, const char *prov) 956148456Spjd{ 957148456Spjd struct g_eli_metadata md; 958148456Spjd unsigned char *mkeydst; 959153190Spjd intmax_t val; 960148456Spjd unsigned nkey; 961153190Spjd int all, force; 962148456Spjd 963148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 964148456Spjd return; 965148456Spjd 966153190Spjd all = gctl_get_int(req, "all"); 967153190Spjd if (all) 968148456Spjd arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 969148456Spjd else { 970153190Spjd force = gctl_get_int(req, "force"); 971153190Spjd val = gctl_get_intmax(req, "keyno"); 972153190Spjd if (val == -1) { 973148456Spjd gctl_error(req, "Key number has to be specified."); 974148456Spjd return; 975148456Spjd } 976153190Spjd nkey = val; 977148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 978148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 979148456Spjd return; 980148456Spjd } 981153190Spjd if (!(md.md_keys & (1 << nkey)) && !force) { 982148456Spjd gctl_error(req, "Master Key %u is not set.", nkey); 983148456Spjd return; 984148456Spjd } 985148456Spjd md.md_keys &= ~(1 << nkey); 986153190Spjd if (md.md_keys == 0 && !force) { 987148456Spjd gctl_error(req, "This is the last Master Key. Use '-f' " 988148456Spjd "option if you really want to remove it."); 989148456Spjd return; 990148456Spjd } 991148456Spjd mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 992148456Spjd arc4rand(mkeydst, G_ELI_MKEYLEN); 993148456Spjd } 994148456Spjd 995148456Spjd eli_metadata_store(req, prov, &md); 996148456Spjd bzero(&md, sizeof(md)); 997148456Spjd} 998148456Spjd 999148456Spjdstatic void 1000148456Spjdeli_delkey(struct gctl_req *req) 1001148456Spjd{ 1002148456Spjd const char *prov; 1003153190Spjd int nargs; 1004148456Spjd 1005153190Spjd nargs = gctl_get_int(req, "nargs"); 1006153190Spjd if (nargs != 1) { 1007158214Spjd gctl_error(req, "Invalid number of arguments."); 1008148456Spjd return; 1009148456Spjd } 1010153190Spjd prov = gctl_get_ascii(req, "arg0"); 1011148456Spjd 1012148456Spjd if (eli_is_attached(prov)) 1013148456Spjd eli_delkey_attached(req, prov); 1014148456Spjd else 1015148456Spjd eli_delkey_detached(req, prov); 1016148456Spjd} 1017148456Spjd 1018148456Spjdstatic void 1019148456Spjdeli_kill_detached(struct gctl_req *req, const char *prov) 1020148456Spjd{ 1021148456Spjd struct g_eli_metadata md; 1022148456Spjd int error; 1023148456Spjd 1024148456Spjd /* 1025148456Spjd * NOTE: Maybe we should verify if this is geli provider first, 1026148456Spjd * but 'kill' command is quite critical so better don't waste 1027148456Spjd * the time. 1028148456Spjd */ 1029148456Spjd#if 0 1030148456Spjd error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 1031148456Spjd G_ELI_MAGIC); 1032148456Spjd if (error != 0) { 1033148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", prov, 1034148456Spjd strerror(error)); 1035148456Spjd return; 1036148456Spjd } 1037148456Spjd#endif 1038148456Spjd 1039148456Spjd arc4rand((unsigned char *)&md, sizeof(md)); 1040148456Spjd error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md)); 1041148456Spjd if (error != 0) { 1042148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", prov, 1043148456Spjd strerror(error)); 1044148456Spjd } 1045148456Spjd} 1046148456Spjd 1047148456Spjdstatic void 1048148456Spjdeli_kill(struct gctl_req *req) 1049148456Spjd{ 1050148456Spjd const char *prov; 1051153190Spjd int i, nargs, all; 1052148456Spjd 1053153190Spjd nargs = gctl_get_int(req, "nargs"); 1054153190Spjd all = gctl_get_int(req, "all"); 1055153190Spjd if (!all && nargs == 0) { 1056148456Spjd gctl_error(req, "Too few arguments."); 1057148456Spjd return; 1058148456Spjd } 1059148456Spjd /* 1060148456Spjd * How '-a' option combine with a list of providers: 1061148456Spjd * Delete Master Keys from all attached providers: 1062148456Spjd * geli kill -a 1063169312Spjd * Delete Master Keys from all attached providers and from 1064148456Spjd * detached da0 and da1: 1065148456Spjd * geli kill -a da0 da1 1066148456Spjd * Delete Master Keys from (attached or detached) da0 and da1: 1067148456Spjd * geli kill da0 da1 1068148456Spjd */ 1069148456Spjd 1070169312Spjd /* First detached providers. */ 1071153190Spjd for (i = 0; i < nargs; i++) { 1072153190Spjd prov = gctl_get_ascii(req, "arg%d", i); 1073148456Spjd if (!eli_is_attached(prov)) 1074148456Spjd eli_kill_detached(req, prov); 1075148456Spjd } 1076162347Spjd /* Now attached providers. */ 1077162347Spjd gctl_issue(req); 1078148456Spjd} 1079148456Spjd 1080182452Spjdstatic int 1081182452Spjdeli_backup_create(struct gctl_req *req, const char *prov, const char *file) 1082148456Spjd{ 1083148456Spjd struct g_eli_metadata md; 1084148456Spjd unsigned secsize; 1085148456Spjd unsigned char *sector; 1086148456Spjd off_t mediasize; 1087182452Spjd int filefd, provfd, ret; 1088148456Spjd 1089182452Spjd ret = -1; 1090148456Spjd provfd = filefd = -1; 1091148456Spjd sector = NULL; 1092148456Spjd secsize = 0; 1093148456Spjd 1094148456Spjd provfd = open(prov, O_RDONLY); 1095148456Spjd if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1096148456Spjd char devprov[MAXPATHLEN]; 1097148456Spjd 1098148456Spjd snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1099148456Spjd provfd = open(devprov, O_RDONLY); 1100148456Spjd } 1101148456Spjd if (provfd == -1) { 1102148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1103169193Spjd goto out; 1104148456Spjd } 1105148456Spjd filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1106148456Spjd if (filefd == -1) { 1107148456Spjd gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1108148456Spjd goto out; 1109148456Spjd } 1110148456Spjd 1111148456Spjd mediasize = g_get_mediasize(prov); 1112148456Spjd secsize = g_get_sectorsize(prov); 1113148456Spjd if (mediasize == 0 || secsize == 0) { 1114148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 1115148456Spjd strerror(errno)); 1116169193Spjd goto out; 1117148456Spjd } 1118148456Spjd 1119148456Spjd sector = malloc(secsize); 1120148456Spjd if (sector == NULL) { 1121148456Spjd gctl_error(req, "Cannot allocate memory."); 1122169193Spjd goto out; 1123148456Spjd } 1124148456Spjd 1125148456Spjd /* Read metadata from the provider. */ 1126148456Spjd if (pread(provfd, sector, secsize, mediasize - secsize) != 1127148456Spjd (ssize_t)secsize) { 1128148456Spjd gctl_error(req, "Cannot read metadata: %s.", strerror(errno)); 1129148456Spjd goto out; 1130148456Spjd } 1131148456Spjd /* Check if this is geli provider. */ 1132148456Spjd if (eli_metadata_decode(sector, &md) != 0) { 1133148456Spjd gctl_error(req, "MD5 hash mismatch: not a geli provider?"); 1134148456Spjd goto out; 1135148456Spjd } 1136148456Spjd /* Write metadata to the destination file. */ 1137148456Spjd if (write(filefd, sector, secsize) != (ssize_t)secsize) { 1138148456Spjd gctl_error(req, "Cannot write to %s: %s.", file, 1139148456Spjd strerror(errno)); 1140148456Spjd goto out; 1141148456Spjd } 1142182452Spjd /* Success. */ 1143182452Spjd ret = 0; 1144148456Spjdout: 1145148456Spjd if (provfd > 0) 1146148456Spjd close(provfd); 1147148456Spjd if (filefd > 0) 1148148456Spjd close(filefd); 1149148456Spjd if (sector != NULL) { 1150148456Spjd bzero(sector, secsize); 1151148456Spjd free(sector); 1152148456Spjd } 1153182452Spjd return (ret); 1154148456Spjd} 1155148456Spjd 1156148456Spjdstatic void 1157182452Spjdeli_backup(struct gctl_req *req) 1158182452Spjd{ 1159182452Spjd const char *file, *prov; 1160182452Spjd int nargs; 1161182452Spjd 1162182452Spjd nargs = gctl_get_int(req, "nargs"); 1163182452Spjd if (nargs != 2) { 1164182452Spjd gctl_error(req, "Invalid number of arguments."); 1165182452Spjd return; 1166182452Spjd } 1167182452Spjd prov = gctl_get_ascii(req, "arg0"); 1168182452Spjd file = gctl_get_ascii(req, "arg1"); 1169182452Spjd 1170182452Spjd eli_backup_create(req, prov, file); 1171182452Spjd} 1172182452Spjd 1173182452Spjdstatic void 1174148456Spjdeli_restore(struct gctl_req *req) 1175148456Spjd{ 1176148456Spjd struct g_eli_metadata md; 1177148456Spjd const char *file, *prov; 1178148456Spjd unsigned char *sector; 1179148456Spjd unsigned secsize; 1180148456Spjd off_t mediasize; 1181153190Spjd int nargs, filefd, provfd; 1182148456Spjd 1183153190Spjd nargs = gctl_get_int(req, "nargs"); 1184153190Spjd if (nargs != 2) { 1185148456Spjd gctl_error(req, "Invalid number of arguments."); 1186148456Spjd return; 1187148456Spjd } 1188153190Spjd file = gctl_get_ascii(req, "arg0"); 1189153190Spjd prov = gctl_get_ascii(req, "arg1"); 1190148456Spjd 1191148456Spjd provfd = filefd = -1; 1192148456Spjd sector = NULL; 1193148456Spjd secsize = 0; 1194148456Spjd 1195148456Spjd filefd = open(file, O_RDONLY); 1196148456Spjd if (filefd == -1) { 1197148456Spjd gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1198148456Spjd goto out; 1199148456Spjd } 1200148456Spjd provfd = open(prov, O_WRONLY); 1201148456Spjd if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1202148456Spjd char devprov[MAXPATHLEN]; 1203148456Spjd 1204148456Spjd snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1205148456Spjd provfd = open(devprov, O_WRONLY); 1206148456Spjd } 1207148456Spjd if (provfd == -1) { 1208148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1209169193Spjd goto out; 1210148456Spjd } 1211148456Spjd 1212148456Spjd mediasize = g_get_mediasize(prov); 1213148456Spjd secsize = g_get_sectorsize(prov); 1214148456Spjd if (mediasize == 0 || secsize == 0) { 1215148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 1216148456Spjd strerror(errno)); 1217169193Spjd goto out; 1218148456Spjd } 1219148456Spjd 1220148456Spjd sector = malloc(secsize); 1221148456Spjd if (sector == NULL) { 1222148456Spjd gctl_error(req, "Cannot allocate memory."); 1223169193Spjd goto out; 1224148456Spjd } 1225148456Spjd 1226148456Spjd /* Read metadata from the backup file. */ 1227148456Spjd if (read(filefd, sector, secsize) != (ssize_t)secsize) { 1228148456Spjd gctl_error(req, "Cannot read from %s: %s.", file, 1229148456Spjd strerror(errno)); 1230148456Spjd goto out; 1231148456Spjd } 1232148456Spjd /* Check if this file contains geli metadata. */ 1233148456Spjd if (eli_metadata_decode(sector, &md) != 0) { 1234148456Spjd gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); 1235148456Spjd goto out; 1236148456Spjd } 1237212934Sbrian /* Check if the provider size has changed since we did the backup. */ 1238212934Sbrian if (md.md_provsize != (uint64_t)mediasize) { 1239212934Sbrian if (gctl_get_int(req, "force")) { 1240212934Sbrian md.md_provsize = mediasize; 1241212934Sbrian eli_metadata_encode(&md, sector); 1242212934Sbrian } else { 1243212934Sbrian gctl_error(req, "Provider size mismatch: " 1244212934Sbrian "wrong backup file?"); 1245212934Sbrian goto out; 1246212934Sbrian } 1247212934Sbrian } 1248162356Spjd /* Write metadata from the provider. */ 1249148456Spjd if (pwrite(provfd, sector, secsize, mediasize - secsize) != 1250148456Spjd (ssize_t)secsize) { 1251148456Spjd gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1252148456Spjd goto out; 1253148456Spjd } 1254148456Spjdout: 1255148456Spjd if (provfd > 0) 1256148456Spjd close(provfd); 1257148456Spjd if (filefd > 0) 1258148456Spjd close(filefd); 1259148456Spjd if (sector != NULL) { 1260148456Spjd bzero(sector, secsize); 1261148456Spjd free(sector); 1262148456Spjd } 1263148456Spjd} 1264148456Spjd 1265148456Spjdstatic void 1266212934Sbrianeli_resize(struct gctl_req *req) 1267212934Sbrian{ 1268212934Sbrian struct g_eli_metadata md; 1269212934Sbrian const char *prov; 1270212934Sbrian unsigned char *sector; 1271213056Spjd ssize_t secsize; 1272212934Sbrian off_t mediasize, oldsize; 1273212934Sbrian int nargs, provfd; 1274212934Sbrian 1275212934Sbrian nargs = gctl_get_int(req, "nargs"); 1276212934Sbrian if (nargs != 1) { 1277212934Sbrian gctl_error(req, "Invalid number of arguments."); 1278212934Sbrian return; 1279212934Sbrian } 1280212934Sbrian prov = gctl_get_ascii(req, "arg0"); 1281212934Sbrian 1282212934Sbrian provfd = -1; 1283212934Sbrian sector = NULL; 1284212934Sbrian secsize = 0; 1285212934Sbrian 1286213056Spjd provfd = g_open(prov, 1); 1287212934Sbrian if (provfd == -1) { 1288212934Sbrian gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1289212934Sbrian goto out; 1290212934Sbrian } 1291212934Sbrian 1292213056Spjd mediasize = g_mediasize(provfd); 1293213056Spjd secsize = g_sectorsize(provfd); 1294213056Spjd if (mediasize == -1 || secsize == -1) { 1295212934Sbrian gctl_error(req, "Cannot get information about %s: %s.", prov, 1296212934Sbrian strerror(errno)); 1297212934Sbrian goto out; 1298212934Sbrian } 1299212934Sbrian 1300212934Sbrian sector = malloc(secsize); 1301212934Sbrian if (sector == NULL) { 1302212934Sbrian gctl_error(req, "Cannot allocate memory."); 1303212934Sbrian goto out; 1304212934Sbrian } 1305212934Sbrian 1306212934Sbrian oldsize = gctl_get_intmax(req, "oldsize"); 1307212934Sbrian if (oldsize < 0 || oldsize > mediasize) { 1308212934Sbrian gctl_error(req, "Invalid oldsize: Out of range."); 1309212934Sbrian goto out; 1310212934Sbrian } 1311212934Sbrian 1312212934Sbrian /* Read metadata from the 'oldsize' offset. */ 1313213056Spjd if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) { 1314212934Sbrian gctl_error(req, "Cannot read old metadata: %s.", 1315212934Sbrian strerror(errno)); 1316212934Sbrian goto out; 1317212934Sbrian } 1318212934Sbrian 1319212934Sbrian /* Check if this sector contains geli metadata. */ 1320212934Sbrian if (eli_metadata_decode(sector, &md) != 0) { 1321212934Sbrian gctl_error(req, "MD5 hash mismatch: no metadata for oldsize."); 1322212934Sbrian goto out; 1323212934Sbrian } 1324212934Sbrian 1325212934Sbrian /* 1326212934Sbrian * If the old metadata doesn't have a correct provider size, refuse 1327212934Sbrian * to resize. 1328212934Sbrian */ 1329212934Sbrian if (md.md_provsize != (uint64_t)oldsize) { 1330212934Sbrian gctl_error(req, "Provider size mismatch at oldsize."); 1331212934Sbrian goto out; 1332212934Sbrian } 1333212934Sbrian 1334212934Sbrian /* 1335212934Sbrian * Update the old metadata with the current provider size and write 1336212934Sbrian * it back to the correct place on the provider. 1337212934Sbrian */ 1338212934Sbrian md.md_provsize = mediasize; 1339212934Sbrian eli_metadata_encode(&md, sector); 1340213056Spjd if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) { 1341212934Sbrian gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1342212934Sbrian goto out; 1343212934Sbrian } 1344212934Sbrian 1345212934Sbrian /* Now trash the old metadata. */ 1346212934Sbrian arc4rand(sector, secsize); 1347213056Spjd if (pwrite(provfd, sector, secsize, oldsize - secsize) != secsize) { 1348212934Sbrian gctl_error(req, "Failed to clobber old metadata: %s.", 1349212934Sbrian strerror(errno)); 1350212934Sbrian goto out; 1351212934Sbrian } 1352212934Sbrianout: 1353213056Spjd if (provfd >= 0) 1354213056Spjd (void)g_close(provfd); 1355212934Sbrian if (sector != NULL) { 1356212934Sbrian bzero(sector, secsize); 1357212934Sbrian free(sector); 1358212934Sbrian } 1359212934Sbrian} 1360212934Sbrian 1361212934Sbrianstatic void 1362148456Spjdeli_clear(struct gctl_req *req) 1363148456Spjd{ 1364148456Spjd const char *name; 1365153190Spjd int error, i, nargs; 1366148456Spjd 1367153190Spjd nargs = gctl_get_int(req, "nargs"); 1368153190Spjd if (nargs < 1) { 1369148456Spjd gctl_error(req, "Too few arguments."); 1370148456Spjd return; 1371148456Spjd } 1372148456Spjd 1373153190Spjd for (i = 0; i < nargs; i++) { 1374153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1375148456Spjd error = g_metadata_clear(name, G_ELI_MAGIC); 1376148456Spjd if (error != 0) { 1377148456Spjd fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1378148456Spjd name, strerror(error)); 1379148456Spjd gctl_error(req, "Not fully done."); 1380148456Spjd continue; 1381148456Spjd } 1382148456Spjd if (verbose) 1383155175Spjd printf("Metadata cleared on %s.\n", name); 1384148456Spjd } 1385148456Spjd} 1386148456Spjd 1387148456Spjdstatic void 1388148456Spjdeli_dump(struct gctl_req *req) 1389148456Spjd{ 1390148456Spjd struct g_eli_metadata md, tmpmd; 1391148456Spjd const char *name; 1392153190Spjd int error, i, nargs; 1393148456Spjd 1394153190Spjd nargs = gctl_get_int(req, "nargs"); 1395153190Spjd if (nargs < 1) { 1396148456Spjd gctl_error(req, "Too few arguments."); 1397148456Spjd return; 1398148456Spjd } 1399148456Spjd 1400153190Spjd for (i = 0; i < nargs; i++) { 1401153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1402148456Spjd error = g_metadata_read(name, (unsigned char *)&tmpmd, 1403148456Spjd sizeof(tmpmd), G_ELI_MAGIC); 1404148456Spjd if (error != 0) { 1405148456Spjd fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1406148456Spjd name, strerror(error)); 1407148456Spjd gctl_error(req, "Not fully done."); 1408148456Spjd continue; 1409148456Spjd } 1410148456Spjd if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1411148456Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1412148456Spjd name); 1413148456Spjd gctl_error(req, "Not fully done."); 1414148456Spjd continue; 1415148456Spjd } 1416148456Spjd printf("Metadata on %s:\n", name); 1417148456Spjd eli_metadata_dump(&md); 1418148456Spjd printf("\n"); 1419148456Spjd } 1420148456Spjd} 1421