1*0054cd36Sjsing /* $OpenBSD: bioctl.c,v 1.88 2009/12/31 14:00:45 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> 31c2126c9aSmarco #include <sys/param.h> 32c2126c9aSmarco #include <sys/queue.h> 3346bc198bSmarco #include <sys/types.h> 3446bc198bSmarco #include <sys/stat.h> 35c2126c9aSmarco #include <scsi/scsi_disk.h> 362b69df39Smarco #include <scsi/scsi_all.h> 373af9de98Smarco #include <dev/biovar.h> 38aef7fe28Shshoexer #include <dev/softraidvar.h> 3986735da2Smarco #include <sys/types.h> 4086735da2Smarco #include <sys/stat.h> 413af9de98Smarco 42db2730c1Smarco #include <errno.h> 43db2730c1Smarco #include <err.h> 44db2730c1Smarco #include <fcntl.h> 458ccdd032Sderaadt #include <util.h> 46db2730c1Smarco #include <stdio.h> 47db2730c1Smarco #include <stdlib.h> 48db2730c1Smarco #include <string.h> 49db2730c1Smarco #include <unistd.h> 50e4e14ad7Sderaadt #include <ctype.h> 51db2730c1Smarco #include <util.h> 5203b2dfbfShenning #include <vis.h> 539e8c6f5bShshoexer #include <readpassphrase.h> 54db2730c1Smarco 555c1f8f6bSdjm #include "pbkdf2.h" 56aef7fe28Shshoexer 576de960dcSmarco struct locator { 586de960dcSmarco int channel; 596de960dcSmarco int target; 606de960dcSmarco int lun; 616de960dcSmarco }; 626de960dcSmarco 638ccdd032Sderaadt void usage(void); 6441eccc89Sderaadt const char *str2locator(const char *, struct locator *); 658ccdd032Sderaadt void cleanup(void); 6646bc198bSmarco int bio_parse_devlist(char *, dev_t *); 67aef7fe28Shshoexer void bio_kdf_derive(struct sr_crypto_kdfinfo *, 68c6446370Sjsing struct sr_crypto_kdf_pbkdf2 *, char *, int); 69aef7fe28Shshoexer void bio_kdf_generate(struct sr_crypto_kdfinfo *); 709e8c6f5bShshoexer void derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *, 71c6446370Sjsing size_t, char *, int); 728ccdd032Sderaadt 738ccdd032Sderaadt void bio_inq(char *); 748ccdd032Sderaadt void bio_alarm(char *); 75a15048bbSmarco int bio_getvolbyname(char *); 76a15048bbSmarco void bio_setstate(char *, int, char *); 77a928c459Sderaadt void bio_setblink(char *, char *, int); 78a928c459Sderaadt void bio_blink(char *, int, int); 79*0054cd36Sjsing void bio_createraid(u_int16_t, char *, char *); 80c7c3e8aaSmarco void bio_deleteraid(char *); 81c6446370Sjsing void bio_changepass(char *); 82e8a57fdeSmarco u_int32_t bio_createflags(char *); 8303b2dfbfShenning char *bio_vis(char *); 8403b2dfbfShenning void bio_diskinq(char *); 853af9de98Smarco 863af9de98Smarco int devh = -1; 87abe9d68eSderaadt int human; 88abe9d68eSderaadt int verbose; 89e8a57fdeSmarco u_int32_t cflags = 0; 90aedd4f07Sdjm int rflag = 8192; 9186735da2Smarco char *password; 923af9de98Smarco 933af9de98Smarco struct bio_locate bl; 943af9de98Smarco 953af9de98Smarco int 963af9de98Smarco main(int argc, char *argv[]) 973af9de98Smarco { 983af9de98Smarco extern char *optarg; 99db2730c1Smarco u_int64_t func = 0; 100db2730c1Smarco /* u_int64_t subfunc = 0; */ 101cf6503d7Sderaadt char *bioc_dev = NULL, *sd_dev = NULL; 102cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 1037195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 104*0054cd36Sjsing char *key_disk = NULL; 105aedd4f07Sdjm const char *errstr; 106c6446370Sjsing int ch, rv, blink = 0, changepass = 0, diskinq = 0; 107c6446370Sjsing int ss_func = 0; 1089ecba717Sderaadt u_int16_t cr_level = 0; 1093af9de98Smarco 1103af9de98Smarco if (argc < 2) 1113af9de98Smarco usage(); 1123af9de98Smarco 113*0054cd36Sjsing while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:Pp:qr:R:vu:")) != 114c6446370Sjsing -1) { 1153af9de98Smarco switch (ch) { 116edfd9792Smarco case 'a': /* alarm */ 117edfd9792Smarco func |= BIOC_ALARM; 118edfd9792Smarco al_arg = optarg; 119edfd9792Smarco break; 120c55617f1Sdlg case 'b': /* blink */ 121c55617f1Sdlg func |= BIOC_BLINK; 122a928c459Sderaadt blink = BIOC_SBBLINK; 123a928c459Sderaadt bl_arg = optarg; 124a928c459Sderaadt break; 125e8a57fdeSmarco case 'C': /* creation flags */ 126e8a57fdeSmarco cflags = bio_createflags(optarg); 127e8a57fdeSmarco break; 1287195049bSmarco case 'c': /* create */ 1297195049bSmarco func |= BIOC_CREATERAID; 13098b750e4Stedu if (isdigit(*optarg)) 1317195049bSmarco cr_level = atoi(optarg); 13298b750e4Stedu 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; 155*0054cd36Sjsing case 'k': /* Key disk. */ 156*0054cd36Sjsing key_disk = optarg; 157*0054cd36Sjsing 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; 181abe9d68eSderaadt case 'v': 182abe9d68eSderaadt verbose = 1; 183abe9d68eSderaadt break; 18403b2dfbfShenning case 'q': 18503b2dfbfShenning diskinq = 1; 18603b2dfbfShenning break; 1873af9de98Smarco default: 1883af9de98Smarco usage(); 1893af9de98Smarco /* NOTREACHED */ 1903af9de98Smarco } 1913af9de98Smarco } 192cf6503d7Sderaadt argc -= optind; 193cf6503d7Sderaadt argv += optind; 1943af9de98Smarco 195c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 196cf6503d7Sderaadt usage(); 197cf6503d7Sderaadt 198dcbaf4c8Sderaadt if (func == 0) 199dcbaf4c8Sderaadt func |= BIOC_INQ; 200dcbaf4c8Sderaadt 201e4e14ad7Sderaadt /* if at least glob sd[0-9]*, it is a drive identifier */ 202e4e14ad7Sderaadt if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 && 203e4e14ad7Sderaadt isdigit(argv[0][2])) 204cf6503d7Sderaadt sd_dev = argv[0]; 205cf6503d7Sderaadt else 206cf6503d7Sderaadt bioc_dev = argv[0]; 20710b411a7Smarco 20810b411a7Smarco if (bioc_dev) { 20941eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2103af9de98Smarco if (devh == -1) 21141eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2123af9de98Smarco 2138ccdd032Sderaadt bl.bl_name = bioc_dev; 2143af9de98Smarco rv = ioctl(devh, BIOCLOCATE, &bl); 2153af9de98Smarco if (rv == -1) 21610b411a7Smarco errx(1, "Can't locate %s device via %s", 21741eccc89Sderaadt bl.bl_name, "/dev/bio"); 218db2730c1Smarco } else if (sd_dev) { 21910b411a7Smarco devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname); 22010b411a7Smarco if (devh == -1) 22110b411a7Smarco err(1, "Can't open %s", sd_dev); 222db2730c1Smarco } else 22386735da2Smarco errx(1, "need device"); 2243af9de98Smarco 22503b2dfbfShenning if (diskinq) { 22603b2dfbfShenning bio_diskinq(sd_dev); 227c6446370Sjsing } else if (changepass && sd_dev != NULL) { 228c6446370Sjsing bio_changepass(sd_dev); 22903b2dfbfShenning } else if (func & BIOC_INQ) { 2308ccdd032Sderaadt bio_inq(sd_dev); 231edfd9792Smarco } else if (func == BIOC_ALARM) { 232edfd9792Smarco bio_alarm(al_arg); 233c55617f1Sdlg } else if (func == BIOC_BLINK) { 234a928c459Sderaadt bio_setblink(sd_dev, bl_arg, blink); 2356de960dcSmarco } else if (func == BIOC_SETSTATE) { 236a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 237c7c3e8aaSmarco } else if (func == BIOC_DELETERAID && sd_dev != NULL) { 238c7c3e8aaSmarco bio_deleteraid(sd_dev); 2397195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2407195049bSmarco if (!(func & BIOC_CREATERAID)) 2417195049bSmarco errx(1, "need -c parameter"); 2427195049bSmarco if (!(func & BIOC_DEVLIST)) 2437195049bSmarco errx(1, "need -l parameter"); 2447195049bSmarco if (sd_dev) 2457195049bSmarco errx(1, "can't use sd device"); 246*0054cd36Sjsing bio_createraid(cr_level, dev_list, key_disk); 2473af9de98Smarco } 2483af9de98Smarco 2493af9de98Smarco return (0); 2503af9de98Smarco } 2513af9de98Smarco 2523af9de98Smarco void 2533af9de98Smarco usage(void) 2543af9de98Smarco { 2553af9de98Smarco extern char *__progname; 2563af9de98Smarco 257d90b5d8bSjmc fprintf(stderr, 258d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 259d90b5d8bSjmc "[-b channel:target[.lun]]\n" 260d0b772c8Sjmc "\t[-H channel:target[.lun]] " 261d0b772c8Sjmc "[-R device | channel:target[.lun]\n" 262d0b772c8Sjmc "\t[-u channel:target[.lun]] " 263d0b772c8Sjmc "device\n" 264af84dad0Sjmc " %s [-dhiPqv] " 265*0054cd36Sjsing "[-C flag[,flag,...]] [-c raidlevel] [-k special]\n" 26678702060Sjmc "\t[-l special[,special,...]] [-p passfile]\n" 26778702060Sjmc "\t[-R device | channel:target[.lun] [-r rounds] " 268d0b772c8Sjmc "device\n", __progname, __progname); 269d90b5d8bSjmc 2703af9de98Smarco exit(1); 2713af9de98Smarco } 2723af9de98Smarco 27341eccc89Sderaadt const char * 2746de960dcSmarco str2locator(const char *string, struct locator *location) 2756de960dcSmarco { 27650d3c4dcSdlg const char *errstr; 27741eccc89Sderaadt char parse[80], *targ, *lun; 2786de960dcSmarco 27941eccc89Sderaadt strlcpy(parse, string, sizeof parse); 28041eccc89Sderaadt targ = strchr(parse, ':'); 2816de960dcSmarco if (targ == NULL) 28241eccc89Sderaadt return ("target not specified"); 2836de960dcSmarco *targ++ = '\0'; 2846de960dcSmarco 28550d3c4dcSdlg lun = strchr(targ, '.'); 2866de960dcSmarco if (lun != NULL) { 2876de960dcSmarco *lun++ = '\0'; 28850d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 28950d3c4dcSdlg if (errstr) 29041eccc89Sderaadt return (errstr); 2916de960dcSmarco } else 2926de960dcSmarco location->lun = 0; 2936de960dcSmarco 29450d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 29550d3c4dcSdlg if (errstr) 29641eccc89Sderaadt return (errstr); 29741eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 29850d3c4dcSdlg if (errstr) 29941eccc89Sderaadt return (errstr); 30041eccc89Sderaadt return (NULL); 3016de960dcSmarco } 3026de960dcSmarco 3033af9de98Smarco void 3048ccdd032Sderaadt bio_inq(char *name) 305d4546a56Sdlg { 3069017fb97Sderaadt char *status, size[64], scsiname[16], volname[32]; 307a4d3c4a2Sderaadt char percent[10], seconds[20]; 308b9950701Smarco int rv, i, d, volheader, hotspare, unused; 309aa65acf1Sderaadt char encname[16], serial[32]; 3108ccdd032Sderaadt struct bioc_disk bd; 3118ccdd032Sderaadt struct bioc_inq bi; 3128ccdd032Sderaadt struct bioc_vol bv; 313db2730c1Smarco 314db2730c1Smarco memset(&bi, 0, sizeof(bi)); 3153af9de98Smarco 3168ccdd032Sderaadt bi.bi_cookie = bl.bl_cookie; 3173af9de98Smarco 318db2730c1Smarco rv = ioctl(devh, BIOCINQ, &bi); 3193af9de98Smarco if (rv == -1) { 32003b2dfbfShenning if (errno == ENOTTY) 32103b2dfbfShenning bio_diskinq(name); 32203b2dfbfShenning else 323da3b0664Shenning err(1, "BIOCINQ"); 3243af9de98Smarco return; 3253af9de98Smarco } 3263af9de98Smarco 3278ccdd032Sderaadt volheader = 0; 3288ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 329db2730c1Smarco memset(&bv, 0, sizeof(bv)); 3308ccdd032Sderaadt bv.bv_cookie = bl.bl_cookie; 3318ccdd032Sderaadt bv.bv_volid = i; 3320a92ff65Sderaadt bv.bv_percent = -1; 3339017fb97Sderaadt bv.bv_seconds = 0; 33470a2ae7bSmarco 335db2730c1Smarco rv = ioctl(devh, BIOCVOL, &bv); 336da3b0664Shenning if (rv == -1) 337da3b0664Shenning err(1, "BIOCVOL"); 3383af9de98Smarco 3398ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 3408ccdd032Sderaadt continue; 3418ccdd032Sderaadt 3428ccdd032Sderaadt if (!volheader) { 3438ccdd032Sderaadt volheader = 1; 344c9377e3bSmickey printf("%-7s %-10s %14s %-8s\n", 3458ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 3468ccdd032Sderaadt } 3478ccdd032Sderaadt 3480a92ff65Sderaadt percent[0] = '\0'; 3499017fb97Sderaadt seconds[0] = '\0'; 3500a92ff65Sderaadt if (bv.bv_percent != -1) 3510a92ff65Sderaadt snprintf(percent, sizeof percent, 3520a92ff65Sderaadt " %d%% done", bv.bv_percent); 3539017fb97Sderaadt if (bv.bv_seconds) 3549017fb97Sderaadt snprintf(seconds, sizeof seconds, 3559017fb97Sderaadt " %u seconds", bv.bv_seconds); 3568ccdd032Sderaadt switch (bv.bv_status) { 357db2730c1Smarco case BIOC_SVONLINE: 3588ccdd032Sderaadt status = BIOC_SVONLINE_S; 359db2730c1Smarco break; 360db2730c1Smarco case BIOC_SVOFFLINE: 3618ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 362db2730c1Smarco break; 363db2730c1Smarco case BIOC_SVDEGRADED: 3648ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 365db2730c1Smarco break; 3660a92ff65Sderaadt case BIOC_SVBUILDING: 3670a92ff65Sderaadt status = BIOC_SVBUILDING_S; 3680a92ff65Sderaadt break; 3690a92ff65Sderaadt case BIOC_SVREBUILD: 3700a92ff65Sderaadt status = BIOC_SVREBUILD_S; 3710a92ff65Sderaadt break; 3720a92ff65Sderaadt case BIOC_SVSCRUB: 3730a92ff65Sderaadt status = BIOC_SVSCRUB_S; 3740a92ff65Sderaadt break; 375db2730c1Smarco case BIOC_SVINVALID: 376db2730c1Smarco default: 3778ccdd032Sderaadt status = BIOC_SVINVALID_S; 378d4546a56Sdlg } 3793af9de98Smarco 380aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 3818ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 382b9950701Smarco 3839ecba717Sderaadt unused = 0; 3849ecba717Sderaadt hotspare = 0; 385aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 386aa65acf1Sderaadt hotspare = 1; 387b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 388b9950701Smarco unused = 1; 389aa65acf1Sderaadt else { 3908ccdd032Sderaadt if (human) 3918ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 3928ccdd032Sderaadt else 3938ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 3948ccdd032Sderaadt bv.bv_size); 395da935596Stodd switch (bv.bv_level) { 396da935596Stodd case 'C': 397da935596Stodd printf("%7s %-10s %14s %-7s CRYPTO%s%s\n", 398da935596Stodd volname, status, size, bv.bv_dev, 399da935596Stodd percent, seconds); 400da935596Stodd break; 401da935596Stodd default: 4029017fb97Sderaadt printf("%7s %-10s %14s %-7s RAID%u%s%s\n", 4030a92ff65Sderaadt volname, status, size, bv.bv_dev, 4049017fb97Sderaadt bv.bv_level, percent, seconds); 405da935596Stodd break; 406da935596Stodd } 407da935596Stodd 408aa65acf1Sderaadt } 4098ccdd032Sderaadt 4108ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 411db2730c1Smarco memset(&bd, 0, sizeof(bd)); 4128ccdd032Sderaadt bd.bd_cookie = bl.bl_cookie; 4138ccdd032Sderaadt bd.bd_diskid = d; 4148ccdd032Sderaadt bd.bd_volid = i; 4153af9de98Smarco 416db2730c1Smarco rv = ioctl(devh, BIOCDISK, &bd); 417da3b0664Shenning if (rv == -1) 418da3b0664Shenning err(1, "BIOCDISK"); 4193af9de98Smarco 4208ccdd032Sderaadt switch (bd.bd_status) { 421db2730c1Smarco case BIOC_SDONLINE: 4228ccdd032Sderaadt status = BIOC_SDONLINE_S; 423d4546a56Sdlg break; 424db2730c1Smarco case BIOC_SDOFFLINE: 4258ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 426d4546a56Sdlg break; 427db2730c1Smarco case BIOC_SDFAILED: 4288ccdd032Sderaadt status = BIOC_SDFAILED_S; 429db2730c1Smarco break; 430db2730c1Smarco case BIOC_SDREBUILD: 4318ccdd032Sderaadt status = BIOC_SDREBUILD_S; 432db2730c1Smarco break; 433db2730c1Smarco case BIOC_SDHOTSPARE: 4348ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 435db2730c1Smarco break; 436db2730c1Smarco case BIOC_SDUNUSED: 4378ccdd032Sderaadt status = BIOC_SDUNUSED_S; 438db2730c1Smarco break; 439e1dfb373Sderaadt case BIOC_SDSCRUB: 440e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 441e1dfb373Sderaadt break; 442db2730c1Smarco case BIOC_SDINVALID: 443d4546a56Sdlg default: 4448ccdd032Sderaadt status = BIOC_SDINVALID_S; 445d4546a56Sdlg } 446aa65acf1Sderaadt 447b9950701Smarco if (hotspare || unused) 448aa65acf1Sderaadt ; /* use volname from parent volume */ 449aa65acf1Sderaadt else 450aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 451aa65acf1Sderaadt bd.bd_diskid); 452aa65acf1Sderaadt 453*0054cd36Sjsing if (bv.bv_level == 'C' && bd.bd_size == 0) 454*0054cd36Sjsing snprintf(size, sizeof size, "%14s", "key disk"); 455*0054cd36Sjsing else if (human) 4568ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 4578ccdd032Sderaadt else 4588ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4598ccdd032Sderaadt bd.bd_size); 4608ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 46143d61178Sderaadt "%u:%u.%u", 46243d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 4635978b28dSderaadt if (bd.bd_procdev[0]) 464abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 4655978b28dSderaadt else 466abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 467abe9d68eSderaadt if (bd.bd_serial[0]) 468abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 469abe9d68eSderaadt else 470abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 4718ccdd032Sderaadt 472aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s <%s>\n", 473aa65acf1Sderaadt volname, status, size, scsiname, encname, 4748ccdd032Sderaadt bd.bd_vendor); 475abe9d68eSderaadt if (verbose) 476aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s '%s'\n", 477abe9d68eSderaadt "", "", "", "", "", serial); 478d4546a56Sdlg } 479d4546a56Sdlg } 480d4546a56Sdlg } 481edfd9792Smarco 482edfd9792Smarco void 483edfd9792Smarco bio_alarm(char *arg) 484edfd9792Smarco { 485edfd9792Smarco int rv; 4868ccdd032Sderaadt struct bioc_alarm ba; 487edfd9792Smarco 4888ccdd032Sderaadt ba.ba_cookie = bl.bl_cookie; 489edfd9792Smarco 490edfd9792Smarco switch (arg[0]) { 491edfd9792Smarco case 'q': /* silence alarm */ 492edfd9792Smarco /* FALLTHROUGH */ 493edfd9792Smarco case 's': 4948ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 495edfd9792Smarco break; 496edfd9792Smarco 497edfd9792Smarco case 'e': /* enable alarm */ 4988ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 499edfd9792Smarco break; 500edfd9792Smarco 501edfd9792Smarco case 'd': /* disable alarm */ 5028ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 503edfd9792Smarco break; 504edfd9792Smarco 505edfd9792Smarco case 't': /* test alarm */ 5068ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 507edfd9792Smarco break; 508edfd9792Smarco 509edfd9792Smarco case 'g': /* get alarm state */ 5108ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 511edfd9792Smarco break; 512edfd9792Smarco 513edfd9792Smarco default: 514da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 515edfd9792Smarco } 516edfd9792Smarco 517edfd9792Smarco rv = ioctl(devh, BIOCALARM, &ba); 518da3b0664Shenning if (rv == -1) 519da3b0664Shenning err(1, "BIOCALARM"); 520edfd9792Smarco 521edfd9792Smarco if (arg[0] == 'g') { 522edfd9792Smarco printf("alarm is currently %s\n", 5238ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 5248ccdd032Sderaadt 525edfd9792Smarco } 526edfd9792Smarco } 5276de960dcSmarco 528a15048bbSmarco int 529a15048bbSmarco bio_getvolbyname(char *name) 530a15048bbSmarco { 531a15048bbSmarco int id = -1, i, rv; 532a15048bbSmarco struct bioc_inq bi; 533a15048bbSmarco struct bioc_vol bv; 534a15048bbSmarco 535a15048bbSmarco memset(&bi, 0, sizeof(bi)); 536a15048bbSmarco bi.bi_cookie = bl.bl_cookie; 537a15048bbSmarco rv = ioctl(devh, BIOCINQ, &bi); 538a15048bbSmarco if (rv == -1) 539a15048bbSmarco err(1, "BIOCINQ"); 540a15048bbSmarco 541a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 542a15048bbSmarco memset(&bv, 0, sizeof(bv)); 543a15048bbSmarco bv.bv_cookie = bl.bl_cookie; 544a15048bbSmarco bv.bv_volid = i; 545a15048bbSmarco rv = ioctl(devh, BIOCVOL, &bv); 546a15048bbSmarco if (rv == -1) 547a15048bbSmarco err(1, "BIOCVOL"); 548a15048bbSmarco 549a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 550a15048bbSmarco continue; 551a15048bbSmarco id = i; 552a15048bbSmarco break; 553a15048bbSmarco } 554a15048bbSmarco 555a15048bbSmarco return (id); 556a15048bbSmarco } 557a15048bbSmarco 558ebaf584eSderaadt void 5598d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 5606de960dcSmarco { 5616de960dcSmarco struct bioc_setstate bs; 5626de960dcSmarco struct locator location; 563a15048bbSmarco struct stat sb; 56441eccc89Sderaadt const char *errstr; 565ebaf584eSderaadt int rv; 5666de960dcSmarco 567a15048bbSmarco memset(&bs, 0, sizeof(bs)); 568a15048bbSmarco if (stat(arg, &sb) == -1) { 569a15048bbSmarco /* use CTL */ 57041eccc89Sderaadt errstr = str2locator(arg, &location); 57141eccc89Sderaadt if (errstr) 57241eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 5736de960dcSmarco bs.bs_channel = location.channel; 5746de960dcSmarco bs.bs_target = location.target; 5756de960dcSmarco bs.bs_lun = location.lun; 576a15048bbSmarco } else { 577a15048bbSmarco /* use other id */ 578a15048bbSmarco bs.bs_other_id = sb.st_rdev; 579a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 580a15048bbSmarco } 581a15048bbSmarco 582a15048bbSmarco bs.bs_cookie = bl.bl_cookie; 583a15048bbSmarco bs.bs_status = status; 584a15048bbSmarco 585d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 586a15048bbSmarco /* make sure user supplied a sd device */ 5878d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 588a15048bbSmarco if (bs.bs_volid == -1) 5898d8693a2Sdtucker errx(1, "invalid device %s", devicename); 590d2647ac1Sjsing } 5916de960dcSmarco 5926de960dcSmarco rv = ioctl(devh, BIOCSETSTATE, &bs); 593da3b0664Shenning if (rv == -1) 594da3b0664Shenning err(1, "BIOCSETSTATE"); 5956de960dcSmarco } 596c55617f1Sdlg 597c55617f1Sdlg void 598a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 599c55617f1Sdlg { 60050d3c4dcSdlg struct locator location; 60150d3c4dcSdlg struct bioc_inq bi; 60250d3c4dcSdlg struct bioc_vol bv; 60350d3c4dcSdlg struct bioc_disk bd; 6040505205bSdlg struct bioc_blink bb; 60541eccc89Sderaadt const char *errstr; 60650d3c4dcSdlg int v, d, rv; 607c55617f1Sdlg 60841eccc89Sderaadt errstr = str2locator(arg, &location); 60941eccc89Sderaadt if (errstr) 61041eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 61150d3c4dcSdlg 6120505205bSdlg /* try setting blink on the device directly */ 6130505205bSdlg memset(&bb, 0, sizeof(bb)); 6140505205bSdlg bb.bb_cookie = bl.bl_cookie; 6150505205bSdlg bb.bb_status = blink; 6160505205bSdlg bb.bb_target = location.target; 617649724a4Smarco bb.bb_channel = location.channel; 6180505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 6190505205bSdlg if (rv == 0) 6200505205bSdlg return; 6210505205bSdlg 622855d4e83Ssobrado /* if the blink didn't work, try to find something that will */ 6230505205bSdlg 62450d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 62550d3c4dcSdlg bi.bi_cookie = bl.bl_cookie; 62650d3c4dcSdlg rv = ioctl(devh, BIOCINQ, &bi); 627da3b0664Shenning if (rv == -1) 628da3b0664Shenning err(1, "BIOCINQ"); 62950d3c4dcSdlg 63050d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 63150d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 63250d3c4dcSdlg bv.bv_cookie = bl.bl_cookie; 63350d3c4dcSdlg bv.bv_volid = v; 63450d3c4dcSdlg rv = ioctl(devh, BIOCVOL, &bv); 635da3b0664Shenning if (rv == -1) 636da3b0664Shenning err(1, "BIOCVOL"); 63750d3c4dcSdlg 63850d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 63950d3c4dcSdlg continue; 64050d3c4dcSdlg 64150d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 64250d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 64350d3c4dcSdlg bd.bd_cookie = bl.bl_cookie; 64450d3c4dcSdlg bd.bd_volid = v; 64550d3c4dcSdlg bd.bd_diskid = d; 64650d3c4dcSdlg 64750d3c4dcSdlg rv = ioctl(devh, BIOCDISK, &bd); 648da3b0664Shenning if (rv == -1) 649da3b0664Shenning err(1, "BIOCDISK"); 65050d3c4dcSdlg 65150d3c4dcSdlg if (bd.bd_channel == location.channel && 65250d3c4dcSdlg bd.bd_target == location.target && 65350d3c4dcSdlg bd.bd_lun == location.lun) { 65450d3c4dcSdlg if (bd.bd_procdev[0] != '\0') { 65550d3c4dcSdlg bio_blink(bd.bd_procdev, 656a928c459Sderaadt location.target, blink); 65750d3c4dcSdlg } else 65841eccc89Sderaadt warnx("Disk %s is not in an enclosure", arg); 65950d3c4dcSdlg return; 66050d3c4dcSdlg } 66150d3c4dcSdlg } 66250d3c4dcSdlg } 66350d3c4dcSdlg 66441eccc89Sderaadt warnx("Disk %s does not exist", arg); 66550d3c4dcSdlg return; 66650d3c4dcSdlg } 66750d3c4dcSdlg 66850d3c4dcSdlg void 669a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 67050d3c4dcSdlg { 67150d3c4dcSdlg int bioh; 67250d3c4dcSdlg struct bio_locate bio; 67350d3c4dcSdlg struct bioc_blink blink; 67450d3c4dcSdlg int rv; 67550d3c4dcSdlg 67641eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 67750d3c4dcSdlg if (bioh == -1) 67841eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 67950d3c4dcSdlg 68050d3c4dcSdlg bio.bl_name = enclosure; 68150d3c4dcSdlg rv = ioctl(bioh, BIOCLOCATE, &bio); 68250d3c4dcSdlg if (rv == -1) 68341eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 684c55617f1Sdlg 685c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 68650d3c4dcSdlg blink.bb_cookie = bio.bl_cookie; 687a928c459Sderaadt blink.bb_status = blinktype; 688c55617f1Sdlg blink.bb_target = target; 689c55617f1Sdlg 69050d3c4dcSdlg rv = ioctl(bioh, BIOCBLINK, &blink); 691c55617f1Sdlg if (rv == -1) 692da3b0664Shenning err(1, "BIOCBLINK"); 69350d3c4dcSdlg 69450d3c4dcSdlg close(bioh); 695c55617f1Sdlg } 6967195049bSmarco 6977195049bSmarco void 698*0054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk) 6997195049bSmarco { 7007195049bSmarco struct bioc_createraid create; 701aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 702aef7fe28Shshoexer struct sr_crypto_kdf_pbkdf2 kdfhint; 703*0054cd36Sjsing struct stat sb; 704*0054cd36Sjsing int rv, no_dev, i; 705*0054cd36Sjsing dev_t *dt, kd = NODEV; 7067195049bSmarco u_int16_t min_disks = 0; 7077195049bSmarco 7087195049bSmarco if (!dev_list) 7097195049bSmarco errx(1, "no devices specified"); 7107195049bSmarco 71146bc198bSmarco dt = (dev_t *)malloc(BIOC_CRMAXLEN); 71246bc198bSmarco if (!dt) 71346bc198bSmarco err(1, "not enough memory for dev_t list"); 71446bc198bSmarco memset(dt, 0, BIOC_CRMAXLEN); 71546bc198bSmarco 71646bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 71746bc198bSmarco 7187195049bSmarco switch (level) { 7197195049bSmarco case 0: 72084e48fabSmarco min_disks = 2; 7217195049bSmarco break; 7227195049bSmarco case 1: 7237195049bSmarco min_disks = 2; 7247195049bSmarco break; 725e717853eSmarco case 4: 726e717853eSmarco case 5: 727e717853eSmarco min_disks = 3; 728e717853eSmarco break; 72984e48fabSmarco case 'C': 730aef7fe28Shshoexer min_disks = 1; 73184e48fabSmarco break; 73298b750e4Stedu case 'c': 73398b750e4Stedu min_disks = 1; 73498b750e4Stedu break; 7357195049bSmarco default: 73623afedbfSgrunk errx(1, "unsupported raid level"); 7377195049bSmarco } 7387195049bSmarco 73984e48fabSmarco if (no_dev < min_disks) 74084e48fabSmarco errx(1, "not enough disks"); 74184e48fabSmarco 742aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 743aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 744818b0595Shalex errx(1, "not exactly one partition"); 745aef7fe28Shshoexer 7467195049bSmarco memset(&create, 0, sizeof(create)); 7477195049bSmarco create.bc_cookie = bl.bl_cookie; 7487195049bSmarco create.bc_level = level; 74946bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 75046bc198bSmarco create.bc_dev_list = dt; 751e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 752*0054cd36Sjsing create.bc_key_disk = NODEV; 7537195049bSmarco 754*0054cd36Sjsing if (level == 'C' && key_disk == NULL) { 755*0054cd36Sjsing 756aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 757aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 758aef7fe28Shshoexer 759*0054cd36Sjsing create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 760*0054cd36Sjsing 761aef7fe28Shshoexer create.bc_opaque = &kdfhint; 762aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 763aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 764aef7fe28Shshoexer 765aef7fe28Shshoexer /* try to get KDF hint */ 76683e979edShshoexer if (ioctl(devh, BIOCCREATERAID, &create) == -1) 76783e979edShshoexer err(1, "ioctl"); 76883e979edShshoexer 76983e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 770c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 771aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 772aef7fe28Shshoexer } else { 773aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 774aef7fe28Shshoexer } 775aef7fe28Shshoexer 776aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 777aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 778aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 779*0054cd36Sjsing 780*0054cd36Sjsing } else if (level == 'C' && key_disk != NULL) { 781*0054cd36Sjsing 782*0054cd36Sjsing if (stat(key_disk, &sb) == -1) 783*0054cd36Sjsing err(1, "could not stat %s", key_disk); 784*0054cd36Sjsing create.bc_key_disk = sb.st_rdev; 785*0054cd36Sjsing 786*0054cd36Sjsing memset(&kdfinfo, 0, sizeof(kdfinfo)); 787*0054cd36Sjsing 788*0054cd36Sjsing kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf); 789*0054cd36Sjsing kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK; 790*0054cd36Sjsing kdfinfo.len = sizeof(kdfinfo); 791*0054cd36Sjsing kdfinfo.flags = SR_CRYPTOKDF_HINT; 792*0054cd36Sjsing 793*0054cd36Sjsing create.bc_opaque = &kdfinfo; 794*0054cd36Sjsing create.bc_opaque_size = sizeof(kdfinfo); 795*0054cd36Sjsing create.bc_opaque_flags = BIOC_SOIN; 796*0054cd36Sjsing 797aef7fe28Shshoexer } 798aef7fe28Shshoexer 7997195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 800aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 80183e979edShshoexer memset(&create, 0, sizeof(create)); 802a83e4577Sdjm if (rv == -1) { 803a83e4577Sdjm if (errno == EPERM) 804a83e4577Sdjm errx(1, "Incorrect passphrase"); 805da3b0664Shenning err(1, "BIOCCREATERAID"); 806a83e4577Sdjm } 80746bc198bSmarco 80846bc198bSmarco free(dt); 80946bc198bSmarco } 81046bc198bSmarco 811aef7fe28Shshoexer void 812aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 813c6446370Sjsing *kdfhint, char* prompt, int verify) 814aef7fe28Shshoexer { 815aef7fe28Shshoexer if (!kdfinfo) 816aef7fe28Shshoexer errx(1, "invalid KDF info"); 817aef7fe28Shshoexer if (!kdfhint) 818aef7fe28Shshoexer errx(1, "invalid KDF hint"); 819aef7fe28Shshoexer 820aef7fe28Shshoexer if (kdfhint->len != sizeof(*kdfhint)) 821aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 822aef7fe28Shshoexer if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2) 823aef7fe28Shshoexer errx(1, "unknown KDF type %d", kdfhint->type); 824aef7fe28Shshoexer if (kdfhint->rounds < 1000) 825aef7fe28Shshoexer errx(1, "number of KDF rounds too low: %d", kdfhint->rounds); 826aef7fe28Shshoexer 827aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 828aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 829aef7fe28Shshoexer 8309e8c6f5bShshoexer derive_key_pkcs(kdfhint->rounds, 831aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 832c6446370Sjsing kdfhint->salt, sizeof(kdfhint->salt), prompt, verify); 833aef7fe28Shshoexer } 834aef7fe28Shshoexer 835aef7fe28Shshoexer void 836aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 837aef7fe28Shshoexer { 838aef7fe28Shshoexer if (!kdfinfo) 839aef7fe28Shshoexer errx(1, "invalid KDF info"); 840aef7fe28Shshoexer 841aef7fe28Shshoexer kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 842aef7fe28Shshoexer kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 843aedd4f07Sdjm kdfinfo->pbkdf2.rounds = rflag; 844aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 845*0054cd36Sjsing kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT; 846aef7fe28Shshoexer 847aef7fe28Shshoexer /* generate salt */ 848aef7fe28Shshoexer arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 849aef7fe28Shshoexer 8509e8c6f5bShshoexer derive_key_pkcs(kdfinfo->pbkdf2.rounds, 851aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 852c6446370Sjsing kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 853c6446370Sjsing "New passphrase: ", 1); 854aef7fe28Shshoexer } 855aef7fe28Shshoexer 85646bc198bSmarco int 85746bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 85846bc198bSmarco { 85946bc198bSmarco char *s, *e; 86046bc198bSmarco u_int32_t sz = 0; 86146bc198bSmarco int no_dev = 0, i, x; 86246bc198bSmarco struct stat sb; 8635c1f8f6bSdjm char dev[MAXPATHLEN]; 86446bc198bSmarco 86546bc198bSmarco if (!lst) 86646bc198bSmarco errx(1, "invalid device list"); 86746bc198bSmarco 86846bc198bSmarco s = e = lst; 86946bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 87046bc198bSmarco while (*e != '\0') { 87146bc198bSmarco if (*e == ',') 87246bc198bSmarco s = e + 1; 87346bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 87446bc198bSmarco /* got one */ 87546bc198bSmarco sz = e - s + 1; 8765c1f8f6bSdjm strlcpy(dev, s, sz + 1); 8775c1f8f6bSdjm if (stat(dev, &sb) == -1) 8785c1f8f6bSdjm err(1, "could not stat %s", dev); 87946bc198bSmarco dt[no_dev] = sb.st_rdev; 88046bc198bSmarco no_dev++; 8815c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 88246bc198bSmarco errx(1, "too many devices on device list"); 88346bc198bSmarco } 88446bc198bSmarco e++; 88546bc198bSmarco } 88646bc198bSmarco 88746bc198bSmarco for (i = 0; i < no_dev; i++) 88846bc198bSmarco for (x = 0; x < no_dev; x++) 88946bc198bSmarco if (dt[i] == dt[x] && x != i) 89046bc198bSmarco errx(1, "duplicate device in list"); 89146bc198bSmarco 89246bc198bSmarco return (no_dev); 8937195049bSmarco } 894e8a57fdeSmarco 895e8a57fdeSmarco u_int32_t 896e8a57fdeSmarco bio_createflags(char *lst) 897e8a57fdeSmarco { 898e8a57fdeSmarco char *s, *e, fs[32]; 899e8a57fdeSmarco u_int32_t sz = 0; 900e8a57fdeSmarco u_int32_t flags = 0; 901e8a57fdeSmarco 902e8a57fdeSmarco if (!lst) 903e8a57fdeSmarco errx(1, "invalid flags list"); 904e8a57fdeSmarco 905e8a57fdeSmarco s = e = lst; 906e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 907e8a57fdeSmarco while (*e != '\0') { 908e8a57fdeSmarco if (*e == ',') 909e8a57fdeSmarco s = e + 1; 910e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 911e8a57fdeSmarco /* got one */ 912e8a57fdeSmarco sz = e - s + 1; 913e8a57fdeSmarco switch (s[0]) { 914e8a57fdeSmarco case 'f': 915e8a57fdeSmarco flags |= BIOC_SCFORCE; 916e8a57fdeSmarco break; 917e8a57fdeSmarco case 'n': 918e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 919e8a57fdeSmarco break; 920e8a57fdeSmarco default: 921e8a57fdeSmarco strlcpy(fs, s, sz + 1); 922e8a57fdeSmarco errx(1, "invalid flag %s", fs); 923e8a57fdeSmarco } 924e8a57fdeSmarco } 925e8a57fdeSmarco e++; 926e8a57fdeSmarco } 927e8a57fdeSmarco 928e8a57fdeSmarco return (flags); 929e8a57fdeSmarco } 93003b2dfbfShenning 931c7c3e8aaSmarco void 932c7c3e8aaSmarco bio_deleteraid(char *dev) 933c7c3e8aaSmarco { 934c7c3e8aaSmarco struct bioc_deleteraid bd; 935c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 936c7c3e8aaSmarco 937c7c3e8aaSmarco bd.bd_cookie = bd.bd_cookie; 938a15048bbSmarco /* XXX make this a dev_t instead of a string */ 939c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 940c7c3e8aaSmarco if (ioctl(devh, BIOCDELETERAID, &bd)) 941c7c3e8aaSmarco errx(1, "delete volume %s failed", dev); 942c7c3e8aaSmarco } 943c7c3e8aaSmarco 944c6446370Sjsing void 945c6446370Sjsing bio_changepass(char *dev) 946c6446370Sjsing { 947c6446370Sjsing struct bioc_discipline bd; 948c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 949c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 950c6446370Sjsing struct sr_crypto_kdf_pbkdf2 kdfhint; 951c6446370Sjsing int rv; 952c6446370Sjsing 953c6446370Sjsing memset(&bd, 0, sizeof(bd)); 954c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 955c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 956c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 957c6446370Sjsing 958c6446370Sjsing /* XXX use dev_t instead of string. */ 959c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 960c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 961c6446370Sjsing bd.bd_size = sizeof(kdfhint); 962c6446370Sjsing bd.bd_data = &kdfhint; 963c6446370Sjsing 964c6446370Sjsing if (ioctl(devh, BIOCDISCIPLINE, &bd)) 965c6446370Sjsing errx(1, "%s: failed to get KDF hint", dev); 966c6446370Sjsing 967c6446370Sjsing /* Current passphrase. */ 968c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 969c6446370Sjsing 970c6446370Sjsing /* New passphrase. */ 971c6446370Sjsing bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1); 972c6446370Sjsing 973c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 974c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 975c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 976c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 977c6446370Sjsing 978c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 979c6446370Sjsing bd.bd_size = sizeof(kdfpair); 980c6446370Sjsing bd.bd_data = &kdfpair; 981c6446370Sjsing 982c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 983c6446370Sjsing 984c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 985c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 986c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 987c6446370Sjsing 988c6446370Sjsing if (rv) { 989c6446370Sjsing if (errno == EPERM) 990c6446370Sjsing errx(1, "%s: incorrect passphrase", dev); 991c6446370Sjsing else 992c6446370Sjsing errx(1, "%s: failed to change passphrase", dev); 993c6446370Sjsing } 994c6446370Sjsing } 995c6446370Sjsing 99603b2dfbfShenning #define BIOCTL_VIS_NBUF 4 99703b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 99803b2dfbfShenning 99903b2dfbfShenning char * 100003b2dfbfShenning bio_vis(char *s) 100103b2dfbfShenning { 100203b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 100303b2dfbfShenning static uint idx = 0; 100403b2dfbfShenning char *buf; 100503b2dfbfShenning 100603b2dfbfShenning buf = rbuf[idx++]; 100703b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 100803b2dfbfShenning idx = 0; 100903b2dfbfShenning 101003b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 101103b2dfbfShenning return (buf); 101203b2dfbfShenning } 101303b2dfbfShenning 101403b2dfbfShenning void 101503b2dfbfShenning bio_diskinq(char *sd_dev) 101603b2dfbfShenning { 101703b2dfbfShenning struct dk_inquiry di; 101803b2dfbfShenning 1019da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 1020da3b0664Shenning err(1, "DIOCINQ"); 102103b2dfbfShenning 102203b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 102303b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 102403b2dfbfShenning } 1025aef7fe28Shshoexer 1026aef7fe28Shshoexer void 10279e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt, 1028c6446370Sjsing size_t saltsz, char *prompt, int verify) 1029aef7fe28Shshoexer { 103086735da2Smarco FILE *f; 103186735da2Smarco size_t pl; 103286735da2Smarco struct stat sb; 10339e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 1034aef7fe28Shshoexer 1035aef7fe28Shshoexer if (!key) 1036aef7fe28Shshoexer errx(1, "Invalid key"); 1037aef7fe28Shshoexer if (!salt) 1038aef7fe28Shshoexer errx(1, "Invalid salt"); 1039aef7fe28Shshoexer if (rounds < 1000) 1040aef7fe28Shshoexer errx(1, "Too less rounds: %d", rounds); 1041aef7fe28Shshoexer 1042aef7fe28Shshoexer /* get passphrase */ 1043ba3d8661Smarco if (password && verify) 1044ba3d8661Smarco errx(1, "can't specify passphrase file during initial " 1045ba3d8661Smarco "creation of crypto volume"); 1046ba3d8661Smarco if (password) { 104786735da2Smarco if ((f = fopen(password, "r")) == NULL) 104886735da2Smarco err(1, "invalid passphrase file"); 104986735da2Smarco 105086735da2Smarco if (fstat(fileno(f), &sb) == -1) 105186735da2Smarco err(1, "can't stat passphrase file"); 105286735da2Smarco if (sb.st_uid != 0) 105386735da2Smarco errx(1, "passphrase file must be owned by root"); 105486735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 105586735da2Smarco errx(1, "passphrase file has the wrong permissions"); 105686735da2Smarco 105786735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 105886735da2Smarco err(1, "can't read passphrase file"); 105986735da2Smarco pl = strlen(passphrase); 106086735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 106186735da2Smarco passphrase[pl - 1] = '\0'; 106286735da2Smarco else 106386735da2Smarco errx(1, "invalid passphrase length"); 106486735da2Smarco 106586735da2Smarco fclose(f); 1066ba3d8661Smarco } else { 1067c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1068c6446370Sjsing RPP_REQUIRE_TTY) == NULL) 10699e8c6f5bShshoexer errx(1, "unable to read passphrase"); 1070ba3d8661Smarco } 10719e8c6f5bShshoexer 10729e8c6f5bShshoexer if (verify) { 10739e8c6f5bShshoexer /* request user to re-type it */ 10749e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 10759e8c6f5bShshoexer sizeof(verifybuf), RPP_REQUIRE_TTY) == NULL) { 10769e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10779e8c6f5bShshoexer errx(1, "unable to read passphrase"); 10789e8c6f5bShshoexer } 10799e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 10809e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 10819e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10829e8c6f5bShshoexer memset(verifybuf, 0, sizeof(verifybuf)); 10839e8c6f5bShshoexer errx(1, "Passphrases did not match"); 10849e8c6f5bShshoexer } 10859e8c6f5bShshoexer /* forget the re-typed one */ 10869e8c6f5bShshoexer memset(verifybuf, 0, strlen(verifybuf)); 10879e8c6f5bShshoexer } 1088aef7fe28Shshoexer 1089aef7fe28Shshoexer /* derive key from passphrase */ 10905c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 10915c1f8f6bSdjm key, keysz, rounds) != 0) 10925c1f8f6bSdjm errx(1, "pbkdf2 failed"); 1093aef7fe28Shshoexer 1094aef7fe28Shshoexer /* forget passphrase */ 10959e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 1096aef7fe28Shshoexer 1097aef7fe28Shshoexer return; 1098aef7fe28Shshoexer } 1099