1*2b5fc845Sjsing /* $OpenBSD: bioctl.c,v 1.104 2011/12/31 17:06:09 jsing Exp $ */ 2cf6503d7Sderaadt 33af9de98Smarco /* 42f39728eSdlg * Copyright (c) 2004, 2005 Marco Peereboom 53af9de98Smarco * All rights reserved. 63af9de98Smarco * 73af9de98Smarco * Redistribution and use in source and binary forms, with or without 83af9de98Smarco * modification, are permitted provided that the following conditions 93af9de98Smarco * are met: 103af9de98Smarco * 1. Redistributions of source code must retain the above copyright 113af9de98Smarco * notice, this list of conditions and the following disclaimer. 123af9de98Smarco * 2. Redistributions in binary form must reproduce the above copyright 133af9de98Smarco * notice, this list of conditions and the following disclaimer in the 143af9de98Smarco * documentation and/or other materials provided with the distribution. 153af9de98Smarco * 163af9de98Smarco * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 173af9de98Smarco * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 183af9de98Smarco * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 193af9de98Smarco * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 203af9de98Smarco * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 213af9de98Smarco * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 223af9de98Smarco * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 233af9de98Smarco * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 243af9de98Smarco * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 253af9de98Smarco * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 263af9de98Smarco * SUCH DAMAGE. 273af9de98Smarco * 283af9de98Smarco */ 293af9de98Smarco 30c2126c9aSmarco #include <sys/ioctl.h> 3191f4f7d8Sdlg #include <sys/dkio.h> 32c2126c9aSmarco #include <sys/param.h> 3346bc198bSmarco #include <sys/types.h> 3446bc198bSmarco #include <sys/stat.h> 353af9de98Smarco #include <dev/biovar.h> 36aef7fe28Shshoexer #include <dev/softraidvar.h> 373af9de98Smarco 38db2730c1Smarco #include <errno.h> 39db2730c1Smarco #include <err.h> 40db2730c1Smarco #include <fcntl.h> 418ccdd032Sderaadt #include <util.h> 42db2730c1Smarco #include <stdio.h> 43db2730c1Smarco #include <stdlib.h> 44db2730c1Smarco #include <string.h> 45db2730c1Smarco #include <unistd.h> 46e4e14ad7Sderaadt #include <ctype.h> 4703b2dfbfShenning #include <vis.h> 489e8c6f5bShshoexer #include <readpassphrase.h> 49db2730c1Smarco 505c1f8f6bSdjm #include "pbkdf2.h" 51aef7fe28Shshoexer 526de960dcSmarco struct locator { 536de960dcSmarco int channel; 546de960dcSmarco int target; 556de960dcSmarco int lun; 566de960dcSmarco }; 576de960dcSmarco 588ccdd032Sderaadt void usage(void); 5941eccc89Sderaadt const char *str2locator(const char *, struct locator *); 608ccdd032Sderaadt void cleanup(void); 6146bc198bSmarco int bio_parse_devlist(char *, dev_t *); 62aef7fe28Shshoexer void bio_kdf_derive(struct sr_crypto_kdfinfo *, 63c6446370Sjsing struct sr_crypto_kdf_pbkdf2 *, char *, int); 64aef7fe28Shshoexer void bio_kdf_generate(struct sr_crypto_kdfinfo *); 659e8c6f5bShshoexer void derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *, 66c6446370Sjsing size_t, char *, int); 678ccdd032Sderaadt 688ccdd032Sderaadt void bio_inq(char *); 698ccdd032Sderaadt void bio_alarm(char *); 70a15048bbSmarco int bio_getvolbyname(char *); 71a15048bbSmarco void bio_setstate(char *, int, char *); 72a928c459Sderaadt void bio_setblink(char *, char *, int); 73a928c459Sderaadt void bio_blink(char *, int, int); 74d4722c44Snicm struct sr_aoe_config *create_aoe(u_int16_t, char *); 750054cd36Sjsing void bio_createraid(u_int16_t, char *, char *); 76c7c3e8aaSmarco void bio_deleteraid(char *); 77c6446370Sjsing void bio_changepass(char *); 78e8a57fdeSmarco u_int32_t bio_createflags(char *); 7903b2dfbfShenning char *bio_vis(char *); 8003b2dfbfShenning void bio_diskinq(char *); 813af9de98Smarco 823af9de98Smarco int devh = -1; 83abe9d68eSderaadt int human; 84abe9d68eSderaadt int verbose; 85e8a57fdeSmarco u_int32_t cflags = 0; 86aedd4f07Sdjm int rflag = 8192; 8786735da2Smarco char *password; 883af9de98Smarco 893af9de98Smarco struct bio_locate bl; 90b96c6ce2Sckuethe int rpp_flag = RPP_REQUIRE_TTY; 913af9de98Smarco 923af9de98Smarco int 933af9de98Smarco main(int argc, char *argv[]) 943af9de98Smarco { 953af9de98Smarco extern char *optarg; 96db2730c1Smarco u_int64_t func = 0; 97db2730c1Smarco /* u_int64_t subfunc = 0; */ 98e63d8b1dSdtucker char *devicename = NULL; 99cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 1007195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 1010054cd36Sjsing char *key_disk = NULL; 102aedd4f07Sdjm const char *errstr; 103c6446370Sjsing int ch, rv, blink = 0, changepass = 0, diskinq = 0; 104c6446370Sjsing int ss_func = 0; 1059ecba717Sderaadt u_int16_t cr_level = 0; 106e37c64dbSjsing int biodev = 0; 1073af9de98Smarco 1083af9de98Smarco if (argc < 2) 1093af9de98Smarco usage(); 1103af9de98Smarco 111b96c6ce2Sckuethe while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:Pp:qr:R:svu:")) != 112c6446370Sjsing -1) { 1133af9de98Smarco switch (ch) { 114edfd9792Smarco case 'a': /* alarm */ 115edfd9792Smarco func |= BIOC_ALARM; 116edfd9792Smarco al_arg = optarg; 117edfd9792Smarco break; 118c55617f1Sdlg case 'b': /* blink */ 119c55617f1Sdlg func |= BIOC_BLINK; 120a928c459Sderaadt blink = BIOC_SBBLINK; 121a928c459Sderaadt bl_arg = optarg; 122a928c459Sderaadt break; 123e8a57fdeSmarco case 'C': /* creation flags */ 124e8a57fdeSmarco cflags = bio_createflags(optarg); 125e8a57fdeSmarco break; 1267195049bSmarco case 'c': /* create */ 1277195049bSmarco func |= BIOC_CREATERAID; 12892d21b5cStedu if (isdigit(*optarg)) { 12992d21b5cStedu cr_level = strtonum(optarg, 0, 10, &errstr); 13092d21b5cStedu if (errstr != NULL) 13192d21b5cStedu errx(1, "Invalid RAID level"); 13292d21b5cStedu } else 13398b750e4Stedu cr_level = *optarg; 1347195049bSmarco break; 135c7c3e8aaSmarco case 'd': 136c7c3e8aaSmarco /* delete volume */ 137c7c3e8aaSmarco func |= BIOC_DELETERAID; 138c7c3e8aaSmarco break; 139a928c459Sderaadt case 'u': /* unblink */ 140a928c459Sderaadt func |= BIOC_BLINK; 141a928c459Sderaadt blink = BIOC_SBUNBLINK; 142c55617f1Sdlg bl_arg = optarg; 143c55617f1Sdlg break; 1446de960dcSmarco case 'H': /* set hotspare */ 1456de960dcSmarco func |= BIOC_SETSTATE; 146a15048bbSmarco ss_func = BIOC_SSHOTSPARE; 1476de960dcSmarco al_arg = optarg; 1486de960dcSmarco break; 1498ccdd032Sderaadt case 'h': 1508ccdd032Sderaadt human = 1; 1518ccdd032Sderaadt break; 152db2730c1Smarco case 'i': /* inquiry */ 153db2730c1Smarco func |= BIOC_INQ; 1543af9de98Smarco break; 1550054cd36Sjsing case 'k': /* Key disk. */ 1560054cd36Sjsing key_disk = optarg; 1570054cd36Sjsing break; 1587195049bSmarco case 'l': /* device list */ 1597195049bSmarco func |= BIOC_DEVLIST; 1607195049bSmarco dev_list = optarg; 1617195049bSmarco break; 162c6446370Sjsing case 'P': 163c6446370Sjsing /* Change passphrase. */ 164c6446370Sjsing changepass = 1; 165c6446370Sjsing break; 16686735da2Smarco case 'p': 16786735da2Smarco password = optarg; 16886735da2Smarco break; 169aedd4f07Sdjm case 'r': 170aedd4f07Sdjm rflag = strtonum(optarg, 1000, 1<<30, &errstr); 171aedd4f07Sdjm if (errstr != NULL) 172aedd4f07Sdjm errx(1, "Number of rounds is %s: %s", 173aedd4f07Sdjm errstr, optarg); 174aedd4f07Sdjm break; 175a15048bbSmarco case 'R': 176a15048bbSmarco /* rebuild to provided chunk/CTL */ 177a15048bbSmarco func |= BIOC_SETSTATE; 178a15048bbSmarco ss_func = BIOC_SSREBUILD; 179a15048bbSmarco al_arg = optarg; 180a15048bbSmarco break; 181b96c6ce2Sckuethe case 's': 182b96c6ce2Sckuethe rpp_flag = RPP_STDIN; 183b96c6ce2Sckuethe break; 184abe9d68eSderaadt case 'v': 185abe9d68eSderaadt verbose = 1; 186abe9d68eSderaadt break; 18703b2dfbfShenning case 'q': 18803b2dfbfShenning diskinq = 1; 18903b2dfbfShenning break; 1903af9de98Smarco default: 1913af9de98Smarco usage(); 1923af9de98Smarco /* NOTREACHED */ 1933af9de98Smarco } 1943af9de98Smarco } 195cf6503d7Sderaadt argc -= optind; 196cf6503d7Sderaadt argv += optind; 1973af9de98Smarco 198c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 199cf6503d7Sderaadt usage(); 200cf6503d7Sderaadt 201dcbaf4c8Sderaadt if (func == 0) 202dcbaf4c8Sderaadt func |= BIOC_INQ; 203dcbaf4c8Sderaadt 204e63d8b1dSdtucker devicename = argv[0]; 205e63d8b1dSdtucker if (devicename == NULL) 206e37c64dbSjsing errx(1, "need device"); 20710b411a7Smarco 208e63d8b1dSdtucker devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname); 209e37c64dbSjsing if (devh == -1) { 21041eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2113af9de98Smarco if (devh == -1) 21241eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2133af9de98Smarco 214e63d8b1dSdtucker bl.bl_name = devicename; 2153af9de98Smarco rv = ioctl(devh, BIOCLOCATE, &bl); 2163af9de98Smarco if (rv == -1) 21710b411a7Smarco errx(1, "Can't locate %s device via %s", 21841eccc89Sderaadt bl.bl_name, "/dev/bio"); 219e37c64dbSjsing biodev = 1; 220e63d8b1dSdtucker devicename = NULL; 221e37c64dbSjsing } 2223af9de98Smarco 22303b2dfbfShenning if (diskinq) { 224e63d8b1dSdtucker bio_diskinq(devicename); 225e37c64dbSjsing } else if (changepass && !biodev) { 226e63d8b1dSdtucker bio_changepass(devicename); 22703b2dfbfShenning } else if (func & BIOC_INQ) { 228e63d8b1dSdtucker bio_inq(devicename); 229edfd9792Smarco } else if (func == BIOC_ALARM) { 230edfd9792Smarco bio_alarm(al_arg); 231c55617f1Sdlg } else if (func == BIOC_BLINK) { 232e63d8b1dSdtucker bio_setblink(devicename, bl_arg, blink); 2336de960dcSmarco } else if (func == BIOC_SETSTATE) { 234a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 235e37c64dbSjsing } else if (func == BIOC_DELETERAID && !biodev) { 236e63d8b1dSdtucker bio_deleteraid(devicename); 2377195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2387195049bSmarco if (!(func & BIOC_CREATERAID)) 2397195049bSmarco errx(1, "need -c parameter"); 2407195049bSmarco if (!(func & BIOC_DEVLIST)) 2417195049bSmarco errx(1, "need -l parameter"); 242e37c64dbSjsing if (!biodev) 243e37c64dbSjsing errx(1, "must use bio device"); 2440054cd36Sjsing bio_createraid(cr_level, dev_list, key_disk); 2453af9de98Smarco } 2463af9de98Smarco 2473af9de98Smarco return (0); 2483af9de98Smarco } 2493af9de98Smarco 2503af9de98Smarco void 2513af9de98Smarco usage(void) 2523af9de98Smarco { 2533af9de98Smarco extern char *__progname; 2543af9de98Smarco 255d90b5d8bSjmc fprintf(stderr, 256d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 257d90b5d8bSjmc "[-b channel:target[.lun]]\n" 258d0b772c8Sjmc "\t[-H channel:target[.lun]] " 259af56bbe7Smatthieu "[-R device | channel:target[.lun]]\n" 260d0b772c8Sjmc "\t[-u channel:target[.lun]] " 261d0b772c8Sjmc "device\n" 262b96c6ce2Sckuethe " %s [-dhiPqsv] " 263b90fdff5Sjmc "[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n" 26478702060Sjmc "\t[-l special[,special,...]] [-p passfile]\n" 265af56bbe7Smatthieu "\t[-R device | channel:target[.lun]] [-r rounds] " 266d0b772c8Sjmc "device\n", __progname, __progname); 267d90b5d8bSjmc 2683af9de98Smarco exit(1); 2693af9de98Smarco } 2703af9de98Smarco 27141eccc89Sderaadt const char * 2726de960dcSmarco str2locator(const char *string, struct locator *location) 2736de960dcSmarco { 27450d3c4dcSdlg const char *errstr; 27541eccc89Sderaadt char parse[80], *targ, *lun; 2766de960dcSmarco 27741eccc89Sderaadt strlcpy(parse, string, sizeof parse); 27841eccc89Sderaadt targ = strchr(parse, ':'); 2796de960dcSmarco if (targ == NULL) 28041eccc89Sderaadt return ("target not specified"); 2816de960dcSmarco *targ++ = '\0'; 2826de960dcSmarco 28350d3c4dcSdlg lun = strchr(targ, '.'); 2846de960dcSmarco if (lun != NULL) { 2856de960dcSmarco *lun++ = '\0'; 28650d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 28750d3c4dcSdlg if (errstr) 28841eccc89Sderaadt return (errstr); 2896de960dcSmarco } else 2906de960dcSmarco location->lun = 0; 2916de960dcSmarco 29250d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 29350d3c4dcSdlg if (errstr) 29441eccc89Sderaadt return (errstr); 29541eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 29650d3c4dcSdlg if (errstr) 29741eccc89Sderaadt return (errstr); 29841eccc89Sderaadt return (NULL); 2996de960dcSmarco } 3006de960dcSmarco 3013af9de98Smarco void 3028ccdd032Sderaadt bio_inq(char *name) 303d4546a56Sdlg { 3049017fb97Sderaadt char *status, size[64], scsiname[16], volname[32]; 305a4d3c4a2Sderaadt char percent[10], seconds[20]; 306b9950701Smarco int rv, i, d, volheader, hotspare, unused; 307aa65acf1Sderaadt char encname[16], serial[32]; 3088ccdd032Sderaadt struct bioc_disk bd; 3098ccdd032Sderaadt struct bioc_inq bi; 3108ccdd032Sderaadt struct bioc_vol bv; 311db2730c1Smarco 312db2730c1Smarco memset(&bi, 0, sizeof(bi)); 3133af9de98Smarco 3148ccdd032Sderaadt bi.bi_cookie = bl.bl_cookie; 3153af9de98Smarco 316db2730c1Smarco rv = ioctl(devh, BIOCINQ, &bi); 3173af9de98Smarco if (rv == -1) { 31803b2dfbfShenning if (errno == ENOTTY) 31903b2dfbfShenning bio_diskinq(name); 32003b2dfbfShenning else 321da3b0664Shenning err(1, "BIOCINQ"); 3223af9de98Smarco return; 3233af9de98Smarco } 3243af9de98Smarco 3258ccdd032Sderaadt volheader = 0; 3268ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 327db2730c1Smarco memset(&bv, 0, sizeof(bv)); 3288ccdd032Sderaadt bv.bv_cookie = bl.bl_cookie; 3298ccdd032Sderaadt bv.bv_volid = i; 3300a92ff65Sderaadt bv.bv_percent = -1; 3319017fb97Sderaadt bv.bv_seconds = 0; 33270a2ae7bSmarco 333db2730c1Smarco rv = ioctl(devh, BIOCVOL, &bv); 334da3b0664Shenning if (rv == -1) 335da3b0664Shenning err(1, "BIOCVOL"); 3363af9de98Smarco 3378ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 3388ccdd032Sderaadt continue; 3398ccdd032Sderaadt 3408ccdd032Sderaadt if (!volheader) { 3418ccdd032Sderaadt volheader = 1; 342150c22bbSjcs printf("%-11s %-10s %14s %-8s\n", 3438ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 3448ccdd032Sderaadt } 3458ccdd032Sderaadt 3460a92ff65Sderaadt percent[0] = '\0'; 3479017fb97Sderaadt seconds[0] = '\0'; 3480a92ff65Sderaadt if (bv.bv_percent != -1) 3490a92ff65Sderaadt snprintf(percent, sizeof percent, 3500a92ff65Sderaadt " %d%% done", bv.bv_percent); 3519017fb97Sderaadt if (bv.bv_seconds) 3529017fb97Sderaadt snprintf(seconds, sizeof seconds, 3539017fb97Sderaadt " %u seconds", bv.bv_seconds); 3548ccdd032Sderaadt switch (bv.bv_status) { 355db2730c1Smarco case BIOC_SVONLINE: 3568ccdd032Sderaadt status = BIOC_SVONLINE_S; 357db2730c1Smarco break; 358db2730c1Smarco case BIOC_SVOFFLINE: 3598ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 360db2730c1Smarco break; 361db2730c1Smarco case BIOC_SVDEGRADED: 3628ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 363db2730c1Smarco break; 3640a92ff65Sderaadt case BIOC_SVBUILDING: 3650a92ff65Sderaadt status = BIOC_SVBUILDING_S; 3660a92ff65Sderaadt break; 3670a92ff65Sderaadt case BIOC_SVREBUILD: 3680a92ff65Sderaadt status = BIOC_SVREBUILD_S; 3690a92ff65Sderaadt break; 3700a92ff65Sderaadt case BIOC_SVSCRUB: 3710a92ff65Sderaadt status = BIOC_SVSCRUB_S; 3720a92ff65Sderaadt break; 373db2730c1Smarco case BIOC_SVINVALID: 374db2730c1Smarco default: 3758ccdd032Sderaadt status = BIOC_SVINVALID_S; 376d4546a56Sdlg } 3773af9de98Smarco 378aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 3798ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 380b9950701Smarco 3819ecba717Sderaadt unused = 0; 3829ecba717Sderaadt hotspare = 0; 383aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 384aa65acf1Sderaadt hotspare = 1; 385b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 386b9950701Smarco unused = 1; 387aa65acf1Sderaadt else { 3888ccdd032Sderaadt if (human) 3898ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 3908ccdd032Sderaadt else 3918ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 3928ccdd032Sderaadt bv.bv_size); 393da935596Stodd switch (bv.bv_level) { 394da935596Stodd case 'C': 395150c22bbSjcs printf("%11s %-10s %14s %-7s CRYPTO%s%s\n", 396da935596Stodd volname, status, size, bv.bv_dev, 397da935596Stodd percent, seconds); 398da935596Stodd break; 399*2b5fc845Sjsing case 'c': 400*2b5fc845Sjsing printf("%11s %-10s %14s %-7s CONCAT%s%s\n", 401*2b5fc845Sjsing volname, status, size, bv.bv_dev, 402*2b5fc845Sjsing percent, seconds); 403*2b5fc845Sjsing break; 404da935596Stodd default: 405150c22bbSjcs printf("%11s %-10s %14s %-7s RAID%u%s%s\n", 4060a92ff65Sderaadt volname, status, size, bv.bv_dev, 4079017fb97Sderaadt bv.bv_level, percent, seconds); 408da935596Stodd break; 409da935596Stodd } 410da935596Stodd 411aa65acf1Sderaadt } 4128ccdd032Sderaadt 4138ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 414db2730c1Smarco memset(&bd, 0, sizeof(bd)); 4158ccdd032Sderaadt bd.bd_cookie = bl.bl_cookie; 4168ccdd032Sderaadt bd.bd_diskid = d; 4178ccdd032Sderaadt bd.bd_volid = i; 4183af9de98Smarco 419db2730c1Smarco rv = ioctl(devh, BIOCDISK, &bd); 420da3b0664Shenning if (rv == -1) 421da3b0664Shenning err(1, "BIOCDISK"); 4223af9de98Smarco 4238ccdd032Sderaadt switch (bd.bd_status) { 424db2730c1Smarco case BIOC_SDONLINE: 4258ccdd032Sderaadt status = BIOC_SDONLINE_S; 426d4546a56Sdlg break; 427db2730c1Smarco case BIOC_SDOFFLINE: 4288ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 429d4546a56Sdlg break; 430db2730c1Smarco case BIOC_SDFAILED: 4318ccdd032Sderaadt status = BIOC_SDFAILED_S; 432db2730c1Smarco break; 433db2730c1Smarco case BIOC_SDREBUILD: 4348ccdd032Sderaadt status = BIOC_SDREBUILD_S; 435db2730c1Smarco break; 436db2730c1Smarco case BIOC_SDHOTSPARE: 4378ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 438db2730c1Smarco break; 439db2730c1Smarco case BIOC_SDUNUSED: 4408ccdd032Sderaadt status = BIOC_SDUNUSED_S; 441db2730c1Smarco break; 442e1dfb373Sderaadt case BIOC_SDSCRUB: 443e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 444e1dfb373Sderaadt break; 445db2730c1Smarco case BIOC_SDINVALID: 446d4546a56Sdlg default: 4478ccdd032Sderaadt status = BIOC_SDINVALID_S; 448d4546a56Sdlg } 449aa65acf1Sderaadt 450b9950701Smarco if (hotspare || unused) 451aa65acf1Sderaadt ; /* use volname from parent volume */ 452aa65acf1Sderaadt else 453aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 454aa65acf1Sderaadt bd.bd_diskid); 455aa65acf1Sderaadt 4560054cd36Sjsing if (bv.bv_level == 'C' && bd.bd_size == 0) 4570054cd36Sjsing snprintf(size, sizeof size, "%14s", "key disk"); 4580054cd36Sjsing else if (human) 4598ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 4608ccdd032Sderaadt else 4618ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4628ccdd032Sderaadt bd.bd_size); 4638ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 46443d61178Sderaadt "%u:%u.%u", 46543d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 4665978b28dSderaadt if (bd.bd_procdev[0]) 467abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 4685978b28dSderaadt else 469abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 470abe9d68eSderaadt if (bd.bd_serial[0]) 471abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 472abe9d68eSderaadt else 473abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 4748ccdd032Sderaadt 475150c22bbSjcs printf("%11s %-10s %14s %-7s %-6s <%s>\n", 476aa65acf1Sderaadt volname, status, size, scsiname, encname, 4778ccdd032Sderaadt bd.bd_vendor); 478abe9d68eSderaadt if (verbose) 479aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s '%s'\n", 480abe9d68eSderaadt "", "", "", "", "", serial); 481d4546a56Sdlg } 482d4546a56Sdlg } 483d4546a56Sdlg } 484edfd9792Smarco 485edfd9792Smarco void 486edfd9792Smarco bio_alarm(char *arg) 487edfd9792Smarco { 488edfd9792Smarco int rv; 4898ccdd032Sderaadt struct bioc_alarm ba; 490edfd9792Smarco 4918ccdd032Sderaadt ba.ba_cookie = bl.bl_cookie; 492edfd9792Smarco 493edfd9792Smarco switch (arg[0]) { 494edfd9792Smarco case 'q': /* silence alarm */ 495edfd9792Smarco /* FALLTHROUGH */ 496edfd9792Smarco case 's': 4978ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 498edfd9792Smarco break; 499edfd9792Smarco 500edfd9792Smarco case 'e': /* enable alarm */ 5018ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 502edfd9792Smarco break; 503edfd9792Smarco 504edfd9792Smarco case 'd': /* disable alarm */ 5058ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 506edfd9792Smarco break; 507edfd9792Smarco 508edfd9792Smarco case 't': /* test alarm */ 5098ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 510edfd9792Smarco break; 511edfd9792Smarco 512edfd9792Smarco case 'g': /* get alarm state */ 5138ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 514edfd9792Smarco break; 515edfd9792Smarco 516edfd9792Smarco default: 517da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 518edfd9792Smarco } 519edfd9792Smarco 520edfd9792Smarco rv = ioctl(devh, BIOCALARM, &ba); 521da3b0664Shenning if (rv == -1) 522da3b0664Shenning err(1, "BIOCALARM"); 523edfd9792Smarco 524edfd9792Smarco if (arg[0] == 'g') { 525edfd9792Smarco printf("alarm is currently %s\n", 5268ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 5278ccdd032Sderaadt 528edfd9792Smarco } 529edfd9792Smarco } 5306de960dcSmarco 531a15048bbSmarco int 532a15048bbSmarco bio_getvolbyname(char *name) 533a15048bbSmarco { 534a15048bbSmarco int id = -1, i, rv; 535a15048bbSmarco struct bioc_inq bi; 536a15048bbSmarco struct bioc_vol bv; 537a15048bbSmarco 538a15048bbSmarco memset(&bi, 0, sizeof(bi)); 539a15048bbSmarco bi.bi_cookie = bl.bl_cookie; 540a15048bbSmarco rv = ioctl(devh, BIOCINQ, &bi); 541a15048bbSmarco if (rv == -1) 542a15048bbSmarco err(1, "BIOCINQ"); 543a15048bbSmarco 544a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 545a15048bbSmarco memset(&bv, 0, sizeof(bv)); 546a15048bbSmarco bv.bv_cookie = bl.bl_cookie; 547a15048bbSmarco bv.bv_volid = i; 548a15048bbSmarco rv = ioctl(devh, BIOCVOL, &bv); 549a15048bbSmarco if (rv == -1) 550a15048bbSmarco err(1, "BIOCVOL"); 551a15048bbSmarco 552a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 553a15048bbSmarco continue; 554a15048bbSmarco id = i; 555a15048bbSmarco break; 556a15048bbSmarco } 557a15048bbSmarco 558a15048bbSmarco return (id); 559a15048bbSmarco } 560a15048bbSmarco 561ebaf584eSderaadt void 5628d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 5636de960dcSmarco { 5646de960dcSmarco struct bioc_setstate bs; 5656de960dcSmarco struct locator location; 566a15048bbSmarco struct stat sb; 56741eccc89Sderaadt const char *errstr; 568ebaf584eSderaadt int rv; 5696de960dcSmarco 570a15048bbSmarco memset(&bs, 0, sizeof(bs)); 571a15048bbSmarco if (stat(arg, &sb) == -1) { 572a15048bbSmarco /* use CTL */ 57341eccc89Sderaadt errstr = str2locator(arg, &location); 57441eccc89Sderaadt if (errstr) 57541eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 5766de960dcSmarco bs.bs_channel = location.channel; 5776de960dcSmarco bs.bs_target = location.target; 5786de960dcSmarco bs.bs_lun = location.lun; 579a15048bbSmarco } else { 580a15048bbSmarco /* use other id */ 581a15048bbSmarco bs.bs_other_id = sb.st_rdev; 582a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 583a15048bbSmarco } 584a15048bbSmarco 585a15048bbSmarco bs.bs_cookie = bl.bl_cookie; 586a15048bbSmarco bs.bs_status = status; 587a15048bbSmarco 588d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 589a15048bbSmarco /* make sure user supplied a sd device */ 5908d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 591a15048bbSmarco if (bs.bs_volid == -1) 5928d8693a2Sdtucker errx(1, "invalid device %s", devicename); 593d2647ac1Sjsing } 5946de960dcSmarco 5956de960dcSmarco rv = ioctl(devh, BIOCSETSTATE, &bs); 596da3b0664Shenning if (rv == -1) 597da3b0664Shenning err(1, "BIOCSETSTATE"); 5986de960dcSmarco } 599c55617f1Sdlg 600c55617f1Sdlg void 601a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 602c55617f1Sdlg { 60350d3c4dcSdlg struct locator location; 60450d3c4dcSdlg struct bioc_inq bi; 60550d3c4dcSdlg struct bioc_vol bv; 60650d3c4dcSdlg struct bioc_disk bd; 6070505205bSdlg struct bioc_blink bb; 60841eccc89Sderaadt const char *errstr; 60950d3c4dcSdlg int v, d, rv; 610c55617f1Sdlg 61141eccc89Sderaadt errstr = str2locator(arg, &location); 61241eccc89Sderaadt if (errstr) 61341eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 61450d3c4dcSdlg 6150505205bSdlg /* try setting blink on the device directly */ 6160505205bSdlg memset(&bb, 0, sizeof(bb)); 6170505205bSdlg bb.bb_cookie = bl.bl_cookie; 6180505205bSdlg bb.bb_status = blink; 6190505205bSdlg bb.bb_target = location.target; 620649724a4Smarco bb.bb_channel = location.channel; 6210505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 6220505205bSdlg if (rv == 0) 6230505205bSdlg return; 6240505205bSdlg 625855d4e83Ssobrado /* if the blink didn't work, try to find something that will */ 6260505205bSdlg 62750d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 62850d3c4dcSdlg bi.bi_cookie = bl.bl_cookie; 62950d3c4dcSdlg rv = ioctl(devh, BIOCINQ, &bi); 630da3b0664Shenning if (rv == -1) 631da3b0664Shenning err(1, "BIOCINQ"); 63250d3c4dcSdlg 63350d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 63450d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 63550d3c4dcSdlg bv.bv_cookie = bl.bl_cookie; 63650d3c4dcSdlg bv.bv_volid = v; 63750d3c4dcSdlg rv = ioctl(devh, BIOCVOL, &bv); 638da3b0664Shenning if (rv == -1) 639da3b0664Shenning err(1, "BIOCVOL"); 64050d3c4dcSdlg 64150d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 64250d3c4dcSdlg continue; 64350d3c4dcSdlg 64450d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 64550d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 64650d3c4dcSdlg bd.bd_cookie = bl.bl_cookie; 64750d3c4dcSdlg bd.bd_volid = v; 64850d3c4dcSdlg bd.bd_diskid = d; 64950d3c4dcSdlg 65050d3c4dcSdlg rv = ioctl(devh, BIOCDISK, &bd); 651da3b0664Shenning if (rv == -1) 652da3b0664Shenning err(1, "BIOCDISK"); 65350d3c4dcSdlg 65450d3c4dcSdlg if (bd.bd_channel == location.channel && 65550d3c4dcSdlg bd.bd_target == location.target && 65650d3c4dcSdlg bd.bd_lun == location.lun) { 65750d3c4dcSdlg if (bd.bd_procdev[0] != '\0') { 65850d3c4dcSdlg bio_blink(bd.bd_procdev, 659a928c459Sderaadt location.target, blink); 66050d3c4dcSdlg } else 66141eccc89Sderaadt warnx("Disk %s is not in an enclosure", arg); 66250d3c4dcSdlg return; 66350d3c4dcSdlg } 66450d3c4dcSdlg } 66550d3c4dcSdlg } 66650d3c4dcSdlg 66741eccc89Sderaadt warnx("Disk %s does not exist", arg); 66850d3c4dcSdlg return; 66950d3c4dcSdlg } 67050d3c4dcSdlg 67150d3c4dcSdlg void 672a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 67350d3c4dcSdlg { 67450d3c4dcSdlg int bioh; 67550d3c4dcSdlg struct bio_locate bio; 67650d3c4dcSdlg struct bioc_blink blink; 67750d3c4dcSdlg int rv; 67850d3c4dcSdlg 67941eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 68050d3c4dcSdlg if (bioh == -1) 68141eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 68250d3c4dcSdlg 68350d3c4dcSdlg bio.bl_name = enclosure; 68450d3c4dcSdlg rv = ioctl(bioh, BIOCLOCATE, &bio); 68550d3c4dcSdlg if (rv == -1) 68641eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 687c55617f1Sdlg 688c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 68950d3c4dcSdlg blink.bb_cookie = bio.bl_cookie; 690a928c459Sderaadt blink.bb_status = blinktype; 691c55617f1Sdlg blink.bb_target = target; 692c55617f1Sdlg 69350d3c4dcSdlg rv = ioctl(bioh, BIOCBLINK, &blink); 694c55617f1Sdlg if (rv == -1) 695da3b0664Shenning err(1, "BIOCBLINK"); 69650d3c4dcSdlg 69750d3c4dcSdlg close(bioh); 698c55617f1Sdlg } 6997195049bSmarco 700a2fc2d65Stedu struct sr_aoe_config * 701a2fc2d65Stedu create_aoe(u_int16_t level, char *dev_list) 702a2fc2d65Stedu { 703a2fc2d65Stedu static struct sr_aoe_config sac; 704a2fc2d65Stedu char *nic; 705a2fc2d65Stedu char *dsteaddr; 706a2fc2d65Stedu char *shelf; 707a2fc2d65Stedu char *slot; 708a2fc2d65Stedu struct ether_addr *eaddr; 709a2fc2d65Stedu const char *errstr; 710a2fc2d65Stedu 711a2fc2d65Stedu nic = dsteaddr = slot = shelf = 0; 712a2fc2d65Stedu 713a2fc2d65Stedu memset(&sac, 0, sizeof(sac)); 714a2fc2d65Stedu nic = dev_list; 715a2fc2d65Stedu dsteaddr = strchr(nic, ','); 716a2fc2d65Stedu if (!dsteaddr) 717a2fc2d65Stedu goto invalid; 718a2fc2d65Stedu *dsteaddr++ = '\0'; 719a2fc2d65Stedu shelf = strchr(dsteaddr, ','); 720a2fc2d65Stedu if (!shelf) 721a2fc2d65Stedu goto invalid; 722a2fc2d65Stedu *shelf++ = '\0'; 723a2fc2d65Stedu slot = strchr(shelf, ','); 724a2fc2d65Stedu if (!slot) 725a2fc2d65Stedu goto invalid; 726a2fc2d65Stedu *slot++ = '\0'; 727a2fc2d65Stedu strlcpy(sac.nic, nic, sizeof(sac.nic)); 728a2fc2d65Stedu eaddr = ether_aton(dsteaddr); 729a2fc2d65Stedu if (!eaddr) 730a2fc2d65Stedu goto invalid; 731a2fc2d65Stedu sac.dsteaddr = *eaddr; 732a2fc2d65Stedu sac.shelf = htons(strtonum(shelf, 0, 0xfffe, &errstr)); 733a2fc2d65Stedu if (errstr) 734a2fc2d65Stedu goto invalid; 735a2fc2d65Stedu sac.slot = strtonum(slot, 0, 0xfe, &errstr); 736a2fc2d65Stedu if (errstr) 737a2fc2d65Stedu goto invalid; 738a2fc2d65Stedu 739a2fc2d65Stedu return &sac; 740a2fc2d65Stedu invalid: 741a2fc2d65Stedu errx(1, "invalid AOE dev list: use nic,dsteaddr,shelf,slot"); 742a2fc2d65Stedu } 743a2fc2d65Stedu 7447195049bSmarco void 7450054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk) 7467195049bSmarco { 7477195049bSmarco struct bioc_createraid create; 748aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 749aef7fe28Shshoexer struct sr_crypto_kdf_pbkdf2 kdfhint; 750a2fc2d65Stedu struct sr_aoe_config *sac; 7510054cd36Sjsing struct stat sb; 7528b0d0f28Sjsing int rv, no_dev, fd; 7537f8eae2bSnicm dev_t *dt; 7547195049bSmarco u_int16_t min_disks = 0; 7557195049bSmarco 7567195049bSmarco if (!dev_list) 7577195049bSmarco errx(1, "no devices specified"); 7587195049bSmarco 759a2fc2d65Stedu if (level == 'a') { 760a2fc2d65Stedu sac = create_aoe(level, dev_list); 761a2fc2d65Stedu no_dev = 0; 762a2fc2d65Stedu dt = NULL; 763a2fc2d65Stedu } else { 76446bc198bSmarco dt = (dev_t *)malloc(BIOC_CRMAXLEN); 76546bc198bSmarco if (!dt) 76646bc198bSmarco err(1, "not enough memory for dev_t list"); 76746bc198bSmarco memset(dt, 0, BIOC_CRMAXLEN); 76846bc198bSmarco 76946bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 770a2fc2d65Stedu } 77146bc198bSmarco 7727195049bSmarco switch (level) { 7737195049bSmarco case 0: 77484e48fabSmarco min_disks = 2; 7757195049bSmarco break; 7767195049bSmarco case 1: 7777195049bSmarco min_disks = 2; 7787195049bSmarco break; 779e717853eSmarco case 4: 780e717853eSmarco case 5: 781e717853eSmarco min_disks = 3; 782e717853eSmarco break; 78384e48fabSmarco case 'C': 784aef7fe28Shshoexer min_disks = 1; 78584e48fabSmarco break; 78698b750e4Stedu case 'c': 78798b750e4Stedu min_disks = 1; 78898b750e4Stedu break; 789a2fc2d65Stedu case 'a': 790a2fc2d65Stedu break; 7917195049bSmarco default: 79223afedbfSgrunk errx(1, "unsupported raid level"); 7937195049bSmarco } 7947195049bSmarco 79584e48fabSmarco if (no_dev < min_disks) 79684e48fabSmarco errx(1, "not enough disks"); 79784e48fabSmarco 798aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 799aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 800818b0595Shalex errx(1, "not exactly one partition"); 801aef7fe28Shshoexer 8027195049bSmarco memset(&create, 0, sizeof(create)); 8037195049bSmarco create.bc_cookie = bl.bl_cookie; 8047195049bSmarco create.bc_level = level; 80546bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 80646bc198bSmarco create.bc_dev_list = dt; 807e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 8080054cd36Sjsing create.bc_key_disk = NODEV; 8097195049bSmarco 810a2fc2d65Stedu if (level == 'a') { 811a2fc2d65Stedu create.bc_opaque = sac; 812a2fc2d65Stedu create.bc_opaque_size = sizeof(*sac); 813a2fc2d65Stedu create.bc_opaque_flags = BIOC_SOIN; 814a2fc2d65Stedu } else if (level == 'C' && key_disk == NULL) { 8150054cd36Sjsing 816aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 817aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 818aef7fe28Shshoexer 8190054cd36Sjsing create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 8200054cd36Sjsing 821aef7fe28Shshoexer create.bc_opaque = &kdfhint; 822aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 823aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 824aef7fe28Shshoexer 825aef7fe28Shshoexer /* try to get KDF hint */ 82683e979edShshoexer if (ioctl(devh, BIOCCREATERAID, &create) == -1) 82783e979edShshoexer err(1, "ioctl"); 82883e979edShshoexer 82983e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 830c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 831aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 832aef7fe28Shshoexer } else { 833aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 834aef7fe28Shshoexer } 835aef7fe28Shshoexer 836aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 837aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 838aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 8390054cd36Sjsing 8400054cd36Sjsing } else if (level == 'C' && key_disk != NULL) { 8410054cd36Sjsing 8428b0d0f28Sjsing /* Get device number for key disk. */ 8438b0d0f28Sjsing fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL); 8448b0d0f28Sjsing if (fd == -1) 8458b0d0f28Sjsing err(1, "could not open %s", key_disk); 8468b0d0f28Sjsing if (fstat(fd, &sb) == -1) { 8478b0d0f28Sjsing close(fd); 8480054cd36Sjsing err(1, "could not stat %s", key_disk); 8498b0d0f28Sjsing } 8508b0d0f28Sjsing close(fd); 8510054cd36Sjsing create.bc_key_disk = sb.st_rdev; 8520054cd36Sjsing 8530054cd36Sjsing memset(&kdfinfo, 0, sizeof(kdfinfo)); 8540054cd36Sjsing 8550054cd36Sjsing kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf); 8560054cd36Sjsing kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK; 8570054cd36Sjsing kdfinfo.len = sizeof(kdfinfo); 8580054cd36Sjsing kdfinfo.flags = SR_CRYPTOKDF_HINT; 8590054cd36Sjsing 8600054cd36Sjsing create.bc_opaque = &kdfinfo; 8610054cd36Sjsing create.bc_opaque_size = sizeof(kdfinfo); 8620054cd36Sjsing create.bc_opaque_flags = BIOC_SOIN; 8630054cd36Sjsing 864aef7fe28Shshoexer } 865aef7fe28Shshoexer 8667195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 867aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 86883e979edShshoexer memset(&create, 0, sizeof(create)); 869a83e4577Sdjm if (rv == -1) { 870a83e4577Sdjm if (errno == EPERM) 871a83e4577Sdjm errx(1, "Incorrect passphrase"); 872da3b0664Shenning err(1, "BIOCCREATERAID"); 873a83e4577Sdjm } 87446bc198bSmarco 87546bc198bSmarco free(dt); 87646bc198bSmarco } 87746bc198bSmarco 878aef7fe28Shshoexer void 879aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 880c6446370Sjsing *kdfhint, char* prompt, int verify) 881aef7fe28Shshoexer { 882aef7fe28Shshoexer if (!kdfinfo) 883aef7fe28Shshoexer errx(1, "invalid KDF info"); 884aef7fe28Shshoexer if (!kdfhint) 885aef7fe28Shshoexer errx(1, "invalid KDF hint"); 886aef7fe28Shshoexer 887aef7fe28Shshoexer if (kdfhint->len != sizeof(*kdfhint)) 888aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 889aef7fe28Shshoexer if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2) 890aef7fe28Shshoexer errx(1, "unknown KDF type %d", kdfhint->type); 891aef7fe28Shshoexer if (kdfhint->rounds < 1000) 892aef7fe28Shshoexer errx(1, "number of KDF rounds too low: %d", kdfhint->rounds); 893aef7fe28Shshoexer 894aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 895aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 896aef7fe28Shshoexer 8979e8c6f5bShshoexer derive_key_pkcs(kdfhint->rounds, 898aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 899c6446370Sjsing kdfhint->salt, sizeof(kdfhint->salt), prompt, verify); 900aef7fe28Shshoexer } 901aef7fe28Shshoexer 902aef7fe28Shshoexer void 903aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 904aef7fe28Shshoexer { 905aef7fe28Shshoexer if (!kdfinfo) 906aef7fe28Shshoexer errx(1, "invalid KDF info"); 907aef7fe28Shshoexer 908aef7fe28Shshoexer kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 909aef7fe28Shshoexer kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 910aedd4f07Sdjm kdfinfo->pbkdf2.rounds = rflag; 911aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 9120054cd36Sjsing kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT; 913aef7fe28Shshoexer 914aef7fe28Shshoexer /* generate salt */ 915aef7fe28Shshoexer arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 916aef7fe28Shshoexer 9179e8c6f5bShshoexer derive_key_pkcs(kdfinfo->pbkdf2.rounds, 918aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 919c6446370Sjsing kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 920c6446370Sjsing "New passphrase: ", 1); 921aef7fe28Shshoexer } 922aef7fe28Shshoexer 92346bc198bSmarco int 92446bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 92546bc198bSmarco { 92646bc198bSmarco char *s, *e; 92746bc198bSmarco u_int32_t sz = 0; 92846bc198bSmarco int no_dev = 0, i, x; 92946bc198bSmarco struct stat sb; 9305c1f8f6bSdjm char dev[MAXPATHLEN]; 931e37c64dbSjsing int fd; 93246bc198bSmarco 93346bc198bSmarco if (!lst) 93446bc198bSmarco errx(1, "invalid device list"); 93546bc198bSmarco 93646bc198bSmarco s = e = lst; 93746bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 93846bc198bSmarco while (*e != '\0') { 93946bc198bSmarco if (*e == ',') 94046bc198bSmarco s = e + 1; 94146bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 94246bc198bSmarco /* got one */ 94346bc198bSmarco sz = e - s + 1; 9445c1f8f6bSdjm strlcpy(dev, s, sz + 1); 945e37c64dbSjsing fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL); 946e37c64dbSjsing if (fd == -1) 947e37c64dbSjsing err(1, "could not open %s", dev); 948e37c64dbSjsing if (fstat(fd, &sb) == -1) { 949e37c64dbSjsing close(fd); 9505c1f8f6bSdjm err(1, "could not stat %s", dev); 951e37c64dbSjsing } 952e37c64dbSjsing close(fd); 95346bc198bSmarco dt[no_dev] = sb.st_rdev; 95446bc198bSmarco no_dev++; 9555c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 95646bc198bSmarco errx(1, "too many devices on device list"); 95746bc198bSmarco } 95846bc198bSmarco e++; 95946bc198bSmarco } 96046bc198bSmarco 96146bc198bSmarco for (i = 0; i < no_dev; i++) 96246bc198bSmarco for (x = 0; x < no_dev; x++) 96346bc198bSmarco if (dt[i] == dt[x] && x != i) 96446bc198bSmarco errx(1, "duplicate device in list"); 96546bc198bSmarco 96646bc198bSmarco return (no_dev); 9677195049bSmarco } 968e8a57fdeSmarco 969e8a57fdeSmarco u_int32_t 970e8a57fdeSmarco bio_createflags(char *lst) 971e8a57fdeSmarco { 972e8a57fdeSmarco char *s, *e, fs[32]; 973e8a57fdeSmarco u_int32_t sz = 0; 974e8a57fdeSmarco u_int32_t flags = 0; 975e8a57fdeSmarco 976e8a57fdeSmarco if (!lst) 977e8a57fdeSmarco errx(1, "invalid flags list"); 978e8a57fdeSmarco 979e8a57fdeSmarco s = e = lst; 980e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 981e8a57fdeSmarco while (*e != '\0') { 982e8a57fdeSmarco if (*e == ',') 983e8a57fdeSmarco s = e + 1; 984e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 985e8a57fdeSmarco /* got one */ 986e8a57fdeSmarco sz = e - s + 1; 987e8a57fdeSmarco switch (s[0]) { 988e8a57fdeSmarco case 'f': 989e8a57fdeSmarco flags |= BIOC_SCFORCE; 990e8a57fdeSmarco break; 991e8a57fdeSmarco case 'n': 992e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 993e8a57fdeSmarco break; 994e8a57fdeSmarco default: 995e8a57fdeSmarco strlcpy(fs, s, sz + 1); 996e8a57fdeSmarco errx(1, "invalid flag %s", fs); 997e8a57fdeSmarco } 998e8a57fdeSmarco } 999e8a57fdeSmarco e++; 1000e8a57fdeSmarco } 1001e8a57fdeSmarco 1002e8a57fdeSmarco return (flags); 1003e8a57fdeSmarco } 100403b2dfbfShenning 1005c7c3e8aaSmarco void 1006c7c3e8aaSmarco bio_deleteraid(char *dev) 1007c7c3e8aaSmarco { 1008c7c3e8aaSmarco struct bioc_deleteraid bd; 1009c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 1010c7c3e8aaSmarco 1011c7c3e8aaSmarco bd.bd_cookie = bd.bd_cookie; 1012a15048bbSmarco /* XXX make this a dev_t instead of a string */ 1013c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 1014c7c3e8aaSmarco if (ioctl(devh, BIOCDELETERAID, &bd)) 1015c7c3e8aaSmarco errx(1, "delete volume %s failed", dev); 1016c7c3e8aaSmarco } 1017c7c3e8aaSmarco 1018c6446370Sjsing void 1019c6446370Sjsing bio_changepass(char *dev) 1020c6446370Sjsing { 1021c6446370Sjsing struct bioc_discipline bd; 1022c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 1023c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 1024c6446370Sjsing struct sr_crypto_kdf_pbkdf2 kdfhint; 1025c6446370Sjsing int rv; 1026c6446370Sjsing 1027c6446370Sjsing memset(&bd, 0, sizeof(bd)); 1028c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 1029c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 1030c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 1031c6446370Sjsing 1032c6446370Sjsing /* XXX use dev_t instead of string. */ 1033c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 1034c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 1035c6446370Sjsing bd.bd_size = sizeof(kdfhint); 1036c6446370Sjsing bd.bd_data = &kdfhint; 1037c6446370Sjsing 1038c6446370Sjsing if (ioctl(devh, BIOCDISCIPLINE, &bd)) 1039c6446370Sjsing errx(1, "%s: failed to get KDF hint", dev); 1040c6446370Sjsing 1041c6446370Sjsing /* Current passphrase. */ 1042c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 1043c6446370Sjsing 1044c6446370Sjsing /* New passphrase. */ 1045c6446370Sjsing bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1); 1046c6446370Sjsing 1047c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 1048c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 1049c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 1050c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 1051c6446370Sjsing 1052c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 1053c6446370Sjsing bd.bd_size = sizeof(kdfpair); 1054c6446370Sjsing bd.bd_data = &kdfpair; 1055c6446370Sjsing 1056c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 1057c6446370Sjsing 1058c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 1059c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 1060c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 1061c6446370Sjsing 1062c6446370Sjsing if (rv) { 1063c6446370Sjsing if (errno == EPERM) 1064c6446370Sjsing errx(1, "%s: incorrect passphrase", dev); 1065c6446370Sjsing else 1066c6446370Sjsing errx(1, "%s: failed to change passphrase", dev); 1067c6446370Sjsing } 1068c6446370Sjsing } 1069c6446370Sjsing 107003b2dfbfShenning #define BIOCTL_VIS_NBUF 4 107103b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 107203b2dfbfShenning 107303b2dfbfShenning char * 107403b2dfbfShenning bio_vis(char *s) 107503b2dfbfShenning { 107603b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 107703b2dfbfShenning static uint idx = 0; 107803b2dfbfShenning char *buf; 107903b2dfbfShenning 108003b2dfbfShenning buf = rbuf[idx++]; 108103b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 108203b2dfbfShenning idx = 0; 108303b2dfbfShenning 108403b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 108503b2dfbfShenning return (buf); 108603b2dfbfShenning } 108703b2dfbfShenning 108803b2dfbfShenning void 108903b2dfbfShenning bio_diskinq(char *sd_dev) 109003b2dfbfShenning { 109103b2dfbfShenning struct dk_inquiry di; 109203b2dfbfShenning 1093da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 1094da3b0664Shenning err(1, "DIOCINQ"); 109503b2dfbfShenning 109603b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 109703b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 109803b2dfbfShenning } 1099aef7fe28Shshoexer 1100aef7fe28Shshoexer void 11019e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt, 1102c6446370Sjsing size_t saltsz, char *prompt, int verify) 1103aef7fe28Shshoexer { 110486735da2Smarco FILE *f; 110586735da2Smarco size_t pl; 110686735da2Smarco struct stat sb; 11079e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 1108aef7fe28Shshoexer 1109aef7fe28Shshoexer if (!key) 1110aef7fe28Shshoexer errx(1, "Invalid key"); 1111aef7fe28Shshoexer if (!salt) 1112aef7fe28Shshoexer errx(1, "Invalid salt"); 1113aef7fe28Shshoexer if (rounds < 1000) 1114b4604b5cShalex errx(1, "Too few rounds: %d", rounds); 1115aef7fe28Shshoexer 1116aef7fe28Shshoexer /* get passphrase */ 1117ba3d8661Smarco if (password && verify) 1118ba3d8661Smarco errx(1, "can't specify passphrase file during initial " 1119ba3d8661Smarco "creation of crypto volume"); 1120ba3d8661Smarco if (password) { 112186735da2Smarco if ((f = fopen(password, "r")) == NULL) 112286735da2Smarco err(1, "invalid passphrase file"); 112386735da2Smarco 112486735da2Smarco if (fstat(fileno(f), &sb) == -1) 112586735da2Smarco err(1, "can't stat passphrase file"); 112686735da2Smarco if (sb.st_uid != 0) 112786735da2Smarco errx(1, "passphrase file must be owned by root"); 112886735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 112986735da2Smarco errx(1, "passphrase file has the wrong permissions"); 113086735da2Smarco 113186735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 113286735da2Smarco err(1, "can't read passphrase file"); 113386735da2Smarco pl = strlen(passphrase); 113486735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 113586735da2Smarco passphrase[pl - 1] = '\0'; 113686735da2Smarco else 113786735da2Smarco errx(1, "invalid passphrase length"); 113886735da2Smarco 113986735da2Smarco fclose(f); 1140ba3d8661Smarco } else { 1141c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1142b96c6ce2Sckuethe rpp_flag) == NULL) 11439e8c6f5bShshoexer errx(1, "unable to read passphrase"); 1144ba3d8661Smarco } 11459e8c6f5bShshoexer 11469e8c6f5bShshoexer if (verify) { 11479e8c6f5bShshoexer /* request user to re-type it */ 11489e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 1149b96c6ce2Sckuethe sizeof(verifybuf), rpp_flag) == NULL) { 11509e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 11519e8c6f5bShshoexer errx(1, "unable to read passphrase"); 11529e8c6f5bShshoexer } 11539e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 11549e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 11559e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 11569e8c6f5bShshoexer memset(verifybuf, 0, sizeof(verifybuf)); 11579e8c6f5bShshoexer errx(1, "Passphrases did not match"); 11589e8c6f5bShshoexer } 11599e8c6f5bShshoexer /* forget the re-typed one */ 11609e8c6f5bShshoexer memset(verifybuf, 0, strlen(verifybuf)); 11619e8c6f5bShshoexer } 1162aef7fe28Shshoexer 1163aef7fe28Shshoexer /* derive key from passphrase */ 11645c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 11655c1f8f6bSdjm key, keysz, rounds) != 0) 11665c1f8f6bSdjm errx(1, "pbkdf2 failed"); 1167aef7fe28Shshoexer 1168aef7fe28Shshoexer /* forget passphrase */ 11699e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 1170aef7fe28Shshoexer 1171aef7fe28Shshoexer return; 1172aef7fe28Shshoexer } 1173