1*91f4f7d8Sdlg /* $OpenBSD: bioctl.c,v 1.93 2010/05/18 04:41:14 dlg 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> 31*91f4f7d8Sdlg #include <sys/dkio.h> 32c2126c9aSmarco #include <sys/param.h> 33c2126c9aSmarco #include <sys/queue.h> 3446bc198bSmarco #include <sys/types.h> 3546bc198bSmarco #include <sys/stat.h> 362b69df39Smarco #include <scsi/scsi_all.h> 3713f2281dSnicm #include <scsi/scsi_disk.h> 383af9de98Smarco #include <dev/biovar.h> 39aef7fe28Shshoexer #include <dev/softraidvar.h> 4086735da2Smarco #include <sys/types.h> 4186735da2Smarco #include <sys/stat.h> 423af9de98Smarco 43db2730c1Smarco #include <errno.h> 44db2730c1Smarco #include <err.h> 45db2730c1Smarco #include <fcntl.h> 468ccdd032Sderaadt #include <util.h> 47db2730c1Smarco #include <stdio.h> 48db2730c1Smarco #include <stdlib.h> 49db2730c1Smarco #include <string.h> 50db2730c1Smarco #include <unistd.h> 51e4e14ad7Sderaadt #include <ctype.h> 52db2730c1Smarco #include <util.h> 5303b2dfbfShenning #include <vis.h> 549e8c6f5bShshoexer #include <readpassphrase.h> 55db2730c1Smarco 565c1f8f6bSdjm #include "pbkdf2.h" 57aef7fe28Shshoexer 586de960dcSmarco struct locator { 596de960dcSmarco int channel; 606de960dcSmarco int target; 616de960dcSmarco int lun; 626de960dcSmarco }; 636de960dcSmarco 648ccdd032Sderaadt void usage(void); 6541eccc89Sderaadt const char *str2locator(const char *, struct locator *); 668ccdd032Sderaadt void cleanup(void); 6746bc198bSmarco int bio_parse_devlist(char *, dev_t *); 68aef7fe28Shshoexer void bio_kdf_derive(struct sr_crypto_kdfinfo *, 69c6446370Sjsing struct sr_crypto_kdf_pbkdf2 *, char *, int); 70aef7fe28Shshoexer void bio_kdf_generate(struct sr_crypto_kdfinfo *); 719e8c6f5bShshoexer void derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *, 72c6446370Sjsing size_t, char *, int); 738ccdd032Sderaadt 748ccdd032Sderaadt void bio_inq(char *); 758ccdd032Sderaadt void bio_alarm(char *); 76a15048bbSmarco int bio_getvolbyname(char *); 77a15048bbSmarco void bio_setstate(char *, int, char *); 78a928c459Sderaadt void bio_setblink(char *, char *, int); 79a928c459Sderaadt void bio_blink(char *, int, int); 800054cd36Sjsing void bio_createraid(u_int16_t, char *, char *); 81c7c3e8aaSmarco void bio_deleteraid(char *); 82c6446370Sjsing void bio_changepass(char *); 83e8a57fdeSmarco u_int32_t bio_createflags(char *); 8403b2dfbfShenning char *bio_vis(char *); 8503b2dfbfShenning void bio_diskinq(char *); 863af9de98Smarco 873af9de98Smarco int devh = -1; 88abe9d68eSderaadt int human; 89abe9d68eSderaadt int verbose; 90e8a57fdeSmarco u_int32_t cflags = 0; 91aedd4f07Sdjm int rflag = 8192; 9286735da2Smarco char *password; 933af9de98Smarco 943af9de98Smarco struct bio_locate bl; 953af9de98Smarco 963af9de98Smarco int 973af9de98Smarco main(int argc, char *argv[]) 983af9de98Smarco { 993af9de98Smarco extern char *optarg; 100db2730c1Smarco u_int64_t func = 0; 101db2730c1Smarco /* u_int64_t subfunc = 0; */ 102cf6503d7Sderaadt char *bioc_dev = NULL, *sd_dev = NULL; 103cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 1047195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 1050054cd36Sjsing char *key_disk = NULL; 106aedd4f07Sdjm const char *errstr; 107c6446370Sjsing int ch, rv, blink = 0, changepass = 0, diskinq = 0; 108c6446370Sjsing int ss_func = 0; 1099ecba717Sderaadt u_int16_t cr_level = 0; 1103af9de98Smarco 1113af9de98Smarco if (argc < 2) 1123af9de98Smarco usage(); 1133af9de98Smarco 1140054cd36Sjsing while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:Pp:qr:R:vu:")) != 115c6446370Sjsing -1) { 1163af9de98Smarco switch (ch) { 117edfd9792Smarco case 'a': /* alarm */ 118edfd9792Smarco func |= BIOC_ALARM; 119edfd9792Smarco al_arg = optarg; 120edfd9792Smarco break; 121c55617f1Sdlg case 'b': /* blink */ 122c55617f1Sdlg func |= BIOC_BLINK; 123a928c459Sderaadt blink = BIOC_SBBLINK; 124a928c459Sderaadt bl_arg = optarg; 125a928c459Sderaadt break; 126e8a57fdeSmarco case 'C': /* creation flags */ 127e8a57fdeSmarco cflags = bio_createflags(optarg); 128e8a57fdeSmarco break; 1297195049bSmarco case 'c': /* create */ 1307195049bSmarco func |= BIOC_CREATERAID; 13198b750e4Stedu if (isdigit(*optarg)) 1327195049bSmarco cr_level = atoi(optarg); 13398b750e4Stedu else 13498b750e4Stedu cr_level = *optarg; 1357195049bSmarco break; 136c7c3e8aaSmarco case 'd': 137c7c3e8aaSmarco /* delete volume */ 138c7c3e8aaSmarco func |= BIOC_DELETERAID; 139c7c3e8aaSmarco break; 140a928c459Sderaadt case 'u': /* unblink */ 141a928c459Sderaadt func |= BIOC_BLINK; 142a928c459Sderaadt blink = BIOC_SBUNBLINK; 143c55617f1Sdlg bl_arg = optarg; 144c55617f1Sdlg break; 1456de960dcSmarco case 'H': /* set hotspare */ 1466de960dcSmarco func |= BIOC_SETSTATE; 147a15048bbSmarco ss_func = BIOC_SSHOTSPARE; 1486de960dcSmarco al_arg = optarg; 1496de960dcSmarco break; 1508ccdd032Sderaadt case 'h': 1518ccdd032Sderaadt human = 1; 1528ccdd032Sderaadt break; 153db2730c1Smarco case 'i': /* inquiry */ 154db2730c1Smarco func |= BIOC_INQ; 1553af9de98Smarco break; 1560054cd36Sjsing case 'k': /* Key disk. */ 1570054cd36Sjsing key_disk = optarg; 1580054cd36Sjsing break; 1597195049bSmarco case 'l': /* device list */ 1607195049bSmarco func |= BIOC_DEVLIST; 1617195049bSmarco dev_list = optarg; 1627195049bSmarco break; 163c6446370Sjsing case 'P': 164c6446370Sjsing /* Change passphrase. */ 165c6446370Sjsing changepass = 1; 166c6446370Sjsing break; 16786735da2Smarco case 'p': 16886735da2Smarco password = optarg; 16986735da2Smarco break; 170aedd4f07Sdjm case 'r': 171aedd4f07Sdjm rflag = strtonum(optarg, 1000, 1<<30, &errstr); 172aedd4f07Sdjm if (errstr != NULL) 173aedd4f07Sdjm errx(1, "Number of rounds is %s: %s", 174aedd4f07Sdjm errstr, optarg); 175aedd4f07Sdjm break; 176a15048bbSmarco case 'R': 177a15048bbSmarco /* rebuild to provided chunk/CTL */ 178a15048bbSmarco func |= BIOC_SETSTATE; 179a15048bbSmarco ss_func = BIOC_SSREBUILD; 180a15048bbSmarco al_arg = optarg; 181a15048bbSmarco break; 182abe9d68eSderaadt case 'v': 183abe9d68eSderaadt verbose = 1; 184abe9d68eSderaadt break; 18503b2dfbfShenning case 'q': 18603b2dfbfShenning diskinq = 1; 18703b2dfbfShenning break; 1883af9de98Smarco default: 1893af9de98Smarco usage(); 1903af9de98Smarco /* NOTREACHED */ 1913af9de98Smarco } 1923af9de98Smarco } 193cf6503d7Sderaadt argc -= optind; 194cf6503d7Sderaadt argv += optind; 1953af9de98Smarco 196c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 197cf6503d7Sderaadt usage(); 198cf6503d7Sderaadt 199dcbaf4c8Sderaadt if (func == 0) 200dcbaf4c8Sderaadt func |= BIOC_INQ; 201dcbaf4c8Sderaadt 202e4e14ad7Sderaadt /* if at least glob sd[0-9]*, it is a drive identifier */ 203e4e14ad7Sderaadt if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 && 204e4e14ad7Sderaadt isdigit(argv[0][2])) 205cf6503d7Sderaadt sd_dev = argv[0]; 206cf6503d7Sderaadt else 207cf6503d7Sderaadt bioc_dev = argv[0]; 20810b411a7Smarco 20910b411a7Smarco if (bioc_dev) { 21041eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2113af9de98Smarco if (devh == -1) 21241eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2133af9de98Smarco 2148ccdd032Sderaadt bl.bl_name = bioc_dev; 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"); 219db2730c1Smarco } else if (sd_dev) { 22010b411a7Smarco devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname); 22110b411a7Smarco if (devh == -1) 22210b411a7Smarco err(1, "Can't open %s", sd_dev); 223db2730c1Smarco } else 22486735da2Smarco errx(1, "need device"); 2253af9de98Smarco 22603b2dfbfShenning if (diskinq) { 22703b2dfbfShenning bio_diskinq(sd_dev); 228c6446370Sjsing } else if (changepass && sd_dev != NULL) { 229c6446370Sjsing bio_changepass(sd_dev); 23003b2dfbfShenning } else if (func & BIOC_INQ) { 2318ccdd032Sderaadt bio_inq(sd_dev); 232edfd9792Smarco } else if (func == BIOC_ALARM) { 233edfd9792Smarco bio_alarm(al_arg); 234c55617f1Sdlg } else if (func == BIOC_BLINK) { 235a928c459Sderaadt bio_setblink(sd_dev, bl_arg, blink); 2366de960dcSmarco } else if (func == BIOC_SETSTATE) { 237a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 238c7c3e8aaSmarco } else if (func == BIOC_DELETERAID && sd_dev != NULL) { 239c7c3e8aaSmarco bio_deleteraid(sd_dev); 2407195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2417195049bSmarco if (!(func & BIOC_CREATERAID)) 2427195049bSmarco errx(1, "need -c parameter"); 2437195049bSmarco if (!(func & BIOC_DEVLIST)) 2447195049bSmarco errx(1, "need -l parameter"); 2457195049bSmarco if (sd_dev) 2467195049bSmarco errx(1, "can't use sd device"); 2470054cd36Sjsing bio_createraid(cr_level, dev_list, key_disk); 2483af9de98Smarco } 2493af9de98Smarco 2503af9de98Smarco return (0); 2513af9de98Smarco } 2523af9de98Smarco 2533af9de98Smarco void 2543af9de98Smarco usage(void) 2553af9de98Smarco { 2563af9de98Smarco extern char *__progname; 2573af9de98Smarco 258d90b5d8bSjmc fprintf(stderr, 259d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 260d90b5d8bSjmc "[-b channel:target[.lun]]\n" 261d0b772c8Sjmc "\t[-H channel:target[.lun]] " 262d0b772c8Sjmc "[-R device | channel:target[.lun]\n" 263d0b772c8Sjmc "\t[-u channel:target[.lun]] " 264d0b772c8Sjmc "device\n" 265af84dad0Sjmc " %s [-dhiPqv] " 266b90fdff5Sjmc "[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n" 26778702060Sjmc "\t[-l special[,special,...]] [-p passfile]\n" 26878702060Sjmc "\t[-R device | channel:target[.lun] [-r rounds] " 269d0b772c8Sjmc "device\n", __progname, __progname); 270d90b5d8bSjmc 2713af9de98Smarco exit(1); 2723af9de98Smarco } 2733af9de98Smarco 27441eccc89Sderaadt const char * 2756de960dcSmarco str2locator(const char *string, struct locator *location) 2766de960dcSmarco { 27750d3c4dcSdlg const char *errstr; 27841eccc89Sderaadt char parse[80], *targ, *lun; 2796de960dcSmarco 28041eccc89Sderaadt strlcpy(parse, string, sizeof parse); 28141eccc89Sderaadt targ = strchr(parse, ':'); 2826de960dcSmarco if (targ == NULL) 28341eccc89Sderaadt return ("target not specified"); 2846de960dcSmarco *targ++ = '\0'; 2856de960dcSmarco 28650d3c4dcSdlg lun = strchr(targ, '.'); 2876de960dcSmarco if (lun != NULL) { 2886de960dcSmarco *lun++ = '\0'; 28950d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 29050d3c4dcSdlg if (errstr) 29141eccc89Sderaadt return (errstr); 2926de960dcSmarco } else 2936de960dcSmarco location->lun = 0; 2946de960dcSmarco 29550d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 29650d3c4dcSdlg if (errstr) 29741eccc89Sderaadt return (errstr); 29841eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 29950d3c4dcSdlg if (errstr) 30041eccc89Sderaadt return (errstr); 30141eccc89Sderaadt return (NULL); 3026de960dcSmarco } 3036de960dcSmarco 3043af9de98Smarco void 3058ccdd032Sderaadt bio_inq(char *name) 306d4546a56Sdlg { 3079017fb97Sderaadt char *status, size[64], scsiname[16], volname[32]; 308a4d3c4a2Sderaadt char percent[10], seconds[20]; 309b9950701Smarco int rv, i, d, volheader, hotspare, unused; 310aa65acf1Sderaadt char encname[16], serial[32]; 3118ccdd032Sderaadt struct bioc_disk bd; 3128ccdd032Sderaadt struct bioc_inq bi; 3138ccdd032Sderaadt struct bioc_vol bv; 314db2730c1Smarco 315db2730c1Smarco memset(&bi, 0, sizeof(bi)); 3163af9de98Smarco 3178ccdd032Sderaadt bi.bi_cookie = bl.bl_cookie; 3183af9de98Smarco 319db2730c1Smarco rv = ioctl(devh, BIOCINQ, &bi); 3203af9de98Smarco if (rv == -1) { 32103b2dfbfShenning if (errno == ENOTTY) 32203b2dfbfShenning bio_diskinq(name); 32303b2dfbfShenning else 324da3b0664Shenning err(1, "BIOCINQ"); 3253af9de98Smarco return; 3263af9de98Smarco } 3273af9de98Smarco 3288ccdd032Sderaadt volheader = 0; 3298ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 330db2730c1Smarco memset(&bv, 0, sizeof(bv)); 3318ccdd032Sderaadt bv.bv_cookie = bl.bl_cookie; 3328ccdd032Sderaadt bv.bv_volid = i; 3330a92ff65Sderaadt bv.bv_percent = -1; 3349017fb97Sderaadt bv.bv_seconds = 0; 33570a2ae7bSmarco 336db2730c1Smarco rv = ioctl(devh, BIOCVOL, &bv); 337da3b0664Shenning if (rv == -1) 338da3b0664Shenning err(1, "BIOCVOL"); 3393af9de98Smarco 3408ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 3418ccdd032Sderaadt continue; 3428ccdd032Sderaadt 3438ccdd032Sderaadt if (!volheader) { 3448ccdd032Sderaadt volheader = 1; 345c9377e3bSmickey printf("%-7s %-10s %14s %-8s\n", 3468ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 3478ccdd032Sderaadt } 3488ccdd032Sderaadt 3490a92ff65Sderaadt percent[0] = '\0'; 3509017fb97Sderaadt seconds[0] = '\0'; 3510a92ff65Sderaadt if (bv.bv_percent != -1) 3520a92ff65Sderaadt snprintf(percent, sizeof percent, 3530a92ff65Sderaadt " %d%% done", bv.bv_percent); 3549017fb97Sderaadt if (bv.bv_seconds) 3559017fb97Sderaadt snprintf(seconds, sizeof seconds, 3569017fb97Sderaadt " %u seconds", bv.bv_seconds); 3578ccdd032Sderaadt switch (bv.bv_status) { 358db2730c1Smarco case BIOC_SVONLINE: 3598ccdd032Sderaadt status = BIOC_SVONLINE_S; 360db2730c1Smarco break; 361db2730c1Smarco case BIOC_SVOFFLINE: 3628ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 363db2730c1Smarco break; 364db2730c1Smarco case BIOC_SVDEGRADED: 3658ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 366db2730c1Smarco break; 3670a92ff65Sderaadt case BIOC_SVBUILDING: 3680a92ff65Sderaadt status = BIOC_SVBUILDING_S; 3690a92ff65Sderaadt break; 3700a92ff65Sderaadt case BIOC_SVREBUILD: 3710a92ff65Sderaadt status = BIOC_SVREBUILD_S; 3720a92ff65Sderaadt break; 3730a92ff65Sderaadt case BIOC_SVSCRUB: 3740a92ff65Sderaadt status = BIOC_SVSCRUB_S; 3750a92ff65Sderaadt break; 376db2730c1Smarco case BIOC_SVINVALID: 377db2730c1Smarco default: 3788ccdd032Sderaadt status = BIOC_SVINVALID_S; 379d4546a56Sdlg } 3803af9de98Smarco 381aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 3828ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 383b9950701Smarco 3849ecba717Sderaadt unused = 0; 3859ecba717Sderaadt hotspare = 0; 386aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 387aa65acf1Sderaadt hotspare = 1; 388b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 389b9950701Smarco unused = 1; 390aa65acf1Sderaadt else { 3918ccdd032Sderaadt if (human) 3928ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 3938ccdd032Sderaadt else 3948ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 3958ccdd032Sderaadt bv.bv_size); 396da935596Stodd switch (bv.bv_level) { 397da935596Stodd case 'C': 398da935596Stodd printf("%7s %-10s %14s %-7s CRYPTO%s%s\n", 399da935596Stodd volname, status, size, bv.bv_dev, 400da935596Stodd percent, seconds); 401da935596Stodd break; 402da935596Stodd default: 4039017fb97Sderaadt printf("%7s %-10s %14s %-7s RAID%u%s%s\n", 4040a92ff65Sderaadt volname, status, size, bv.bv_dev, 4059017fb97Sderaadt bv.bv_level, percent, seconds); 406da935596Stodd break; 407da935596Stodd } 408da935596Stodd 409aa65acf1Sderaadt } 4108ccdd032Sderaadt 4118ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 412db2730c1Smarco memset(&bd, 0, sizeof(bd)); 4138ccdd032Sderaadt bd.bd_cookie = bl.bl_cookie; 4148ccdd032Sderaadt bd.bd_diskid = d; 4158ccdd032Sderaadt bd.bd_volid = i; 4163af9de98Smarco 417db2730c1Smarco rv = ioctl(devh, BIOCDISK, &bd); 418da3b0664Shenning if (rv == -1) 419da3b0664Shenning err(1, "BIOCDISK"); 4203af9de98Smarco 4218ccdd032Sderaadt switch (bd.bd_status) { 422db2730c1Smarco case BIOC_SDONLINE: 4238ccdd032Sderaadt status = BIOC_SDONLINE_S; 424d4546a56Sdlg break; 425db2730c1Smarco case BIOC_SDOFFLINE: 4268ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 427d4546a56Sdlg break; 428db2730c1Smarco case BIOC_SDFAILED: 4298ccdd032Sderaadt status = BIOC_SDFAILED_S; 430db2730c1Smarco break; 431db2730c1Smarco case BIOC_SDREBUILD: 4328ccdd032Sderaadt status = BIOC_SDREBUILD_S; 433db2730c1Smarco break; 434db2730c1Smarco case BIOC_SDHOTSPARE: 4358ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 436db2730c1Smarco break; 437db2730c1Smarco case BIOC_SDUNUSED: 4388ccdd032Sderaadt status = BIOC_SDUNUSED_S; 439db2730c1Smarco break; 440e1dfb373Sderaadt case BIOC_SDSCRUB: 441e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 442e1dfb373Sderaadt break; 443db2730c1Smarco case BIOC_SDINVALID: 444d4546a56Sdlg default: 4458ccdd032Sderaadt status = BIOC_SDINVALID_S; 446d4546a56Sdlg } 447aa65acf1Sderaadt 448b9950701Smarco if (hotspare || unused) 449aa65acf1Sderaadt ; /* use volname from parent volume */ 450aa65acf1Sderaadt else 451aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 452aa65acf1Sderaadt bd.bd_diskid); 453aa65acf1Sderaadt 4540054cd36Sjsing if (bv.bv_level == 'C' && bd.bd_size == 0) 4550054cd36Sjsing snprintf(size, sizeof size, "%14s", "key disk"); 4560054cd36Sjsing else if (human) 4578ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 4588ccdd032Sderaadt else 4598ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4608ccdd032Sderaadt bd.bd_size); 4618ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 46243d61178Sderaadt "%u:%u.%u", 46343d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 4645978b28dSderaadt if (bd.bd_procdev[0]) 465abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 4665978b28dSderaadt else 467abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 468abe9d68eSderaadt if (bd.bd_serial[0]) 469abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 470abe9d68eSderaadt else 471abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 4728ccdd032Sderaadt 473aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s <%s>\n", 474aa65acf1Sderaadt volname, status, size, scsiname, encname, 4758ccdd032Sderaadt bd.bd_vendor); 476abe9d68eSderaadt if (verbose) 477aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s '%s'\n", 478abe9d68eSderaadt "", "", "", "", "", serial); 479d4546a56Sdlg } 480d4546a56Sdlg } 481d4546a56Sdlg } 482edfd9792Smarco 483edfd9792Smarco void 484edfd9792Smarco bio_alarm(char *arg) 485edfd9792Smarco { 486edfd9792Smarco int rv; 4878ccdd032Sderaadt struct bioc_alarm ba; 488edfd9792Smarco 4898ccdd032Sderaadt ba.ba_cookie = bl.bl_cookie; 490edfd9792Smarco 491edfd9792Smarco switch (arg[0]) { 492edfd9792Smarco case 'q': /* silence alarm */ 493edfd9792Smarco /* FALLTHROUGH */ 494edfd9792Smarco case 's': 4958ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 496edfd9792Smarco break; 497edfd9792Smarco 498edfd9792Smarco case 'e': /* enable alarm */ 4998ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 500edfd9792Smarco break; 501edfd9792Smarco 502edfd9792Smarco case 'd': /* disable alarm */ 5038ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 504edfd9792Smarco break; 505edfd9792Smarco 506edfd9792Smarco case 't': /* test alarm */ 5078ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 508edfd9792Smarco break; 509edfd9792Smarco 510edfd9792Smarco case 'g': /* get alarm state */ 5118ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 512edfd9792Smarco break; 513edfd9792Smarco 514edfd9792Smarco default: 515da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 516edfd9792Smarco } 517edfd9792Smarco 518edfd9792Smarco rv = ioctl(devh, BIOCALARM, &ba); 519da3b0664Shenning if (rv == -1) 520da3b0664Shenning err(1, "BIOCALARM"); 521edfd9792Smarco 522edfd9792Smarco if (arg[0] == 'g') { 523edfd9792Smarco printf("alarm is currently %s\n", 5248ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 5258ccdd032Sderaadt 526edfd9792Smarco } 527edfd9792Smarco } 5286de960dcSmarco 529a15048bbSmarco int 530a15048bbSmarco bio_getvolbyname(char *name) 531a15048bbSmarco { 532a15048bbSmarco int id = -1, i, rv; 533a15048bbSmarco struct bioc_inq bi; 534a15048bbSmarco struct bioc_vol bv; 535a15048bbSmarco 536a15048bbSmarco memset(&bi, 0, sizeof(bi)); 537a15048bbSmarco bi.bi_cookie = bl.bl_cookie; 538a15048bbSmarco rv = ioctl(devh, BIOCINQ, &bi); 539a15048bbSmarco if (rv == -1) 540a15048bbSmarco err(1, "BIOCINQ"); 541a15048bbSmarco 542a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 543a15048bbSmarco memset(&bv, 0, sizeof(bv)); 544a15048bbSmarco bv.bv_cookie = bl.bl_cookie; 545a15048bbSmarco bv.bv_volid = i; 546a15048bbSmarco rv = ioctl(devh, BIOCVOL, &bv); 547a15048bbSmarco if (rv == -1) 548a15048bbSmarco err(1, "BIOCVOL"); 549a15048bbSmarco 550a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 551a15048bbSmarco continue; 552a15048bbSmarco id = i; 553a15048bbSmarco break; 554a15048bbSmarco } 555a15048bbSmarco 556a15048bbSmarco return (id); 557a15048bbSmarco } 558a15048bbSmarco 559ebaf584eSderaadt void 5608d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 5616de960dcSmarco { 5626de960dcSmarco struct bioc_setstate bs; 5636de960dcSmarco struct locator location; 564a15048bbSmarco struct stat sb; 56541eccc89Sderaadt const char *errstr; 566ebaf584eSderaadt int rv; 5676de960dcSmarco 568a15048bbSmarco memset(&bs, 0, sizeof(bs)); 569a15048bbSmarco if (stat(arg, &sb) == -1) { 570a15048bbSmarco /* use CTL */ 57141eccc89Sderaadt errstr = str2locator(arg, &location); 57241eccc89Sderaadt if (errstr) 57341eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 5746de960dcSmarco bs.bs_channel = location.channel; 5756de960dcSmarco bs.bs_target = location.target; 5766de960dcSmarco bs.bs_lun = location.lun; 577a15048bbSmarco } else { 578a15048bbSmarco /* use other id */ 579a15048bbSmarco bs.bs_other_id = sb.st_rdev; 580a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 581a15048bbSmarco } 582a15048bbSmarco 583a15048bbSmarco bs.bs_cookie = bl.bl_cookie; 584a15048bbSmarco bs.bs_status = status; 585a15048bbSmarco 586d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 587a15048bbSmarco /* make sure user supplied a sd device */ 5888d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 589a15048bbSmarco if (bs.bs_volid == -1) 5908d8693a2Sdtucker errx(1, "invalid device %s", devicename); 591d2647ac1Sjsing } 5926de960dcSmarco 5936de960dcSmarco rv = ioctl(devh, BIOCSETSTATE, &bs); 594da3b0664Shenning if (rv == -1) 595da3b0664Shenning err(1, "BIOCSETSTATE"); 5966de960dcSmarco } 597c55617f1Sdlg 598c55617f1Sdlg void 599a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 600c55617f1Sdlg { 60150d3c4dcSdlg struct locator location; 60250d3c4dcSdlg struct bioc_inq bi; 60350d3c4dcSdlg struct bioc_vol bv; 60450d3c4dcSdlg struct bioc_disk bd; 6050505205bSdlg struct bioc_blink bb; 60641eccc89Sderaadt const char *errstr; 60750d3c4dcSdlg int v, d, rv; 608c55617f1Sdlg 60941eccc89Sderaadt errstr = str2locator(arg, &location); 61041eccc89Sderaadt if (errstr) 61141eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 61250d3c4dcSdlg 6130505205bSdlg /* try setting blink on the device directly */ 6140505205bSdlg memset(&bb, 0, sizeof(bb)); 6150505205bSdlg bb.bb_cookie = bl.bl_cookie; 6160505205bSdlg bb.bb_status = blink; 6170505205bSdlg bb.bb_target = location.target; 618649724a4Smarco bb.bb_channel = location.channel; 6190505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 6200505205bSdlg if (rv == 0) 6210505205bSdlg return; 6220505205bSdlg 623855d4e83Ssobrado /* if the blink didn't work, try to find something that will */ 6240505205bSdlg 62550d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 62650d3c4dcSdlg bi.bi_cookie = bl.bl_cookie; 62750d3c4dcSdlg rv = ioctl(devh, BIOCINQ, &bi); 628da3b0664Shenning if (rv == -1) 629da3b0664Shenning err(1, "BIOCINQ"); 63050d3c4dcSdlg 63150d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 63250d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 63350d3c4dcSdlg bv.bv_cookie = bl.bl_cookie; 63450d3c4dcSdlg bv.bv_volid = v; 63550d3c4dcSdlg rv = ioctl(devh, BIOCVOL, &bv); 636da3b0664Shenning if (rv == -1) 637da3b0664Shenning err(1, "BIOCVOL"); 63850d3c4dcSdlg 63950d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 64050d3c4dcSdlg continue; 64150d3c4dcSdlg 64250d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 64350d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 64450d3c4dcSdlg bd.bd_cookie = bl.bl_cookie; 64550d3c4dcSdlg bd.bd_volid = v; 64650d3c4dcSdlg bd.bd_diskid = d; 64750d3c4dcSdlg 64850d3c4dcSdlg rv = ioctl(devh, BIOCDISK, &bd); 649da3b0664Shenning if (rv == -1) 650da3b0664Shenning err(1, "BIOCDISK"); 65150d3c4dcSdlg 65250d3c4dcSdlg if (bd.bd_channel == location.channel && 65350d3c4dcSdlg bd.bd_target == location.target && 65450d3c4dcSdlg bd.bd_lun == location.lun) { 65550d3c4dcSdlg if (bd.bd_procdev[0] != '\0') { 65650d3c4dcSdlg bio_blink(bd.bd_procdev, 657a928c459Sderaadt location.target, blink); 65850d3c4dcSdlg } else 65941eccc89Sderaadt warnx("Disk %s is not in an enclosure", arg); 66050d3c4dcSdlg return; 66150d3c4dcSdlg } 66250d3c4dcSdlg } 66350d3c4dcSdlg } 66450d3c4dcSdlg 66541eccc89Sderaadt warnx("Disk %s does not exist", arg); 66650d3c4dcSdlg return; 66750d3c4dcSdlg } 66850d3c4dcSdlg 66950d3c4dcSdlg void 670a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 67150d3c4dcSdlg { 67250d3c4dcSdlg int bioh; 67350d3c4dcSdlg struct bio_locate bio; 67450d3c4dcSdlg struct bioc_blink blink; 67550d3c4dcSdlg int rv; 67650d3c4dcSdlg 67741eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 67850d3c4dcSdlg if (bioh == -1) 67941eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 68050d3c4dcSdlg 68150d3c4dcSdlg bio.bl_name = enclosure; 68250d3c4dcSdlg rv = ioctl(bioh, BIOCLOCATE, &bio); 68350d3c4dcSdlg if (rv == -1) 68441eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 685c55617f1Sdlg 686c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 68750d3c4dcSdlg blink.bb_cookie = bio.bl_cookie; 688a928c459Sderaadt blink.bb_status = blinktype; 689c55617f1Sdlg blink.bb_target = target; 690c55617f1Sdlg 69150d3c4dcSdlg rv = ioctl(bioh, BIOCBLINK, &blink); 692c55617f1Sdlg if (rv == -1) 693da3b0664Shenning err(1, "BIOCBLINK"); 69450d3c4dcSdlg 69550d3c4dcSdlg close(bioh); 696c55617f1Sdlg } 6977195049bSmarco 6987195049bSmarco void 6990054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk) 7007195049bSmarco { 7017195049bSmarco struct bioc_createraid create; 702aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 703aef7fe28Shshoexer struct sr_crypto_kdf_pbkdf2 kdfhint; 7040054cd36Sjsing struct stat sb; 7057f8eae2bSnicm int rv, no_dev; 7067f8eae2bSnicm dev_t *dt; 7077195049bSmarco u_int16_t min_disks = 0; 7087195049bSmarco 7097195049bSmarco if (!dev_list) 7107195049bSmarco errx(1, "no devices specified"); 7117195049bSmarco 71246bc198bSmarco dt = (dev_t *)malloc(BIOC_CRMAXLEN); 71346bc198bSmarco if (!dt) 71446bc198bSmarco err(1, "not enough memory for dev_t list"); 71546bc198bSmarco memset(dt, 0, BIOC_CRMAXLEN); 71646bc198bSmarco 71746bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 71846bc198bSmarco 7197195049bSmarco switch (level) { 7207195049bSmarco case 0: 72184e48fabSmarco min_disks = 2; 7227195049bSmarco break; 7237195049bSmarco case 1: 7247195049bSmarco min_disks = 2; 7257195049bSmarco break; 726e717853eSmarco case 4: 727e717853eSmarco case 5: 728e717853eSmarco min_disks = 3; 729e717853eSmarco break; 73084e48fabSmarco case 'C': 731aef7fe28Shshoexer min_disks = 1; 73284e48fabSmarco break; 73398b750e4Stedu case 'c': 73498b750e4Stedu min_disks = 1; 73598b750e4Stedu break; 7367195049bSmarco default: 73723afedbfSgrunk errx(1, "unsupported raid level"); 7387195049bSmarco } 7397195049bSmarco 74084e48fabSmarco if (no_dev < min_disks) 74184e48fabSmarco errx(1, "not enough disks"); 74284e48fabSmarco 743aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 744aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 745818b0595Shalex errx(1, "not exactly one partition"); 746aef7fe28Shshoexer 7477195049bSmarco memset(&create, 0, sizeof(create)); 7487195049bSmarco create.bc_cookie = bl.bl_cookie; 7497195049bSmarco create.bc_level = level; 75046bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 75146bc198bSmarco create.bc_dev_list = dt; 752e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 7530054cd36Sjsing create.bc_key_disk = NODEV; 7547195049bSmarco 7550054cd36Sjsing if (level == 'C' && key_disk == NULL) { 7560054cd36Sjsing 757aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 758aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 759aef7fe28Shshoexer 7600054cd36Sjsing create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 7610054cd36Sjsing 762aef7fe28Shshoexer create.bc_opaque = &kdfhint; 763aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 764aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 765aef7fe28Shshoexer 766aef7fe28Shshoexer /* try to get KDF hint */ 76783e979edShshoexer if (ioctl(devh, BIOCCREATERAID, &create) == -1) 76883e979edShshoexer err(1, "ioctl"); 76983e979edShshoexer 77083e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 771c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 772aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 773aef7fe28Shshoexer } else { 774aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 775aef7fe28Shshoexer } 776aef7fe28Shshoexer 777aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 778aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 779aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 7800054cd36Sjsing 7810054cd36Sjsing } else if (level == 'C' && key_disk != NULL) { 7820054cd36Sjsing 7830054cd36Sjsing if (stat(key_disk, &sb) == -1) 7840054cd36Sjsing err(1, "could not stat %s", key_disk); 7850054cd36Sjsing create.bc_key_disk = sb.st_rdev; 7860054cd36Sjsing 7870054cd36Sjsing memset(&kdfinfo, 0, sizeof(kdfinfo)); 7880054cd36Sjsing 7890054cd36Sjsing kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf); 7900054cd36Sjsing kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK; 7910054cd36Sjsing kdfinfo.len = sizeof(kdfinfo); 7920054cd36Sjsing kdfinfo.flags = SR_CRYPTOKDF_HINT; 7930054cd36Sjsing 7940054cd36Sjsing create.bc_opaque = &kdfinfo; 7950054cd36Sjsing create.bc_opaque_size = sizeof(kdfinfo); 7960054cd36Sjsing create.bc_opaque_flags = BIOC_SOIN; 7970054cd36Sjsing 798aef7fe28Shshoexer } 799aef7fe28Shshoexer 8007195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 801aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 80283e979edShshoexer memset(&create, 0, sizeof(create)); 803a83e4577Sdjm if (rv == -1) { 804a83e4577Sdjm if (errno == EPERM) 805a83e4577Sdjm errx(1, "Incorrect passphrase"); 806da3b0664Shenning err(1, "BIOCCREATERAID"); 807a83e4577Sdjm } 80846bc198bSmarco 80946bc198bSmarco free(dt); 81046bc198bSmarco } 81146bc198bSmarco 812aef7fe28Shshoexer void 813aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 814c6446370Sjsing *kdfhint, char* prompt, int verify) 815aef7fe28Shshoexer { 816aef7fe28Shshoexer if (!kdfinfo) 817aef7fe28Shshoexer errx(1, "invalid KDF info"); 818aef7fe28Shshoexer if (!kdfhint) 819aef7fe28Shshoexer errx(1, "invalid KDF hint"); 820aef7fe28Shshoexer 821aef7fe28Shshoexer if (kdfhint->len != sizeof(*kdfhint)) 822aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 823aef7fe28Shshoexer if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2) 824aef7fe28Shshoexer errx(1, "unknown KDF type %d", kdfhint->type); 825aef7fe28Shshoexer if (kdfhint->rounds < 1000) 826aef7fe28Shshoexer errx(1, "number of KDF rounds too low: %d", kdfhint->rounds); 827aef7fe28Shshoexer 828aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 829aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 830aef7fe28Shshoexer 8319e8c6f5bShshoexer derive_key_pkcs(kdfhint->rounds, 832aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 833c6446370Sjsing kdfhint->salt, sizeof(kdfhint->salt), prompt, verify); 834aef7fe28Shshoexer } 835aef7fe28Shshoexer 836aef7fe28Shshoexer void 837aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 838aef7fe28Shshoexer { 839aef7fe28Shshoexer if (!kdfinfo) 840aef7fe28Shshoexer errx(1, "invalid KDF info"); 841aef7fe28Shshoexer 842aef7fe28Shshoexer kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 843aef7fe28Shshoexer kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 844aedd4f07Sdjm kdfinfo->pbkdf2.rounds = rflag; 845aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 8460054cd36Sjsing kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT; 847aef7fe28Shshoexer 848aef7fe28Shshoexer /* generate salt */ 849aef7fe28Shshoexer arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 850aef7fe28Shshoexer 8519e8c6f5bShshoexer derive_key_pkcs(kdfinfo->pbkdf2.rounds, 852aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 853c6446370Sjsing kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 854c6446370Sjsing "New passphrase: ", 1); 855aef7fe28Shshoexer } 856aef7fe28Shshoexer 85746bc198bSmarco int 85846bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 85946bc198bSmarco { 86046bc198bSmarco char *s, *e; 86146bc198bSmarco u_int32_t sz = 0; 86246bc198bSmarco int no_dev = 0, i, x; 86346bc198bSmarco struct stat sb; 8645c1f8f6bSdjm char dev[MAXPATHLEN]; 86546bc198bSmarco 86646bc198bSmarco if (!lst) 86746bc198bSmarco errx(1, "invalid device list"); 86846bc198bSmarco 86946bc198bSmarco s = e = lst; 87046bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 87146bc198bSmarco while (*e != '\0') { 87246bc198bSmarco if (*e == ',') 87346bc198bSmarco s = e + 1; 87446bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 87546bc198bSmarco /* got one */ 87646bc198bSmarco sz = e - s + 1; 8775c1f8f6bSdjm strlcpy(dev, s, sz + 1); 8785c1f8f6bSdjm if (stat(dev, &sb) == -1) 8795c1f8f6bSdjm err(1, "could not stat %s", dev); 88046bc198bSmarco dt[no_dev] = sb.st_rdev; 88146bc198bSmarco no_dev++; 8825c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 88346bc198bSmarco errx(1, "too many devices on device list"); 88446bc198bSmarco } 88546bc198bSmarco e++; 88646bc198bSmarco } 88746bc198bSmarco 88846bc198bSmarco for (i = 0; i < no_dev; i++) 88946bc198bSmarco for (x = 0; x < no_dev; x++) 89046bc198bSmarco if (dt[i] == dt[x] && x != i) 89146bc198bSmarco errx(1, "duplicate device in list"); 89246bc198bSmarco 89346bc198bSmarco return (no_dev); 8947195049bSmarco } 895e8a57fdeSmarco 896e8a57fdeSmarco u_int32_t 897e8a57fdeSmarco bio_createflags(char *lst) 898e8a57fdeSmarco { 899e8a57fdeSmarco char *s, *e, fs[32]; 900e8a57fdeSmarco u_int32_t sz = 0; 901e8a57fdeSmarco u_int32_t flags = 0; 902e8a57fdeSmarco 903e8a57fdeSmarco if (!lst) 904e8a57fdeSmarco errx(1, "invalid flags list"); 905e8a57fdeSmarco 906e8a57fdeSmarco s = e = lst; 907e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 908e8a57fdeSmarco while (*e != '\0') { 909e8a57fdeSmarco if (*e == ',') 910e8a57fdeSmarco s = e + 1; 911e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 912e8a57fdeSmarco /* got one */ 913e8a57fdeSmarco sz = e - s + 1; 914e8a57fdeSmarco switch (s[0]) { 915e8a57fdeSmarco case 'f': 916e8a57fdeSmarco flags |= BIOC_SCFORCE; 917e8a57fdeSmarco break; 918e8a57fdeSmarco case 'n': 919e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 920e8a57fdeSmarco break; 921e8a57fdeSmarco default: 922e8a57fdeSmarco strlcpy(fs, s, sz + 1); 923e8a57fdeSmarco errx(1, "invalid flag %s", fs); 924e8a57fdeSmarco } 925e8a57fdeSmarco } 926e8a57fdeSmarco e++; 927e8a57fdeSmarco } 928e8a57fdeSmarco 929e8a57fdeSmarco return (flags); 930e8a57fdeSmarco } 93103b2dfbfShenning 932c7c3e8aaSmarco void 933c7c3e8aaSmarco bio_deleteraid(char *dev) 934c7c3e8aaSmarco { 935c7c3e8aaSmarco struct bioc_deleteraid bd; 936c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 937c7c3e8aaSmarco 938c7c3e8aaSmarco bd.bd_cookie = bd.bd_cookie; 939a15048bbSmarco /* XXX make this a dev_t instead of a string */ 940c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 941c7c3e8aaSmarco if (ioctl(devh, BIOCDELETERAID, &bd)) 942c7c3e8aaSmarco errx(1, "delete volume %s failed", dev); 943c7c3e8aaSmarco } 944c7c3e8aaSmarco 945c6446370Sjsing void 946c6446370Sjsing bio_changepass(char *dev) 947c6446370Sjsing { 948c6446370Sjsing struct bioc_discipline bd; 949c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 950c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 951c6446370Sjsing struct sr_crypto_kdf_pbkdf2 kdfhint; 952c6446370Sjsing int rv; 953c6446370Sjsing 954c6446370Sjsing memset(&bd, 0, sizeof(bd)); 955c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 956c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 957c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 958c6446370Sjsing 959c6446370Sjsing /* XXX use dev_t instead of string. */ 960c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 961c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 962c6446370Sjsing bd.bd_size = sizeof(kdfhint); 963c6446370Sjsing bd.bd_data = &kdfhint; 964c6446370Sjsing 965c6446370Sjsing if (ioctl(devh, BIOCDISCIPLINE, &bd)) 966c6446370Sjsing errx(1, "%s: failed to get KDF hint", dev); 967c6446370Sjsing 968c6446370Sjsing /* Current passphrase. */ 969c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 970c6446370Sjsing 971c6446370Sjsing /* New passphrase. */ 972c6446370Sjsing bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1); 973c6446370Sjsing 974c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 975c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 976c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 977c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 978c6446370Sjsing 979c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 980c6446370Sjsing bd.bd_size = sizeof(kdfpair); 981c6446370Sjsing bd.bd_data = &kdfpair; 982c6446370Sjsing 983c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 984c6446370Sjsing 985c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 986c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 987c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 988c6446370Sjsing 989c6446370Sjsing if (rv) { 990c6446370Sjsing if (errno == EPERM) 991c6446370Sjsing errx(1, "%s: incorrect passphrase", dev); 992c6446370Sjsing else 993c6446370Sjsing errx(1, "%s: failed to change passphrase", dev); 994c6446370Sjsing } 995c6446370Sjsing } 996c6446370Sjsing 99703b2dfbfShenning #define BIOCTL_VIS_NBUF 4 99803b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 99903b2dfbfShenning 100003b2dfbfShenning char * 100103b2dfbfShenning bio_vis(char *s) 100203b2dfbfShenning { 100303b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 100403b2dfbfShenning static uint idx = 0; 100503b2dfbfShenning char *buf; 100603b2dfbfShenning 100703b2dfbfShenning buf = rbuf[idx++]; 100803b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 100903b2dfbfShenning idx = 0; 101003b2dfbfShenning 101103b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 101203b2dfbfShenning return (buf); 101303b2dfbfShenning } 101403b2dfbfShenning 101503b2dfbfShenning void 101603b2dfbfShenning bio_diskinq(char *sd_dev) 101703b2dfbfShenning { 101803b2dfbfShenning struct dk_inquiry di; 101903b2dfbfShenning 1020da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 1021da3b0664Shenning err(1, "DIOCINQ"); 102203b2dfbfShenning 102303b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 102403b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 102503b2dfbfShenning } 1026aef7fe28Shshoexer 1027aef7fe28Shshoexer void 10289e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt, 1029c6446370Sjsing size_t saltsz, char *prompt, int verify) 1030aef7fe28Shshoexer { 103186735da2Smarco FILE *f; 103286735da2Smarco size_t pl; 103386735da2Smarco struct stat sb; 10349e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 1035aef7fe28Shshoexer 1036aef7fe28Shshoexer if (!key) 1037aef7fe28Shshoexer errx(1, "Invalid key"); 1038aef7fe28Shshoexer if (!salt) 1039aef7fe28Shshoexer errx(1, "Invalid salt"); 1040aef7fe28Shshoexer if (rounds < 1000) 1041b4604b5cShalex errx(1, "Too few rounds: %d", rounds); 1042aef7fe28Shshoexer 1043aef7fe28Shshoexer /* get passphrase */ 1044ba3d8661Smarco if (password && verify) 1045ba3d8661Smarco errx(1, "can't specify passphrase file during initial " 1046ba3d8661Smarco "creation of crypto volume"); 1047ba3d8661Smarco if (password) { 104886735da2Smarco if ((f = fopen(password, "r")) == NULL) 104986735da2Smarco err(1, "invalid passphrase file"); 105086735da2Smarco 105186735da2Smarco if (fstat(fileno(f), &sb) == -1) 105286735da2Smarco err(1, "can't stat passphrase file"); 105386735da2Smarco if (sb.st_uid != 0) 105486735da2Smarco errx(1, "passphrase file must be owned by root"); 105586735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 105686735da2Smarco errx(1, "passphrase file has the wrong permissions"); 105786735da2Smarco 105886735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 105986735da2Smarco err(1, "can't read passphrase file"); 106086735da2Smarco pl = strlen(passphrase); 106186735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 106286735da2Smarco passphrase[pl - 1] = '\0'; 106386735da2Smarco else 106486735da2Smarco errx(1, "invalid passphrase length"); 106586735da2Smarco 106686735da2Smarco fclose(f); 1067ba3d8661Smarco } else { 1068c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1069c6446370Sjsing RPP_REQUIRE_TTY) == NULL) 10709e8c6f5bShshoexer errx(1, "unable to read passphrase"); 1071ba3d8661Smarco } 10729e8c6f5bShshoexer 10739e8c6f5bShshoexer if (verify) { 10749e8c6f5bShshoexer /* request user to re-type it */ 10759e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 10769e8c6f5bShshoexer sizeof(verifybuf), RPP_REQUIRE_TTY) == NULL) { 10779e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10789e8c6f5bShshoexer errx(1, "unable to read passphrase"); 10799e8c6f5bShshoexer } 10809e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 10819e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 10829e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 10839e8c6f5bShshoexer memset(verifybuf, 0, sizeof(verifybuf)); 10849e8c6f5bShshoexer errx(1, "Passphrases did not match"); 10859e8c6f5bShshoexer } 10869e8c6f5bShshoexer /* forget the re-typed one */ 10879e8c6f5bShshoexer memset(verifybuf, 0, strlen(verifybuf)); 10889e8c6f5bShshoexer } 1089aef7fe28Shshoexer 1090aef7fe28Shshoexer /* derive key from passphrase */ 10915c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 10925c1f8f6bSdjm key, keysz, rounds) != 0) 10935c1f8f6bSdjm errx(1, "pbkdf2 failed"); 1094aef7fe28Shshoexer 1095aef7fe28Shshoexer /* forget passphrase */ 10969e8c6f5bShshoexer memset(passphrase, 0, sizeof(passphrase)); 1097aef7fe28Shshoexer 1098aef7fe28Shshoexer return; 1099aef7fe28Shshoexer } 1100