1*92d21b5cStedu /* $OpenBSD: bioctl.c,v 1.100 2011/07/04 04:52:34 tedu 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); 740054cd36Sjsing void bio_createraid(u_int16_t, char *, char *); 75c7c3e8aaSmarco void bio_deleteraid(char *); 76c6446370Sjsing void bio_changepass(char *); 77e8a57fdeSmarco u_int32_t bio_createflags(char *); 7803b2dfbfShenning char *bio_vis(char *); 7903b2dfbfShenning void bio_diskinq(char *); 803af9de98Smarco 813af9de98Smarco int devh = -1; 82abe9d68eSderaadt int human; 83abe9d68eSderaadt int verbose; 84e8a57fdeSmarco u_int32_t cflags = 0; 85aedd4f07Sdjm int rflag = 8192; 8686735da2Smarco char *password; 873af9de98Smarco 883af9de98Smarco struct bio_locate bl; 89b96c6ce2Sckuethe int rpp_flag = RPP_REQUIRE_TTY; 903af9de98Smarco 913af9de98Smarco int 923af9de98Smarco main(int argc, char *argv[]) 933af9de98Smarco { 943af9de98Smarco extern char *optarg; 95db2730c1Smarco u_int64_t func = 0; 96db2730c1Smarco /* u_int64_t subfunc = 0; */ 97e63d8b1dSdtucker char *devicename = NULL; 98cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 997195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 1000054cd36Sjsing char *key_disk = NULL; 101aedd4f07Sdjm const char *errstr; 102c6446370Sjsing int ch, rv, blink = 0, changepass = 0, diskinq = 0; 103c6446370Sjsing int ss_func = 0; 1049ecba717Sderaadt u_int16_t cr_level = 0; 105e37c64dbSjsing int biodev = 0; 1063af9de98Smarco 1073af9de98Smarco if (argc < 2) 1083af9de98Smarco usage(); 1093af9de98Smarco 110b96c6ce2Sckuethe while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:Pp:qr:R:svu:")) != 111c6446370Sjsing -1) { 1123af9de98Smarco switch (ch) { 113edfd9792Smarco case 'a': /* alarm */ 114edfd9792Smarco func |= BIOC_ALARM; 115edfd9792Smarco al_arg = optarg; 116edfd9792Smarco break; 117c55617f1Sdlg case 'b': /* blink */ 118c55617f1Sdlg func |= BIOC_BLINK; 119a928c459Sderaadt blink = BIOC_SBBLINK; 120a928c459Sderaadt bl_arg = optarg; 121a928c459Sderaadt break; 122e8a57fdeSmarco case 'C': /* creation flags */ 123e8a57fdeSmarco cflags = bio_createflags(optarg); 124e8a57fdeSmarco break; 1257195049bSmarco case 'c': /* create */ 1267195049bSmarco func |= BIOC_CREATERAID; 127*92d21b5cStedu if (isdigit(*optarg)) { 128*92d21b5cStedu cr_level = strtonum(optarg, 0, 10, &errstr); 129*92d21b5cStedu if (errstr != NULL) 130*92d21b5cStedu errx(1, "Invalid RAID level"); 131*92d21b5cStedu } else 13298b750e4Stedu cr_level = *optarg; 1337195049bSmarco break; 134c7c3e8aaSmarco case 'd': 135c7c3e8aaSmarco /* delete volume */ 136c7c3e8aaSmarco func |= BIOC_DELETERAID; 137c7c3e8aaSmarco break; 138a928c459Sderaadt case 'u': /* unblink */ 139a928c459Sderaadt func |= BIOC_BLINK; 140a928c459Sderaadt blink = BIOC_SBUNBLINK; 141c55617f1Sdlg bl_arg = optarg; 142c55617f1Sdlg break; 1436de960dcSmarco case 'H': /* set hotspare */ 1446de960dcSmarco func |= BIOC_SETSTATE; 145a15048bbSmarco ss_func = BIOC_SSHOTSPARE; 1466de960dcSmarco al_arg = optarg; 1476de960dcSmarco break; 1488ccdd032Sderaadt case 'h': 1498ccdd032Sderaadt human = 1; 1508ccdd032Sderaadt break; 151db2730c1Smarco case 'i': /* inquiry */ 152db2730c1Smarco func |= BIOC_INQ; 1533af9de98Smarco break; 1540054cd36Sjsing case 'k': /* Key disk. */ 1550054cd36Sjsing key_disk = optarg; 1560054cd36Sjsing break; 1577195049bSmarco case 'l': /* device list */ 1587195049bSmarco func |= BIOC_DEVLIST; 1597195049bSmarco dev_list = optarg; 1607195049bSmarco break; 161c6446370Sjsing case 'P': 162c6446370Sjsing /* Change passphrase. */ 163c6446370Sjsing changepass = 1; 164c6446370Sjsing break; 16586735da2Smarco case 'p': 16686735da2Smarco password = optarg; 16786735da2Smarco break; 168aedd4f07Sdjm case 'r': 169aedd4f07Sdjm rflag = strtonum(optarg, 1000, 1<<30, &errstr); 170aedd4f07Sdjm if (errstr != NULL) 171aedd4f07Sdjm errx(1, "Number of rounds is %s: %s", 172aedd4f07Sdjm errstr, optarg); 173aedd4f07Sdjm break; 174a15048bbSmarco case 'R': 175a15048bbSmarco /* rebuild to provided chunk/CTL */ 176a15048bbSmarco func |= BIOC_SETSTATE; 177a15048bbSmarco ss_func = BIOC_SSREBUILD; 178a15048bbSmarco al_arg = optarg; 179a15048bbSmarco break; 180b96c6ce2Sckuethe case 's': 181b96c6ce2Sckuethe rpp_flag = RPP_STDIN; 182b96c6ce2Sckuethe break; 183abe9d68eSderaadt case 'v': 184abe9d68eSderaadt verbose = 1; 185abe9d68eSderaadt break; 18603b2dfbfShenning case 'q': 18703b2dfbfShenning diskinq = 1; 18803b2dfbfShenning break; 1893af9de98Smarco default: 1903af9de98Smarco usage(); 1913af9de98Smarco /* NOTREACHED */ 1923af9de98Smarco } 1933af9de98Smarco } 194cf6503d7Sderaadt argc -= optind; 195cf6503d7Sderaadt argv += optind; 1963af9de98Smarco 197c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 198cf6503d7Sderaadt usage(); 199cf6503d7Sderaadt 200dcbaf4c8Sderaadt if (func == 0) 201dcbaf4c8Sderaadt func |= BIOC_INQ; 202dcbaf4c8Sderaadt 203e63d8b1dSdtucker devicename = argv[0]; 204e63d8b1dSdtucker if (devicename == NULL) 205e37c64dbSjsing errx(1, "need device"); 20610b411a7Smarco 207e63d8b1dSdtucker devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname); 208e37c64dbSjsing if (devh == -1) { 20941eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2103af9de98Smarco if (devh == -1) 21141eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2123af9de98Smarco 213e63d8b1dSdtucker bl.bl_name = devicename; 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"); 218e37c64dbSjsing biodev = 1; 219e63d8b1dSdtucker devicename = NULL; 220e37c64dbSjsing } 2213af9de98Smarco 22203b2dfbfShenning if (diskinq) { 223e63d8b1dSdtucker bio_diskinq(devicename); 224e37c64dbSjsing } else if (changepass && !biodev) { 225e63d8b1dSdtucker bio_changepass(devicename); 22603b2dfbfShenning } else if (func & BIOC_INQ) { 227e63d8b1dSdtucker bio_inq(devicename); 228edfd9792Smarco } else if (func == BIOC_ALARM) { 229edfd9792Smarco bio_alarm(al_arg); 230c55617f1Sdlg } else if (func == BIOC_BLINK) { 231e63d8b1dSdtucker bio_setblink(devicename, bl_arg, blink); 2326de960dcSmarco } else if (func == BIOC_SETSTATE) { 233a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 234e37c64dbSjsing } else if (func == BIOC_DELETERAID && !biodev) { 235e63d8b1dSdtucker bio_deleteraid(devicename); 2367195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2377195049bSmarco if (!(func & BIOC_CREATERAID)) 2387195049bSmarco errx(1, "need -c parameter"); 2397195049bSmarco if (!(func & BIOC_DEVLIST)) 2407195049bSmarco errx(1, "need -l parameter"); 241e37c64dbSjsing if (!biodev) 242e37c64dbSjsing errx(1, "must use bio device"); 2430054cd36Sjsing bio_createraid(cr_level, dev_list, key_disk); 2443af9de98Smarco } 2453af9de98Smarco 2463af9de98Smarco return (0); 2473af9de98Smarco } 2483af9de98Smarco 2493af9de98Smarco void 2503af9de98Smarco usage(void) 2513af9de98Smarco { 2523af9de98Smarco extern char *__progname; 2533af9de98Smarco 254d90b5d8bSjmc fprintf(stderr, 255d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 256d90b5d8bSjmc "[-b channel:target[.lun]]\n" 257d0b772c8Sjmc "\t[-H channel:target[.lun]] " 258d0b772c8Sjmc "[-R device | channel:target[.lun]\n" 259d0b772c8Sjmc "\t[-u channel:target[.lun]] " 260d0b772c8Sjmc "device\n" 261b96c6ce2Sckuethe " %s [-dhiPqsv] " 262b90fdff5Sjmc "[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n" 26378702060Sjmc "\t[-l special[,special,...]] [-p passfile]\n" 26478702060Sjmc "\t[-R device | channel:target[.lun] [-r rounds] " 265d0b772c8Sjmc "device\n", __progname, __progname); 266d90b5d8bSjmc 2673af9de98Smarco exit(1); 2683af9de98Smarco } 2693af9de98Smarco 27041eccc89Sderaadt const char * 2716de960dcSmarco str2locator(const char *string, struct locator *location) 2726de960dcSmarco { 27350d3c4dcSdlg const char *errstr; 27441eccc89Sderaadt char parse[80], *targ, *lun; 2756de960dcSmarco 27641eccc89Sderaadt strlcpy(parse, string, sizeof parse); 27741eccc89Sderaadt targ = strchr(parse, ':'); 2786de960dcSmarco if (targ == NULL) 27941eccc89Sderaadt return ("target not specified"); 2806de960dcSmarco *targ++ = '\0'; 2816de960dcSmarco 28250d3c4dcSdlg lun = strchr(targ, '.'); 2836de960dcSmarco if (lun != NULL) { 2846de960dcSmarco *lun++ = '\0'; 28550d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 28650d3c4dcSdlg if (errstr) 28741eccc89Sderaadt return (errstr); 2886de960dcSmarco } else 2896de960dcSmarco location->lun = 0; 2906de960dcSmarco 29150d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 29250d3c4dcSdlg if (errstr) 29341eccc89Sderaadt return (errstr); 29441eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 29550d3c4dcSdlg if (errstr) 29641eccc89Sderaadt return (errstr); 29741eccc89Sderaadt return (NULL); 2986de960dcSmarco } 2996de960dcSmarco 3003af9de98Smarco void 3018ccdd032Sderaadt bio_inq(char *name) 302d4546a56Sdlg { 3039017fb97Sderaadt char *status, size[64], scsiname[16], volname[32]; 304a4d3c4a2Sderaadt char percent[10], seconds[20]; 305b9950701Smarco int rv, i, d, volheader, hotspare, unused; 306aa65acf1Sderaadt char encname[16], serial[32]; 3078ccdd032Sderaadt struct bioc_disk bd; 3088ccdd032Sderaadt struct bioc_inq bi; 3098ccdd032Sderaadt struct bioc_vol bv; 310db2730c1Smarco 311db2730c1Smarco memset(&bi, 0, sizeof(bi)); 3123af9de98Smarco 3138ccdd032Sderaadt bi.bi_cookie = bl.bl_cookie; 3143af9de98Smarco 315db2730c1Smarco rv = ioctl(devh, BIOCINQ, &bi); 3163af9de98Smarco if (rv == -1) { 31703b2dfbfShenning if (errno == ENOTTY) 31803b2dfbfShenning bio_diskinq(name); 31903b2dfbfShenning else 320da3b0664Shenning err(1, "BIOCINQ"); 3213af9de98Smarco return; 3223af9de98Smarco } 3233af9de98Smarco 3248ccdd032Sderaadt volheader = 0; 3258ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 326db2730c1Smarco memset(&bv, 0, sizeof(bv)); 3278ccdd032Sderaadt bv.bv_cookie = bl.bl_cookie; 3288ccdd032Sderaadt bv.bv_volid = i; 3290a92ff65Sderaadt bv.bv_percent = -1; 3309017fb97Sderaadt bv.bv_seconds = 0; 33170a2ae7bSmarco 332db2730c1Smarco rv = ioctl(devh, BIOCVOL, &bv); 333da3b0664Shenning if (rv == -1) 334da3b0664Shenning err(1, "BIOCVOL"); 3353af9de98Smarco 3368ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 3378ccdd032Sderaadt continue; 3388ccdd032Sderaadt 3398ccdd032Sderaadt if (!volheader) { 3408ccdd032Sderaadt volheader = 1; 341150c22bbSjcs printf("%-11s %-10s %14s %-8s\n", 3428ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 3438ccdd032Sderaadt } 3448ccdd032Sderaadt 3450a92ff65Sderaadt percent[0] = '\0'; 3469017fb97Sderaadt seconds[0] = '\0'; 3470a92ff65Sderaadt if (bv.bv_percent != -1) 3480a92ff65Sderaadt snprintf(percent, sizeof percent, 3490a92ff65Sderaadt " %d%% done", bv.bv_percent); 3509017fb97Sderaadt if (bv.bv_seconds) 3519017fb97Sderaadt snprintf(seconds, sizeof seconds, 3529017fb97Sderaadt " %u seconds", bv.bv_seconds); 3538ccdd032Sderaadt switch (bv.bv_status) { 354db2730c1Smarco case BIOC_SVONLINE: 3558ccdd032Sderaadt status = BIOC_SVONLINE_S; 356db2730c1Smarco break; 357db2730c1Smarco case BIOC_SVOFFLINE: 3588ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 359db2730c1Smarco break; 360db2730c1Smarco case BIOC_SVDEGRADED: 3618ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 362db2730c1Smarco break; 3630a92ff65Sderaadt case BIOC_SVBUILDING: 3640a92ff65Sderaadt status = BIOC_SVBUILDING_S; 3650a92ff65Sderaadt break; 3660a92ff65Sderaadt case BIOC_SVREBUILD: 3670a92ff65Sderaadt status = BIOC_SVREBUILD_S; 3680a92ff65Sderaadt break; 3690a92ff65Sderaadt case BIOC_SVSCRUB: 3700a92ff65Sderaadt status = BIOC_SVSCRUB_S; 3710a92ff65Sderaadt break; 372db2730c1Smarco case BIOC_SVINVALID: 373db2730c1Smarco default: 3748ccdd032Sderaadt status = BIOC_SVINVALID_S; 375d4546a56Sdlg } 3763af9de98Smarco 377aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 3788ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 379b9950701Smarco 3809ecba717Sderaadt unused = 0; 3819ecba717Sderaadt hotspare = 0; 382aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 383aa65acf1Sderaadt hotspare = 1; 384b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 385b9950701Smarco unused = 1; 386aa65acf1Sderaadt else { 3878ccdd032Sderaadt if (human) 3888ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 3898ccdd032Sderaadt else 3908ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 3918ccdd032Sderaadt bv.bv_size); 392da935596Stodd switch (bv.bv_level) { 393da935596Stodd case 'C': 394150c22bbSjcs printf("%11s %-10s %14s %-7s CRYPTO%s%s\n", 395da935596Stodd volname, status, size, bv.bv_dev, 396da935596Stodd percent, seconds); 397da935596Stodd break; 398da935596Stodd default: 399150c22bbSjcs printf("%11s %-10s %14s %-7s RAID%u%s%s\n", 4000a92ff65Sderaadt volname, status, size, bv.bv_dev, 4019017fb97Sderaadt bv.bv_level, percent, seconds); 402da935596Stodd break; 403da935596Stodd } 404da935596Stodd 405aa65acf1Sderaadt } 4068ccdd032Sderaadt 4078ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 408db2730c1Smarco memset(&bd, 0, sizeof(bd)); 4098ccdd032Sderaadt bd.bd_cookie = bl.bl_cookie; 4108ccdd032Sderaadt bd.bd_diskid = d; 4118ccdd032Sderaadt bd.bd_volid = i; 4123af9de98Smarco 413db2730c1Smarco rv = ioctl(devh, BIOCDISK, &bd); 414da3b0664Shenning if (rv == -1) 415da3b0664Shenning err(1, "BIOCDISK"); 4163af9de98Smarco 4178ccdd032Sderaadt switch (bd.bd_status) { 418db2730c1Smarco case BIOC_SDONLINE: 4198ccdd032Sderaadt status = BIOC_SDONLINE_S; 420d4546a56Sdlg break; 421db2730c1Smarco case BIOC_SDOFFLINE: 4228ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 423d4546a56Sdlg break; 424db2730c1Smarco case BIOC_SDFAILED: 4258ccdd032Sderaadt status = BIOC_SDFAILED_S; 426db2730c1Smarco break; 427db2730c1Smarco case BIOC_SDREBUILD: 4288ccdd032Sderaadt status = BIOC_SDREBUILD_S; 429db2730c1Smarco break; 430db2730c1Smarco case BIOC_SDHOTSPARE: 4318ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 432db2730c1Smarco break; 433db2730c1Smarco case BIOC_SDUNUSED: 4348ccdd032Sderaadt status = BIOC_SDUNUSED_S; 435db2730c1Smarco break; 436e1dfb373Sderaadt case BIOC_SDSCRUB: 437e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 438e1dfb373Sderaadt break; 439db2730c1Smarco case BIOC_SDINVALID: 440d4546a56Sdlg default: 4418ccdd032Sderaadt status = BIOC_SDINVALID_S; 442d4546a56Sdlg } 443aa65acf1Sderaadt 444b9950701Smarco if (hotspare || unused) 445aa65acf1Sderaadt ; /* use volname from parent volume */ 446aa65acf1Sderaadt else 447aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 448aa65acf1Sderaadt bd.bd_diskid); 449aa65acf1Sderaadt 4500054cd36Sjsing if (bv.bv_level == 'C' && bd.bd_size == 0) 4510054cd36Sjsing snprintf(size, sizeof size, "%14s", "key disk"); 4520054cd36Sjsing else if (human) 4538ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 4548ccdd032Sderaadt else 4558ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4568ccdd032Sderaadt bd.bd_size); 4578ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 45843d61178Sderaadt "%u:%u.%u", 45943d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 4605978b28dSderaadt if (bd.bd_procdev[0]) 461abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 4625978b28dSderaadt else 463abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 464abe9d68eSderaadt if (bd.bd_serial[0]) 465abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 466abe9d68eSderaadt else 467abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 4688ccdd032Sderaadt 469150c22bbSjcs printf("%11s %-10s %14s %-7s %-6s <%s>\n", 470aa65acf1Sderaadt volname, status, size, scsiname, encname, 4718ccdd032Sderaadt bd.bd_vendor); 472abe9d68eSderaadt if (verbose) 473aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s '%s'\n", 474abe9d68eSderaadt "", "", "", "", "", serial); 475d4546a56Sdlg } 476d4546a56Sdlg } 477d4546a56Sdlg } 478edfd9792Smarco 479edfd9792Smarco void 480edfd9792Smarco bio_alarm(char *arg) 481edfd9792Smarco { 482edfd9792Smarco int rv; 4838ccdd032Sderaadt struct bioc_alarm ba; 484edfd9792Smarco 4858ccdd032Sderaadt ba.ba_cookie = bl.bl_cookie; 486edfd9792Smarco 487edfd9792Smarco switch (arg[0]) { 488edfd9792Smarco case 'q': /* silence alarm */ 489edfd9792Smarco /* FALLTHROUGH */ 490edfd9792Smarco case 's': 4918ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 492edfd9792Smarco break; 493edfd9792Smarco 494edfd9792Smarco case 'e': /* enable alarm */ 4958ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 496edfd9792Smarco break; 497edfd9792Smarco 498edfd9792Smarco case 'd': /* disable alarm */ 4998ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 500edfd9792Smarco break; 501edfd9792Smarco 502edfd9792Smarco case 't': /* test alarm */ 5038ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 504edfd9792Smarco break; 505edfd9792Smarco 506edfd9792Smarco case 'g': /* get alarm state */ 5078ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 508edfd9792Smarco break; 509edfd9792Smarco 510edfd9792Smarco default: 511da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 512edfd9792Smarco } 513edfd9792Smarco 514edfd9792Smarco rv = ioctl(devh, BIOCALARM, &ba); 515da3b0664Shenning if (rv == -1) 516da3b0664Shenning err(1, "BIOCALARM"); 517edfd9792Smarco 518edfd9792Smarco if (arg[0] == 'g') { 519edfd9792Smarco printf("alarm is currently %s\n", 5208ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 5218ccdd032Sderaadt 522edfd9792Smarco } 523edfd9792Smarco } 5246de960dcSmarco 525a15048bbSmarco int 526a15048bbSmarco bio_getvolbyname(char *name) 527a15048bbSmarco { 528a15048bbSmarco int id = -1, i, rv; 529a15048bbSmarco struct bioc_inq bi; 530a15048bbSmarco struct bioc_vol bv; 531a15048bbSmarco 532a15048bbSmarco memset(&bi, 0, sizeof(bi)); 533a15048bbSmarco bi.bi_cookie = bl.bl_cookie; 534a15048bbSmarco rv = ioctl(devh, BIOCINQ, &bi); 535a15048bbSmarco if (rv == -1) 536a15048bbSmarco err(1, "BIOCINQ"); 537a15048bbSmarco 538a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 539a15048bbSmarco memset(&bv, 0, sizeof(bv)); 540a15048bbSmarco bv.bv_cookie = bl.bl_cookie; 541a15048bbSmarco bv.bv_volid = i; 542a15048bbSmarco rv = ioctl(devh, BIOCVOL, &bv); 543a15048bbSmarco if (rv == -1) 544a15048bbSmarco err(1, "BIOCVOL"); 545a15048bbSmarco 546a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 547a15048bbSmarco continue; 548a15048bbSmarco id = i; 549a15048bbSmarco break; 550a15048bbSmarco } 551a15048bbSmarco 552a15048bbSmarco return (id); 553a15048bbSmarco } 554a15048bbSmarco 555ebaf584eSderaadt void 5568d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 5576de960dcSmarco { 5586de960dcSmarco struct bioc_setstate bs; 5596de960dcSmarco struct locator location; 560a15048bbSmarco struct stat sb; 56141eccc89Sderaadt const char *errstr; 562ebaf584eSderaadt int rv; 5636de960dcSmarco 564a15048bbSmarco memset(&bs, 0, sizeof(bs)); 565a15048bbSmarco if (stat(arg, &sb) == -1) { 566a15048bbSmarco /* use CTL */ 56741eccc89Sderaadt errstr = str2locator(arg, &location); 56841eccc89Sderaadt if (errstr) 56941eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 5706de960dcSmarco bs.bs_channel = location.channel; 5716de960dcSmarco bs.bs_target = location.target; 5726de960dcSmarco bs.bs_lun = location.lun; 573a15048bbSmarco } else { 574a15048bbSmarco /* use other id */ 575a15048bbSmarco bs.bs_other_id = sb.st_rdev; 576a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 577a15048bbSmarco } 578a15048bbSmarco 579a15048bbSmarco bs.bs_cookie = bl.bl_cookie; 580a15048bbSmarco bs.bs_status = status; 581a15048bbSmarco 582d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 583a15048bbSmarco /* make sure user supplied a sd device */ 5848d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 585a15048bbSmarco if (bs.bs_volid == -1) 5868d8693a2Sdtucker errx(1, "invalid device %s", devicename); 587d2647ac1Sjsing } 5886de960dcSmarco 5896de960dcSmarco rv = ioctl(devh, BIOCSETSTATE, &bs); 590da3b0664Shenning if (rv == -1) 591da3b0664Shenning err(1, "BIOCSETSTATE"); 5926de960dcSmarco } 593c55617f1Sdlg 594c55617f1Sdlg void 595a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 596c55617f1Sdlg { 59750d3c4dcSdlg struct locator location; 59850d3c4dcSdlg struct bioc_inq bi; 59950d3c4dcSdlg struct bioc_vol bv; 60050d3c4dcSdlg struct bioc_disk bd; 6010505205bSdlg struct bioc_blink bb; 60241eccc89Sderaadt const char *errstr; 60350d3c4dcSdlg int v, d, rv; 604c55617f1Sdlg 60541eccc89Sderaadt errstr = str2locator(arg, &location); 60641eccc89Sderaadt if (errstr) 60741eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 60850d3c4dcSdlg 6090505205bSdlg /* try setting blink on the device directly */ 6100505205bSdlg memset(&bb, 0, sizeof(bb)); 6110505205bSdlg bb.bb_cookie = bl.bl_cookie; 6120505205bSdlg bb.bb_status = blink; 6130505205bSdlg bb.bb_target = location.target; 614649724a4Smarco bb.bb_channel = location.channel; 6150505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 6160505205bSdlg if (rv == 0) 6170505205bSdlg return; 6180505205bSdlg 619855d4e83Ssobrado /* if the blink didn't work, try to find something that will */ 6200505205bSdlg 62150d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 62250d3c4dcSdlg bi.bi_cookie = bl.bl_cookie; 62350d3c4dcSdlg rv = ioctl(devh, BIOCINQ, &bi); 624da3b0664Shenning if (rv == -1) 625da3b0664Shenning err(1, "BIOCINQ"); 62650d3c4dcSdlg 62750d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 62850d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 62950d3c4dcSdlg bv.bv_cookie = bl.bl_cookie; 63050d3c4dcSdlg bv.bv_volid = v; 63150d3c4dcSdlg rv = ioctl(devh, BIOCVOL, &bv); 632da3b0664Shenning if (rv == -1) 633da3b0664Shenning err(1, "BIOCVOL"); 63450d3c4dcSdlg 63550d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 63650d3c4dcSdlg continue; 63750d3c4dcSdlg 63850d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 63950d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 64050d3c4dcSdlg bd.bd_cookie = bl.bl_cookie; 64150d3c4dcSdlg bd.bd_volid = v; 64250d3c4dcSdlg bd.bd_diskid = d; 64350d3c4dcSdlg 64450d3c4dcSdlg rv = ioctl(devh, BIOCDISK, &bd); 645da3b0664Shenning if (rv == -1) 646da3b0664Shenning err(1, "BIOCDISK"); 64750d3c4dcSdlg 64850d3c4dcSdlg if (bd.bd_channel == location.channel && 64950d3c4dcSdlg bd.bd_target == location.target && 65050d3c4dcSdlg bd.bd_lun == location.lun) { 65150d3c4dcSdlg if (bd.bd_procdev[0] != '\0') { 65250d3c4dcSdlg bio_blink(bd.bd_procdev, 653a928c459Sderaadt location.target, blink); 65450d3c4dcSdlg } else 65541eccc89Sderaadt warnx("Disk %s is not in an enclosure", arg); 65650d3c4dcSdlg return; 65750d3c4dcSdlg } 65850d3c4dcSdlg } 65950d3c4dcSdlg } 66050d3c4dcSdlg 66141eccc89Sderaadt warnx("Disk %s does not exist", arg); 66250d3c4dcSdlg return; 66350d3c4dcSdlg } 66450d3c4dcSdlg 66550d3c4dcSdlg void 666a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 66750d3c4dcSdlg { 66850d3c4dcSdlg int bioh; 66950d3c4dcSdlg struct bio_locate bio; 67050d3c4dcSdlg struct bioc_blink blink; 67150d3c4dcSdlg int rv; 67250d3c4dcSdlg 67341eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 67450d3c4dcSdlg if (bioh == -1) 67541eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 67650d3c4dcSdlg 67750d3c4dcSdlg bio.bl_name = enclosure; 67850d3c4dcSdlg rv = ioctl(bioh, BIOCLOCATE, &bio); 67950d3c4dcSdlg if (rv == -1) 68041eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 681c55617f1Sdlg 682c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 68350d3c4dcSdlg blink.bb_cookie = bio.bl_cookie; 684a928c459Sderaadt blink.bb_status = blinktype; 685c55617f1Sdlg blink.bb_target = target; 686c55617f1Sdlg 68750d3c4dcSdlg rv = ioctl(bioh, BIOCBLINK, &blink); 688c55617f1Sdlg if (rv == -1) 689da3b0664Shenning err(1, "BIOCBLINK"); 69050d3c4dcSdlg 69150d3c4dcSdlg close(bioh); 692c55617f1Sdlg } 6937195049bSmarco 6947195049bSmarco void 6950054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk) 6967195049bSmarco { 6977195049bSmarco struct bioc_createraid create; 698aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 699aef7fe28Shshoexer struct sr_crypto_kdf_pbkdf2 kdfhint; 7000054cd36Sjsing struct stat sb; 7018b0d0f28Sjsing int rv, no_dev, fd; 7027f8eae2bSnicm dev_t *dt; 7037195049bSmarco u_int16_t min_disks = 0; 7047195049bSmarco 7057195049bSmarco if (!dev_list) 7067195049bSmarco errx(1, "no devices specified"); 7077195049bSmarco 70846bc198bSmarco dt = (dev_t *)malloc(BIOC_CRMAXLEN); 70946bc198bSmarco if (!dt) 71046bc198bSmarco err(1, "not enough memory for dev_t list"); 71146bc198bSmarco memset(dt, 0, BIOC_CRMAXLEN); 71246bc198bSmarco 71346bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 71446bc198bSmarco 7157195049bSmarco switch (level) { 7167195049bSmarco case 0: 71784e48fabSmarco min_disks = 2; 7187195049bSmarco break; 7197195049bSmarco case 1: 7207195049bSmarco min_disks = 2; 7217195049bSmarco break; 722e717853eSmarco case 4: 723e717853eSmarco case 5: 724e717853eSmarco min_disks = 3; 725e717853eSmarco break; 72684e48fabSmarco case 'C': 727aef7fe28Shshoexer min_disks = 1; 72884e48fabSmarco break; 72998b750e4Stedu case 'c': 73098b750e4Stedu min_disks = 1; 73198b750e4Stedu break; 7327195049bSmarco default: 73323afedbfSgrunk errx(1, "unsupported raid level"); 7347195049bSmarco } 7357195049bSmarco 73684e48fabSmarco if (no_dev < min_disks) 73784e48fabSmarco errx(1, "not enough disks"); 73884e48fabSmarco 739aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 740aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 741818b0595Shalex errx(1, "not exactly one partition"); 742aef7fe28Shshoexer 7437195049bSmarco memset(&create, 0, sizeof(create)); 7447195049bSmarco create.bc_cookie = bl.bl_cookie; 7457195049bSmarco create.bc_level = level; 74646bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 74746bc198bSmarco create.bc_dev_list = dt; 748e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 7490054cd36Sjsing create.bc_key_disk = NODEV; 7507195049bSmarco 7510054cd36Sjsing if (level == 'C' && key_disk == NULL) { 7520054cd36Sjsing 753aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 754aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 755aef7fe28Shshoexer 7560054cd36Sjsing create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 7570054cd36Sjsing 758aef7fe28Shshoexer create.bc_opaque = &kdfhint; 759aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 760aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 761aef7fe28Shshoexer 762aef7fe28Shshoexer /* try to get KDF hint */ 76383e979edShshoexer if (ioctl(devh, BIOCCREATERAID, &create) == -1) 76483e979edShshoexer err(1, "ioctl"); 76583e979edShshoexer 76683e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 767c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 768aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 769aef7fe28Shshoexer } else { 770aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 771aef7fe28Shshoexer } 772aef7fe28Shshoexer 773aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 774aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 775aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 7760054cd36Sjsing 7770054cd36Sjsing } else if (level == 'C' && key_disk != NULL) { 7780054cd36Sjsing 7798b0d0f28Sjsing /* Get device number for key disk. */ 7808b0d0f28Sjsing fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL); 7818b0d0f28Sjsing if (fd == -1) 7828b0d0f28Sjsing err(1, "could not open %s", key_disk); 7838b0d0f28Sjsing if (fstat(fd, &sb) == -1) { 7848b0d0f28Sjsing close(fd); 7850054cd36Sjsing err(1, "could not stat %s", key_disk); 7868b0d0f28Sjsing } 7878b0d0f28Sjsing close(fd); 7880054cd36Sjsing create.bc_key_disk = sb.st_rdev; 7890054cd36Sjsing 7900054cd36Sjsing memset(&kdfinfo, 0, sizeof(kdfinfo)); 7910054cd36Sjsing 7920054cd36Sjsing kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf); 7930054cd36Sjsing kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK; 7940054cd36Sjsing kdfinfo.len = sizeof(kdfinfo); 7950054cd36Sjsing kdfinfo.flags = SR_CRYPTOKDF_HINT; 7960054cd36Sjsing 7970054cd36Sjsing create.bc_opaque = &kdfinfo; 7980054cd36Sjsing create.bc_opaque_size = sizeof(kdfinfo); 7990054cd36Sjsing create.bc_opaque_flags = BIOC_SOIN; 8000054cd36Sjsing 801aef7fe28Shshoexer } 802aef7fe28Shshoexer 8037195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 804aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 80583e979edShshoexer memset(&create, 0, sizeof(create)); 806a83e4577Sdjm if (rv == -1) { 807a83e4577Sdjm if (errno == EPERM) 808a83e4577Sdjm errx(1, "Incorrect passphrase"); 809da3b0664Shenning err(1, "BIOCCREATERAID"); 810a83e4577Sdjm } 81146bc198bSmarco 81246bc198bSmarco free(dt); 81346bc198bSmarco } 81446bc198bSmarco 815aef7fe28Shshoexer void 816aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 817c6446370Sjsing *kdfhint, char* prompt, int verify) 818aef7fe28Shshoexer { 819aef7fe28Shshoexer if (!kdfinfo) 820aef7fe28Shshoexer errx(1, "invalid KDF info"); 821aef7fe28Shshoexer if (!kdfhint) 822aef7fe28Shshoexer errx(1, "invalid KDF hint"); 823aef7fe28Shshoexer 824aef7fe28Shshoexer if (kdfhint->len != sizeof(*kdfhint)) 825aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 826aef7fe28Shshoexer if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2) 827aef7fe28Shshoexer errx(1, "unknown KDF type %d", kdfhint->type); 828aef7fe28Shshoexer if (kdfhint->rounds < 1000) 829aef7fe28Shshoexer errx(1, "number of KDF rounds too low: %d", kdfhint->rounds); 830aef7fe28Shshoexer 831aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 832aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 833aef7fe28Shshoexer 8349e8c6f5bShshoexer derive_key_pkcs(kdfhint->rounds, 835aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 836c6446370Sjsing kdfhint->salt, sizeof(kdfhint->salt), prompt, verify); 837aef7fe28Shshoexer } 838aef7fe28Shshoexer 839aef7fe28Shshoexer void 840aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 841aef7fe28Shshoexer { 842aef7fe28Shshoexer if (!kdfinfo) 843aef7fe28Shshoexer errx(1, "invalid KDF info"); 844aef7fe28Shshoexer 845aef7fe28Shshoexer kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 846aef7fe28Shshoexer kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 847aedd4f07Sdjm kdfinfo->pbkdf2.rounds = rflag; 848aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 8490054cd36Sjsing kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT; 850aef7fe28Shshoexer 851aef7fe28Shshoexer /* generate salt */ 852aef7fe28Shshoexer arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 853aef7fe28Shshoexer 8549e8c6f5bShshoexer derive_key_pkcs(kdfinfo->pbkdf2.rounds, 855aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 856c6446370Sjsing kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 857c6446370Sjsing "New passphrase: ", 1); 858aef7fe28Shshoexer } 859aef7fe28Shshoexer 86046bc198bSmarco int 86146bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 86246bc198bSmarco { 86346bc198bSmarco char *s, *e; 86446bc198bSmarco u_int32_t sz = 0; 86546bc198bSmarco int no_dev = 0, i, x; 86646bc198bSmarco struct stat sb; 8675c1f8f6bSdjm char dev[MAXPATHLEN]; 868e37c64dbSjsing int fd; 86946bc198bSmarco 87046bc198bSmarco if (!lst) 87146bc198bSmarco errx(1, "invalid device list"); 87246bc198bSmarco 87346bc198bSmarco s = e = lst; 87446bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 87546bc198bSmarco while (*e != '\0') { 87646bc198bSmarco if (*e == ',') 87746bc198bSmarco s = e + 1; 87846bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 87946bc198bSmarco /* got one */ 88046bc198bSmarco sz = e - s + 1; 8815c1f8f6bSdjm strlcpy(dev, s, sz + 1); 882e37c64dbSjsing fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL); 883e37c64dbSjsing if (fd == -1) 884e37c64dbSjsing err(1, "could not open %s", dev); 885e37c64dbSjsing if (fstat(fd, &sb) == -1) { 886e37c64dbSjsing close(fd); 8875c1f8f6bSdjm err(1, "could not stat %s", dev); 888e37c64dbSjsing } 889e37c64dbSjsing close(fd); 89046bc198bSmarco dt[no_dev] = sb.st_rdev; 89146bc198bSmarco no_dev++; 8925c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 89346bc198bSmarco errx(1, "too many devices on device list"); 89446bc198bSmarco } 89546bc198bSmarco e++; 89646bc198bSmarco } 89746bc198bSmarco 89846bc198bSmarco for (i = 0; i < no_dev; i++) 89946bc198bSmarco for (x = 0; x < no_dev; x++) 90046bc198bSmarco if (dt[i] == dt[x] && x != i) 90146bc198bSmarco errx(1, "duplicate device in list"); 90246bc198bSmarco 90346bc198bSmarco return (no_dev); 9047195049bSmarco } 905e8a57fdeSmarco 906e8a57fdeSmarco u_int32_t 907e8a57fdeSmarco bio_createflags(char *lst) 908e8a57fdeSmarco { 909e8a57fdeSmarco char *s, *e, fs[32]; 910e8a57fdeSmarco u_int32_t sz = 0; 911e8a57fdeSmarco u_int32_t flags = 0; 912e8a57fdeSmarco 913e8a57fdeSmarco if (!lst) 914e8a57fdeSmarco errx(1, "invalid flags list"); 915e8a57fdeSmarco 916e8a57fdeSmarco s = e = lst; 917e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 918e8a57fdeSmarco while (*e != '\0') { 919e8a57fdeSmarco if (*e == ',') 920e8a57fdeSmarco s = e + 1; 921e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 922e8a57fdeSmarco /* got one */ 923e8a57fdeSmarco sz = e - s + 1; 924e8a57fdeSmarco switch (s[0]) { 925e8a57fdeSmarco case 'f': 926e8a57fdeSmarco flags |= BIOC_SCFORCE; 927e8a57fdeSmarco break; 928e8a57fdeSmarco case 'n': 929e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 930e8a57fdeSmarco break; 931e8a57fdeSmarco default: 932e8a57fdeSmarco strlcpy(fs, s, sz + 1); 933e8a57fdeSmarco errx(1, "invalid flag %s", fs); 934e8a57fdeSmarco } 935e8a57fdeSmarco } 936e8a57fdeSmarco e++; 937e8a57fdeSmarco } 938e8a57fdeSmarco 939e8a57fdeSmarco return (flags); 940e8a57fdeSmarco } 94103b2dfbfShenning 942c7c3e8aaSmarco void 943c7c3e8aaSmarco bio_deleteraid(char *dev) 944c7c3e8aaSmarco { 945c7c3e8aaSmarco struct bioc_deleteraid bd; 946c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 947c7c3e8aaSmarco 948c7c3e8aaSmarco bd.bd_cookie = bd.bd_cookie; 949a15048bbSmarco /* XXX make this a dev_t instead of a string */ 950c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 951c7c3e8aaSmarco if (ioctl(devh, BIOCDELETERAID, &bd)) 952c7c3e8aaSmarco errx(1, "delete volume %s failed", dev); 953c7c3e8aaSmarco } 954c7c3e8aaSmarco 955c6446370Sjsing void 956c6446370Sjsing bio_changepass(char *dev) 957c6446370Sjsing { 958c6446370Sjsing struct bioc_discipline bd; 959c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 960c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 961c6446370Sjsing struct sr_crypto_kdf_pbkdf2 kdfhint; 962c6446370Sjsing int rv; 963c6446370Sjsing 964c6446370Sjsing memset(&bd, 0, sizeof(bd)); 965c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 966c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 967c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 968c6446370Sjsing 969c6446370Sjsing /* XXX use dev_t instead of string. */ 970c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 971c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 972c6446370Sjsing bd.bd_size = sizeof(kdfhint); 973c6446370Sjsing bd.bd_data = &kdfhint; 974c6446370Sjsing 975c6446370Sjsing if (ioctl(devh, BIOCDISCIPLINE, &bd)) 976c6446370Sjsing errx(1, "%s: failed to get KDF hint", dev); 977c6446370Sjsing 978c6446370Sjsing /* Current passphrase. */ 979c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 980c6446370Sjsing 981c6446370Sjsing /* New passphrase. */ 982c6446370Sjsing bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1); 983c6446370Sjsing 984c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 985c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 986c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 987c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 988c6446370Sjsing 989c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 990c6446370Sjsing bd.bd_size = sizeof(kdfpair); 991c6446370Sjsing bd.bd_data = &kdfpair; 992c6446370Sjsing 993c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 994c6446370Sjsing 995c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 996c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 997c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 998c6446370Sjsing 999c6446370Sjsing if (rv) { 1000c6446370Sjsing if (errno == EPERM) 1001c6446370Sjsing errx(1, "%s: incorrect passphrase", dev); 1002c6446370Sjsing else 1003c6446370Sjsing errx(1, "%s: failed to change passphrase", dev); 1004c6446370Sjsing } 1005c6446370Sjsing } 1006c6446370Sjsing 100703b2dfbfShenning #define BIOCTL_VIS_NBUF 4 100803b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 100903b2dfbfShenning 101003b2dfbfShenning char * 101103b2dfbfShenning bio_vis(char *s) 101203b2dfbfShenning { 101303b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 101403b2dfbfShenning static uint idx = 0; 101503b2dfbfShenning char *buf; 101603b2dfbfShenning 101703b2dfbfShenning buf = rbuf[idx++]; 101803b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 101903b2dfbfShenning idx = 0; 102003b2dfbfShenning 102103b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 102203b2dfbfShenning return (buf); 102303b2dfbfShenning } 102403b2dfbfShenning 102503b2dfbfShenning void 102603b2dfbfShenning bio_diskinq(char *sd_dev) 102703b2dfbfShenning { 102803b2dfbfShenning struct dk_inquiry di; 102903b2dfbfShenning 1030da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 1031da3b0664Shenning err(1, "DIOCINQ"); 103203b2dfbfShenning 103303b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 103403b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 103503b2dfbfShenning } 1036aef7fe28Shshoexer 1037aef7fe28Shshoexer void 10389e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt, 1039c6446370Sjsing size_t saltsz, char *prompt, int verify) 1040aef7fe28Shshoexer { 104186735da2Smarco FILE *f; 104286735da2Smarco size_t pl; 104386735da2Smarco struct stat sb; 10449e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 1045aef7fe28Shshoexer 1046aef7fe28Shshoexer if (!key) 1047aef7fe28Shshoexer errx(1, "Invalid key"); 1048aef7fe28Shshoexer if (!salt) 1049aef7fe28Shshoexer errx(1, "Invalid salt"); 1050aef7fe28Shshoexer if (rounds < 1000) 1051b4604b5cShalex errx(1, "Too few rounds: %d", rounds); 1052aef7fe28Shshoexer 1053aef7fe28Shshoexer /* get passphrase */ 1054ba3d8661Smarco if (password && verify) 1055ba3d8661Smarco errx(1, "can't specify passphrase file during initial " 1056ba3d8661Smarco "creation of crypto volume"); 1057ba3d8661Smarco if (password) { 105886735da2Smarco if ((f = fopen(password, "r")) == NULL) 105986735da2Smarco err(1, "invalid passphrase file"); 106086735da2Smarco 106186735da2Smarco if (fstat(fileno(f), &sb) == -1) 106286735da2Smarco err(1, "can't stat passphrase file"); 106386735da2Smarco if (sb.st_uid != 0) 106486735da2Smarco errx(1, "passphrase file must be owned by root"); 106586735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 106686735da2Smarco errx(1, "passphrase file has the wrong permissions"); 106786735da2Smarco 106886735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 106986735da2Smarco err(1, "can't read passphrase file"); 107086735da2Smarco pl = strlen(passphrase); 107186735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 107286735da2Smarco passphrase[pl - 1] = '\0'; 107386735da2Smarco else 107486735da2Smarco errx(1, "invalid passphrase length"); 107586735da2Smarco 107686735da2Smarco fclose(f); 1077ba3d8661Smarco } else { 1078c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1079b96c6ce2Sckuethe rpp_flag) == NULL) 10809e8c6f5bShshoexer errx(1, "unable to read passphrase"); 1081ba3d8661Smarco } 10829e8c6f5bShshoexer 10839e8c6f5bShshoexer if (verify) { 10849e8c6f5bShshoexer /* request user to re-type it */ 10859e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 1086b96c6ce2Sckuethe sizeof(verifybuf), rpp_flag) == NULL) { 10879e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10889e8c6f5bShshoexer errx(1, "unable to read passphrase"); 10899e8c6f5bShshoexer } 10909e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 10919e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 10929e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10939e8c6f5bShshoexer memset(verifybuf, 0, sizeof(verifybuf)); 10949e8c6f5bShshoexer errx(1, "Passphrases did not match"); 10959e8c6f5bShshoexer } 10969e8c6f5bShshoexer /* forget the re-typed one */ 10979e8c6f5bShshoexer memset(verifybuf, 0, strlen(verifybuf)); 10989e8c6f5bShshoexer } 1099aef7fe28Shshoexer 1100aef7fe28Shshoexer /* derive key from passphrase */ 11015c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 11025c1f8f6bSdjm key, keysz, rounds) != 0) 11035c1f8f6bSdjm errx(1, "pbkdf2 failed"); 1104aef7fe28Shshoexer 1105aef7fe28Shshoexer /* forget passphrase */ 11069e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 1107aef7fe28Shshoexer 1108aef7fe28Shshoexer return; 1109aef7fe28Shshoexer } 1110