1*61f93244Sjsing /* $OpenBSD: bioctl.c,v 1.133 2016/09/08 18:41:04 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 30b9fc9a72Sderaadt #include <sys/param.h> /* NODEV */ 31c2126c9aSmarco #include <sys/ioctl.h> 3291f4f7d8Sdlg #include <sys/dkio.h> 3346bc198bSmarco #include <sys/stat.h> 34aef7fe28Shshoexer #include <dev/softraidvar.h> 35e7d4f752Sderaadt #include <dev/biovar.h> 363af9de98Smarco 37db2730c1Smarco #include <errno.h> 38db2730c1Smarco #include <err.h> 39db2730c1Smarco #include <fcntl.h> 408ccdd032Sderaadt #include <util.h> 41934f30d8Sderaadt #include <ctype.h> 42db2730c1Smarco #include <stdio.h> 43db2730c1Smarco #include <stdlib.h> 44db2730c1Smarco #include <string.h> 45db2730c1Smarco #include <unistd.h> 46b9fc9a72Sderaadt #include <limits.h> 4703b2dfbfShenning #include <vis.h> 489e8c6f5bShshoexer #include <readpassphrase.h> 49db2730c1Smarco 506de960dcSmarco struct locator { 516de960dcSmarco int channel; 526de960dcSmarco int target; 536de960dcSmarco int lun; 546de960dcSmarco }; 556de960dcSmarco 56d865b7d2Suebayasi struct timing { 57d865b7d2Suebayasi int interval; 58d865b7d2Suebayasi int start; 59d865b7d2Suebayasi }; 60d865b7d2Suebayasi 618ccdd032Sderaadt void usage(void); 6241eccc89Sderaadt const char *str2locator(const char *, struct locator *); 63d865b7d2Suebayasi const char *str2patrol(const char *, struct timing *); 64d313c28bSjsing void bio_status(struct bio_status *); 6546bc198bSmarco int bio_parse_devlist(char *, dev_t *); 66aef7fe28Shshoexer void bio_kdf_derive(struct sr_crypto_kdfinfo *, 67c6446370Sjsing struct sr_crypto_kdf_pbkdf2 *, char *, int); 68aef7fe28Shshoexer void bio_kdf_generate(struct sr_crypto_kdfinfo *); 69*61f93244Sjsing void derive_key_pkcs(u_int32_t, int, u_int8_t *, size_t, 70*61f93244Sjsing u_int8_t *, size_t, char *, int); 718ccdd032Sderaadt 728ccdd032Sderaadt void bio_inq(char *); 738ccdd032Sderaadt void bio_alarm(char *); 74a15048bbSmarco int bio_getvolbyname(char *); 75a15048bbSmarco void bio_setstate(char *, int, char *); 76a928c459Sderaadt void bio_setblink(char *, char *, int); 77a928c459Sderaadt void bio_blink(char *, int, int); 780054cd36Sjsing void bio_createraid(u_int16_t, char *, char *); 79c7c3e8aaSmarco void bio_deleteraid(char *); 80c6446370Sjsing void bio_changepass(char *); 81e8a57fdeSmarco u_int32_t bio_createflags(char *); 8203b2dfbfShenning char *bio_vis(char *); 8303b2dfbfShenning void bio_diskinq(char *); 84d865b7d2Suebayasi void bio_patrol(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 93545c4d7fSjsing void *bio_cookie; 94545c4d7fSjsing 95b96c6ce2Sckuethe int rpp_flag = RPP_REQUIRE_TTY; 963af9de98Smarco 973af9de98Smarco int 983af9de98Smarco main(int argc, char *argv[]) 993af9de98Smarco { 100545c4d7fSjsing struct bio_locate bl; 1013af9de98Smarco extern char *optarg; 102db2730c1Smarco u_int64_t func = 0; 103e63d8b1dSdtucker char *devicename = NULL; 104cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 1057195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 1060054cd36Sjsing char *key_disk = NULL; 107aedd4f07Sdjm const char *errstr; 108d313c28bSjsing int ch, blink = 0, changepass = 0, diskinq = 0; 109c6446370Sjsing int ss_func = 0; 1109ecba717Sderaadt u_int16_t cr_level = 0; 111e37c64dbSjsing int biodev = 0; 1123af9de98Smarco 1133af9de98Smarco if (argc < 2) 1143af9de98Smarco usage(); 1153af9de98Smarco 116d865b7d2Suebayasi while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:O:Pp:qr:R:st:u:v")) != 117c6446370Sjsing -1) { 1183af9de98Smarco switch (ch) { 119edfd9792Smarco case 'a': /* alarm */ 120edfd9792Smarco func |= BIOC_ALARM; 121edfd9792Smarco al_arg = optarg; 122edfd9792Smarco break; 123c55617f1Sdlg case 'b': /* blink */ 124c55617f1Sdlg func |= BIOC_BLINK; 125a928c459Sderaadt blink = BIOC_SBBLINK; 126a928c459Sderaadt bl_arg = optarg; 127a928c459Sderaadt break; 128e8a57fdeSmarco case 'C': /* creation flags */ 129e8a57fdeSmarco cflags = bio_createflags(optarg); 130e8a57fdeSmarco break; 1317195049bSmarco case 'c': /* create */ 1327195049bSmarco func |= BIOC_CREATERAID; 133025f5691Sderaadt if (isdigit((unsigned char)*optarg)) { 13492d21b5cStedu cr_level = strtonum(optarg, 0, 10, &errstr); 13592d21b5cStedu if (errstr != NULL) 13692d21b5cStedu errx(1, "Invalid RAID level"); 13792d21b5cStedu } else 13898b750e4Stedu cr_level = *optarg; 1397195049bSmarco break; 140c7c3e8aaSmarco case 'd': 141c7c3e8aaSmarco /* delete volume */ 142c7c3e8aaSmarco func |= BIOC_DELETERAID; 143c7c3e8aaSmarco break; 144a928c459Sderaadt case 'u': /* unblink */ 145a928c459Sderaadt func |= BIOC_BLINK; 146a928c459Sderaadt blink = BIOC_SBUNBLINK; 147c55617f1Sdlg bl_arg = optarg; 148c55617f1Sdlg break; 1496de960dcSmarco case 'H': /* set hotspare */ 1506de960dcSmarco func |= BIOC_SETSTATE; 151a15048bbSmarco ss_func = BIOC_SSHOTSPARE; 1526de960dcSmarco al_arg = optarg; 1536de960dcSmarco break; 1548ccdd032Sderaadt case 'h': 1558ccdd032Sderaadt human = 1; 1568ccdd032Sderaadt break; 157db2730c1Smarco case 'i': /* inquiry */ 158db2730c1Smarco func |= BIOC_INQ; 1593af9de98Smarco break; 1600054cd36Sjsing case 'k': /* Key disk. */ 1610054cd36Sjsing key_disk = optarg; 1620054cd36Sjsing break; 1637195049bSmarco case 'l': /* device list */ 1647195049bSmarco func |= BIOC_DEVLIST; 1657195049bSmarco dev_list = optarg; 1667195049bSmarco break; 167c6446370Sjsing case 'P': 168c6446370Sjsing /* Change passphrase. */ 169c6446370Sjsing changepass = 1; 170c6446370Sjsing break; 17186735da2Smarco case 'p': 17286735da2Smarco password = optarg; 17386735da2Smarco break; 174aedd4f07Sdjm case 'r': 175aedd4f07Sdjm rflag = strtonum(optarg, 1000, 1<<30, &errstr); 176aedd4f07Sdjm if (errstr != NULL) 177*61f93244Sjsing errx(1, "number of KDF rounds is %s: %s", 178aedd4f07Sdjm errstr, optarg); 179aedd4f07Sdjm break; 18050e55a42Sjsing case 'O': 18150e55a42Sjsing /* set a chunk to offline */ 18250e55a42Sjsing func |= BIOC_SETSTATE; 18350e55a42Sjsing ss_func = BIOC_SSOFFLINE; 18450e55a42Sjsing al_arg = optarg; 18550e55a42Sjsing break; 186a15048bbSmarco case 'R': 187a15048bbSmarco /* rebuild to provided chunk/CTL */ 188a15048bbSmarco func |= BIOC_SETSTATE; 189a15048bbSmarco ss_func = BIOC_SSREBUILD; 190a15048bbSmarco al_arg = optarg; 191a15048bbSmarco break; 192b96c6ce2Sckuethe case 's': 193b96c6ce2Sckuethe rpp_flag = RPP_STDIN; 194b96c6ce2Sckuethe break; 195d865b7d2Suebayasi case 't': /* patrol */ 196d865b7d2Suebayasi func |= BIOC_PATROL; 197d865b7d2Suebayasi al_arg = optarg; 198d865b7d2Suebayasi break; 199abe9d68eSderaadt case 'v': 200abe9d68eSderaadt verbose = 1; 201abe9d68eSderaadt break; 20203b2dfbfShenning case 'q': 20303b2dfbfShenning diskinq = 1; 20403b2dfbfShenning break; 2053af9de98Smarco default: 2063af9de98Smarco usage(); 2073af9de98Smarco /* NOTREACHED */ 2083af9de98Smarco } 2093af9de98Smarco } 210cf6503d7Sderaadt argc -= optind; 211cf6503d7Sderaadt argv += optind; 2123af9de98Smarco 213c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 214cf6503d7Sderaadt usage(); 215cf6503d7Sderaadt 216dcbaf4c8Sderaadt if (func == 0) 217dcbaf4c8Sderaadt func |= BIOC_INQ; 218dcbaf4c8Sderaadt 219e63d8b1dSdtucker devicename = argv[0]; 220e63d8b1dSdtucker if (devicename == NULL) 221e37c64dbSjsing errx(1, "need device"); 22210b411a7Smarco 223e63d8b1dSdtucker devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname); 224e37c64dbSjsing if (devh == -1) { 22541eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2263af9de98Smarco if (devh == -1) 22741eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2283af9de98Smarco 229e63d8b1dSdtucker bl.bl_name = devicename; 230d313c28bSjsing if (ioctl(devh, BIOCLOCATE, &bl)) 23110b411a7Smarco errx(1, "Can't locate %s device via %s", 23241eccc89Sderaadt bl.bl_name, "/dev/bio"); 233d313c28bSjsing 234d313c28bSjsing bio_status(&bl.bl_bio.bio_status); 235d313c28bSjsing 236545c4d7fSjsing bio_cookie = bl.bl_bio.bio_cookie; 237e37c64dbSjsing biodev = 1; 238e63d8b1dSdtucker devicename = NULL; 239e37c64dbSjsing } 2403af9de98Smarco 24103b2dfbfShenning if (diskinq) { 242e63d8b1dSdtucker bio_diskinq(devicename); 243e37c64dbSjsing } else if (changepass && !biodev) { 244e63d8b1dSdtucker bio_changepass(devicename); 24503b2dfbfShenning } else if (func & BIOC_INQ) { 246e63d8b1dSdtucker bio_inq(devicename); 247edfd9792Smarco } else if (func == BIOC_ALARM) { 248edfd9792Smarco bio_alarm(al_arg); 249c55617f1Sdlg } else if (func == BIOC_BLINK) { 250e63d8b1dSdtucker bio_setblink(devicename, bl_arg, blink); 251d865b7d2Suebayasi } else if (func == BIOC_PATROL) { 252d865b7d2Suebayasi bio_patrol(al_arg); 2536de960dcSmarco } else if (func == BIOC_SETSTATE) { 254a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 255e37c64dbSjsing } else if (func == BIOC_DELETERAID && !biodev) { 256e63d8b1dSdtucker bio_deleteraid(devicename); 2577195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2587195049bSmarco if (!(func & BIOC_CREATERAID)) 2597195049bSmarco errx(1, "need -c parameter"); 2607195049bSmarco if (!(func & BIOC_DEVLIST)) 2617195049bSmarco errx(1, "need -l parameter"); 262e37c64dbSjsing if (!biodev) 263e37c64dbSjsing errx(1, "must use bio device"); 2640054cd36Sjsing bio_createraid(cr_level, dev_list, key_disk); 2653af9de98Smarco } 2663af9de98Smarco 2673af9de98Smarco return (0); 2683af9de98Smarco } 2693af9de98Smarco 2703af9de98Smarco void 2713af9de98Smarco usage(void) 2723af9de98Smarco { 2733af9de98Smarco extern char *__progname; 2743af9de98Smarco 275d90b5d8bSjmc fprintf(stderr, 276d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 277d90b5d8bSjmc "[-b channel:target[.lun]]\n" 278d0b772c8Sjmc "\t[-H channel:target[.lun]] " 279af56bbe7Smatthieu "[-R device | channel:target[.lun]]\n" 2802e6b119fSjmc "\t[-t patrol-function] " 2812e6b119fSjmc "[-u channel:target[.lun]] " 282d0b772c8Sjmc "device\n" 283b96c6ce2Sckuethe " %s [-dhiPqsv] " 284b90fdff5Sjmc "[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n" 28550e55a42Sjsing "\t[-l special[,special,...]] " 28650e55a42Sjsing "[-O device | channel:target[.lun]]\n" 28750e55a42Sjsing "\t[-p passfile] [-R device | channel:target[.lun]]\n" 2882e6b119fSjmc "\t[-r rounds] " 289d0b772c8Sjmc "device\n", __progname, __progname); 290d90b5d8bSjmc 2913af9de98Smarco exit(1); 2923af9de98Smarco } 2933af9de98Smarco 29441eccc89Sderaadt const char * 2956de960dcSmarco str2locator(const char *string, struct locator *location) 2966de960dcSmarco { 29750d3c4dcSdlg const char *errstr; 29841eccc89Sderaadt char parse[80], *targ, *lun; 2996de960dcSmarco 30041eccc89Sderaadt strlcpy(parse, string, sizeof parse); 30141eccc89Sderaadt targ = strchr(parse, ':'); 3026de960dcSmarco if (targ == NULL) 30341eccc89Sderaadt return ("target not specified"); 3046de960dcSmarco *targ++ = '\0'; 3056de960dcSmarco 30650d3c4dcSdlg lun = strchr(targ, '.'); 3076de960dcSmarco if (lun != NULL) { 3086de960dcSmarco *lun++ = '\0'; 30950d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 31050d3c4dcSdlg if (errstr) 31141eccc89Sderaadt return (errstr); 3126de960dcSmarco } else 3136de960dcSmarco location->lun = 0; 3146de960dcSmarco 31550d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 31650d3c4dcSdlg if (errstr) 31741eccc89Sderaadt return (errstr); 31841eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 31950d3c4dcSdlg if (errstr) 32041eccc89Sderaadt return (errstr); 32141eccc89Sderaadt return (NULL); 3226de960dcSmarco } 3236de960dcSmarco 324d865b7d2Suebayasi const char * 325d865b7d2Suebayasi str2patrol(const char *string, struct timing *timing) 326d865b7d2Suebayasi { 327d865b7d2Suebayasi const char *errstr; 328d865b7d2Suebayasi char parse[80], *interval = NULL, *start = NULL; 329d865b7d2Suebayasi 330d865b7d2Suebayasi timing->interval = 0; 331d865b7d2Suebayasi timing->start = 0; 332d865b7d2Suebayasi 333d865b7d2Suebayasi strlcpy(parse, string, sizeof parse); 334d865b7d2Suebayasi 335d865b7d2Suebayasi interval = strchr(parse, '.'); 336d865b7d2Suebayasi if (interval != NULL) { 337d865b7d2Suebayasi *interval++ = '\0'; 338d865b7d2Suebayasi start = strchr(interval, '.'); 339d865b7d2Suebayasi if (start != NULL) 340d865b7d2Suebayasi *start++ = '\0'; 341d865b7d2Suebayasi } 342d865b7d2Suebayasi if (interval != NULL) { 343d865b7d2Suebayasi /* -1 == continuously */ 344d865b7d2Suebayasi timing->interval = strtonum(interval, -1, INT_MAX, &errstr); 345d865b7d2Suebayasi if (errstr) 346d865b7d2Suebayasi return (errstr); 347d865b7d2Suebayasi } 348d865b7d2Suebayasi if (start != NULL) { 349d865b7d2Suebayasi timing->start = strtonum(start, 0, INT_MAX, &errstr); 350d865b7d2Suebayasi if (errstr) 351d865b7d2Suebayasi return (errstr); 352d865b7d2Suebayasi } 353d865b7d2Suebayasi 354d865b7d2Suebayasi return (NULL); 355d865b7d2Suebayasi } 356d865b7d2Suebayasi 3573af9de98Smarco void 358d313c28bSjsing bio_status(struct bio_status *bs) 359d313c28bSjsing { 3600a69bfccSjsing extern char *__progname; 3610a69bfccSjsing char *prefix; 362d313c28bSjsing int i; 363d313c28bSjsing 364d313c28bSjsing if (strlen(bs->bs_controller)) 3650a69bfccSjsing prefix = bs->bs_controller; 3660a69bfccSjsing else 3670a69bfccSjsing prefix = __progname; 368d313c28bSjsing 3690a69bfccSjsing for (i = 0; i < bs->bs_msg_count; i++) 3700a69bfccSjsing printf("%s: %s\n", prefix, bs->bs_msgs[i].bm_msg); 3710a69bfccSjsing 3720a69bfccSjsing if (bs->bs_status == BIO_STATUS_ERROR) { 3730a69bfccSjsing if (bs->bs_msg_count == 0) 3740a69bfccSjsing errx(1, "unknown error"); 3750a69bfccSjsing else 376d313c28bSjsing exit(1); 377d313c28bSjsing } 3780a69bfccSjsing } 379d313c28bSjsing 380d313c28bSjsing void 3818ccdd032Sderaadt bio_inq(char *name) 382d4546a56Sdlg { 383cc711184Skettenis char *status, *cache; 384cc711184Skettenis char size[64], scsiname[16], volname[32]; 385d865b7d2Suebayasi char percent[20], seconds[20]; 386d313c28bSjsing int i, d, volheader, hotspare, unused; 387aa65acf1Sderaadt char encname[16], serial[32]; 3888ccdd032Sderaadt struct bioc_inq bi; 3898ccdd032Sderaadt struct bioc_vol bv; 390c2b1f828Sderaadt struct bioc_disk bd; 391db2730c1Smarco 392db2730c1Smarco memset(&bi, 0, sizeof(bi)); 3933af9de98Smarco 394545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 3953af9de98Smarco 396d313c28bSjsing if (ioctl(devh, BIOCINQ, &bi)) { 39703b2dfbfShenning if (errno == ENOTTY) 39803b2dfbfShenning bio_diskinq(name); 39903b2dfbfShenning else 400da3b0664Shenning err(1, "BIOCINQ"); 4013af9de98Smarco return; 4023af9de98Smarco } 4033af9de98Smarco 404d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 405d313c28bSjsing 4068ccdd032Sderaadt volheader = 0; 4078ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 408db2730c1Smarco memset(&bv, 0, sizeof(bv)); 409545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 4108ccdd032Sderaadt bv.bv_volid = i; 4110a92ff65Sderaadt bv.bv_percent = -1; 4129017fb97Sderaadt bv.bv_seconds = 0; 41370a2ae7bSmarco 414d313c28bSjsing if (ioctl(devh, BIOCVOL, &bv)) 415da3b0664Shenning err(1, "BIOCVOL"); 4163af9de98Smarco 417d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 418d313c28bSjsing 4198ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 4208ccdd032Sderaadt continue; 4218ccdd032Sderaadt 4228ccdd032Sderaadt if (!volheader) { 4238ccdd032Sderaadt volheader = 1; 424150c22bbSjcs printf("%-11s %-10s %14s %-8s\n", 4258ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 4268ccdd032Sderaadt } 4278ccdd032Sderaadt 4280a92ff65Sderaadt percent[0] = '\0'; 4299017fb97Sderaadt seconds[0] = '\0'; 4300a92ff65Sderaadt if (bv.bv_percent != -1) 4310a92ff65Sderaadt snprintf(percent, sizeof percent, 4320a92ff65Sderaadt " %d%% done", bv.bv_percent); 4339017fb97Sderaadt if (bv.bv_seconds) 4349017fb97Sderaadt snprintf(seconds, sizeof seconds, 4359017fb97Sderaadt " %u seconds", bv.bv_seconds); 4368ccdd032Sderaadt switch (bv.bv_status) { 437db2730c1Smarco case BIOC_SVONLINE: 4388ccdd032Sderaadt status = BIOC_SVONLINE_S; 439db2730c1Smarco break; 440db2730c1Smarco case BIOC_SVOFFLINE: 4418ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 442db2730c1Smarco break; 443db2730c1Smarco case BIOC_SVDEGRADED: 4448ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 445db2730c1Smarco break; 4460a92ff65Sderaadt case BIOC_SVBUILDING: 4470a92ff65Sderaadt status = BIOC_SVBUILDING_S; 4480a92ff65Sderaadt break; 4490a92ff65Sderaadt case BIOC_SVREBUILD: 4500a92ff65Sderaadt status = BIOC_SVREBUILD_S; 4510a92ff65Sderaadt break; 4520a92ff65Sderaadt case BIOC_SVSCRUB: 4530a92ff65Sderaadt status = BIOC_SVSCRUB_S; 4540a92ff65Sderaadt break; 455db2730c1Smarco case BIOC_SVINVALID: 456db2730c1Smarco default: 4578ccdd032Sderaadt status = BIOC_SVINVALID_S; 458d4546a56Sdlg } 459cc711184Skettenis switch (bv.bv_cache) { 460cc711184Skettenis case BIOC_CVWRITEBACK: 461cc711184Skettenis cache = BIOC_CVWRITEBACK_S; 462cc711184Skettenis break; 463cc711184Skettenis case BIOC_CVWRITETHROUGH: 464cc711184Skettenis cache = BIOC_CVWRITETHROUGH_S; 465cc711184Skettenis break; 466cc711184Skettenis case BIOC_CVUNKNOWN: 467cc711184Skettenis default: 468cc711184Skettenis cache = BIOC_CVUNKNOWN_S; 469cc711184Skettenis } 4703af9de98Smarco 471aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 4728ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 473b9950701Smarco 4749ecba717Sderaadt unused = 0; 4759ecba717Sderaadt hotspare = 0; 476aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 477aa65acf1Sderaadt hotspare = 1; 478b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 479b9950701Smarco unused = 1; 480aa65acf1Sderaadt else { 4818ccdd032Sderaadt if (human) 4828ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 4838ccdd032Sderaadt else 4848ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4858ccdd032Sderaadt bv.bv_size); 486da935596Stodd switch (bv.bv_level) { 487da935596Stodd case 'C': 488150c22bbSjcs printf("%11s %-10s %14s %-7s CRYPTO%s%s\n", 489da935596Stodd volname, status, size, bv.bv_dev, 490da935596Stodd percent, seconds); 491da935596Stodd break; 4922b5fc845Sjsing case 'c': 4932b5fc845Sjsing printf("%11s %-10s %14s %-7s CONCAT%s%s\n", 4942b5fc845Sjsing volname, status, size, bv.bv_dev, 4952b5fc845Sjsing percent, seconds); 4962b5fc845Sjsing break; 497da935596Stodd default: 498cc711184Skettenis printf("%11s %-10s %14s %-7s RAID%u%s%s %s\n", 4990a92ff65Sderaadt volname, status, size, bv.bv_dev, 500cc711184Skettenis bv.bv_level, percent, seconds, cache); 501da935596Stodd break; 502da935596Stodd } 503da935596Stodd 504aa65acf1Sderaadt } 5058ccdd032Sderaadt 5068ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 507db2730c1Smarco memset(&bd, 0, sizeof(bd)); 508545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 5098ccdd032Sderaadt bd.bd_diskid = d; 5108ccdd032Sderaadt bd.bd_volid = i; 511d865b7d2Suebayasi bd.bd_patrol.bdp_percent = -1; 512d865b7d2Suebayasi bd.bd_patrol.bdp_seconds = 0; 5133af9de98Smarco 514d313c28bSjsing if (ioctl(devh, BIOCDISK, &bd)) 515da3b0664Shenning err(1, "BIOCDISK"); 5163af9de98Smarco 517d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 518d313c28bSjsing 5198ccdd032Sderaadt switch (bd.bd_status) { 520db2730c1Smarco case BIOC_SDONLINE: 5218ccdd032Sderaadt status = BIOC_SDONLINE_S; 522d4546a56Sdlg break; 523db2730c1Smarco case BIOC_SDOFFLINE: 5248ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 525d4546a56Sdlg break; 526db2730c1Smarco case BIOC_SDFAILED: 5278ccdd032Sderaadt status = BIOC_SDFAILED_S; 528db2730c1Smarco break; 529db2730c1Smarco case BIOC_SDREBUILD: 5308ccdd032Sderaadt status = BIOC_SDREBUILD_S; 531db2730c1Smarco break; 532db2730c1Smarco case BIOC_SDHOTSPARE: 5338ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 534db2730c1Smarco break; 535db2730c1Smarco case BIOC_SDUNUSED: 5368ccdd032Sderaadt status = BIOC_SDUNUSED_S; 537db2730c1Smarco break; 538e1dfb373Sderaadt case BIOC_SDSCRUB: 539e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 540e1dfb373Sderaadt break; 541db2730c1Smarco case BIOC_SDINVALID: 542d4546a56Sdlg default: 5438ccdd032Sderaadt status = BIOC_SDINVALID_S; 544d4546a56Sdlg } 545aa65acf1Sderaadt 546b9950701Smarco if (hotspare || unused) 547aa65acf1Sderaadt ; /* use volname from parent volume */ 548aa65acf1Sderaadt else 549aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 550aa65acf1Sderaadt bd.bd_diskid); 551aa65acf1Sderaadt 5520054cd36Sjsing if (bv.bv_level == 'C' && bd.bd_size == 0) 5530054cd36Sjsing snprintf(size, sizeof size, "%14s", "key disk"); 5540054cd36Sjsing else if (human) 5558ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 5568ccdd032Sderaadt else 5578ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 5588ccdd032Sderaadt bd.bd_size); 5598ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 56043d61178Sderaadt "%u:%u.%u", 56143d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 5625978b28dSderaadt if (bd.bd_procdev[0]) 563abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 5645978b28dSderaadt else 565abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 566abe9d68eSderaadt if (bd.bd_serial[0]) 567abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 568abe9d68eSderaadt else 569abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 5708ccdd032Sderaadt 571d865b7d2Suebayasi percent[0] = '\0'; 572d865b7d2Suebayasi seconds[0] = '\0'; 573d865b7d2Suebayasi if (bd.bd_patrol.bdp_percent != -1) 574d865b7d2Suebayasi snprintf(percent, sizeof percent, 575d865b7d2Suebayasi " patrol %d%% done", bd.bd_patrol.bdp_percent); 576d865b7d2Suebayasi if (bd.bd_patrol.bdp_seconds) 577d865b7d2Suebayasi snprintf(seconds, sizeof seconds, 578d865b7d2Suebayasi " %u seconds", bd.bd_patrol.bdp_seconds); 579d865b7d2Suebayasi 580150c22bbSjcs printf("%11s %-10s %14s %-7s %-6s <%s>\n", 581aa65acf1Sderaadt volname, status, size, scsiname, encname, 5828ccdd032Sderaadt bd.bd_vendor); 583abe9d68eSderaadt if (verbose) 584d865b7d2Suebayasi printf("%11s %-10s %14s %-7s %-6s '%s'%s%s\n", 585d865b7d2Suebayasi "", "", "", "", "", serial, percent, seconds); 586d4546a56Sdlg } 587d4546a56Sdlg } 588d4546a56Sdlg } 589edfd9792Smarco 590edfd9792Smarco void 591edfd9792Smarco bio_alarm(char *arg) 592edfd9792Smarco { 5938ccdd032Sderaadt struct bioc_alarm ba; 594edfd9792Smarco 595c2b1f828Sderaadt memset(&ba, 0, sizeof(ba)); 596545c4d7fSjsing ba.ba_bio.bio_cookie = bio_cookie; 597edfd9792Smarco 598edfd9792Smarco switch (arg[0]) { 599edfd9792Smarco case 'q': /* silence alarm */ 600edfd9792Smarco /* FALLTHROUGH */ 601edfd9792Smarco case 's': 6028ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 603edfd9792Smarco break; 604edfd9792Smarco 605edfd9792Smarco case 'e': /* enable alarm */ 6068ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 607edfd9792Smarco break; 608edfd9792Smarco 609edfd9792Smarco case 'd': /* disable alarm */ 6108ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 611edfd9792Smarco break; 612edfd9792Smarco 613edfd9792Smarco case 't': /* test alarm */ 6148ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 615edfd9792Smarco break; 616edfd9792Smarco 617edfd9792Smarco case 'g': /* get alarm state */ 6188ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 619edfd9792Smarco break; 620edfd9792Smarco 621edfd9792Smarco default: 622da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 623edfd9792Smarco } 624edfd9792Smarco 625d313c28bSjsing if (ioctl(devh, BIOCALARM, &ba)) 626da3b0664Shenning err(1, "BIOCALARM"); 627edfd9792Smarco 628d313c28bSjsing bio_status(&ba.ba_bio.bio_status); 629d313c28bSjsing 630d313c28bSjsing if (arg[0] == 'g') 631edfd9792Smarco printf("alarm is currently %s\n", 6328ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 633edfd9792Smarco } 6346de960dcSmarco 635a15048bbSmarco int 636a15048bbSmarco bio_getvolbyname(char *name) 637a15048bbSmarco { 638d313c28bSjsing int id = -1, i; 639a15048bbSmarco struct bioc_inq bi; 640a15048bbSmarco struct bioc_vol bv; 641a15048bbSmarco 642a15048bbSmarco memset(&bi, 0, sizeof(bi)); 643545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 644d313c28bSjsing if (ioctl(devh, BIOCINQ, &bi)) 645a15048bbSmarco err(1, "BIOCINQ"); 646a15048bbSmarco 647d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 648d313c28bSjsing 649a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 650a15048bbSmarco memset(&bv, 0, sizeof(bv)); 651545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 652a15048bbSmarco bv.bv_volid = i; 653d313c28bSjsing if (ioctl(devh, BIOCVOL, &bv)) 654a15048bbSmarco err(1, "BIOCVOL"); 655a15048bbSmarco 656d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 657d313c28bSjsing 658a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 659a15048bbSmarco continue; 660a15048bbSmarco id = i; 661a15048bbSmarco break; 662a15048bbSmarco } 663a15048bbSmarco 664a15048bbSmarco return (id); 665a15048bbSmarco } 666a15048bbSmarco 667ebaf584eSderaadt void 6688d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 6696de960dcSmarco { 6706de960dcSmarco struct bioc_setstate bs; 6716de960dcSmarco struct locator location; 672a15048bbSmarco struct stat sb; 67341eccc89Sderaadt const char *errstr; 6746de960dcSmarco 675a15048bbSmarco memset(&bs, 0, sizeof(bs)); 676a15048bbSmarco if (stat(arg, &sb) == -1) { 677a15048bbSmarco /* use CTL */ 67841eccc89Sderaadt errstr = str2locator(arg, &location); 67941eccc89Sderaadt if (errstr) 68041eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 6816de960dcSmarco bs.bs_channel = location.channel; 6826de960dcSmarco bs.bs_target = location.target; 6836de960dcSmarco bs.bs_lun = location.lun; 684a15048bbSmarco } else { 685a15048bbSmarco /* use other id */ 686a15048bbSmarco bs.bs_other_id = sb.st_rdev; 687a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 688a15048bbSmarco } 689a15048bbSmarco 690545c4d7fSjsing bs.bs_bio.bio_cookie = bio_cookie; 691a15048bbSmarco bs.bs_status = status; 692a15048bbSmarco 693d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 694a15048bbSmarco /* make sure user supplied a sd device */ 6958d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 696a15048bbSmarco if (bs.bs_volid == -1) 6978d8693a2Sdtucker errx(1, "invalid device %s", devicename); 698d2647ac1Sjsing } 6996de960dcSmarco 700d313c28bSjsing if (ioctl(devh, BIOCSETSTATE, &bs)) 701da3b0664Shenning err(1, "BIOCSETSTATE"); 702d313c28bSjsing 703d313c28bSjsing bio_status(&bs.bs_bio.bio_status); 7046de960dcSmarco } 705c55617f1Sdlg 706c55617f1Sdlg void 707a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 708c55617f1Sdlg { 70950d3c4dcSdlg struct locator location; 710c2b1f828Sderaadt struct bioc_blink bb; 71150d3c4dcSdlg struct bioc_inq bi; 71250d3c4dcSdlg struct bioc_vol bv; 71350d3c4dcSdlg struct bioc_disk bd; 71441eccc89Sderaadt const char *errstr; 71550d3c4dcSdlg int v, d, rv; 716c55617f1Sdlg 71741eccc89Sderaadt errstr = str2locator(arg, &location); 71841eccc89Sderaadt if (errstr) 71941eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 72050d3c4dcSdlg 7210505205bSdlg /* try setting blink on the device directly */ 7220505205bSdlg memset(&bb, 0, sizeof(bb)); 723545c4d7fSjsing bb.bb_bio.bio_cookie = bio_cookie; 7240505205bSdlg bb.bb_status = blink; 7250505205bSdlg bb.bb_target = location.target; 726649724a4Smarco bb.bb_channel = location.channel; 7270505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 728d313c28bSjsing 729d313c28bSjsing if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_UNKNOWN) 7300505205bSdlg return; 7310505205bSdlg 732d313c28bSjsing if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_SUCCESS) { 733d313c28bSjsing bio_status(&bb.bb_bio.bio_status); 734d313c28bSjsing return; 735d313c28bSjsing } 736d313c28bSjsing 737855d4e83Ssobrado /* if the blink didn't work, try to find something that will */ 7380505205bSdlg 73950d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 740545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 741d313c28bSjsing if (ioctl(devh, BIOCINQ, &bi)) 742da3b0664Shenning err(1, "BIOCINQ"); 74350d3c4dcSdlg 744d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 745d313c28bSjsing 74650d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 74750d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 748545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 74950d3c4dcSdlg bv.bv_volid = v; 750d313c28bSjsing if (ioctl(devh, BIOCVOL, &bv)) 751da3b0664Shenning err(1, "BIOCVOL"); 75250d3c4dcSdlg 753d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 754d313c28bSjsing 75550d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 75650d3c4dcSdlg continue; 75750d3c4dcSdlg 75850d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 75950d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 760545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 76150d3c4dcSdlg bd.bd_volid = v; 76250d3c4dcSdlg bd.bd_diskid = d; 76350d3c4dcSdlg 764d313c28bSjsing if (ioctl(devh, BIOCDISK, &bd)) 765da3b0664Shenning err(1, "BIOCDISK"); 76650d3c4dcSdlg 767d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 768d313c28bSjsing 76950d3c4dcSdlg if (bd.bd_channel == location.channel && 77050d3c4dcSdlg bd.bd_target == location.target && 77150d3c4dcSdlg bd.bd_lun == location.lun) { 772d313c28bSjsing if (bd.bd_procdev[0] != '\0') 77350d3c4dcSdlg bio_blink(bd.bd_procdev, 774a928c459Sderaadt location.target, blink); 775d313c28bSjsing else 776d313c28bSjsing warnx("Disk %s is not in an enclosure", 777d313c28bSjsing arg); 77850d3c4dcSdlg return; 77950d3c4dcSdlg } 78050d3c4dcSdlg } 78150d3c4dcSdlg } 78250d3c4dcSdlg 78341eccc89Sderaadt warnx("Disk %s does not exist", arg); 784d313c28bSjsing 78550d3c4dcSdlg return; 78650d3c4dcSdlg } 78750d3c4dcSdlg 78850d3c4dcSdlg void 789a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 79050d3c4dcSdlg { 79150d3c4dcSdlg int bioh; 792d313c28bSjsing struct bio_locate bl; 79350d3c4dcSdlg struct bioc_blink blink; 79450d3c4dcSdlg 79541eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 79650d3c4dcSdlg if (bioh == -1) 79741eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 79850d3c4dcSdlg 799c2b1f828Sderaadt memset(&bl, 0, sizeof(bl)); 800d313c28bSjsing bl.bl_name = enclosure; 801d313c28bSjsing if (ioctl(bioh, BIOCLOCATE, &bl)) 80241eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 803c55617f1Sdlg 804d313c28bSjsing bio_status(&bl.bl_bio.bio_status); 805d313c28bSjsing 806c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 807545c4d7fSjsing blink.bb_bio.bio_cookie = bio_cookie; 808a928c459Sderaadt blink.bb_status = blinktype; 809c55617f1Sdlg blink.bb_target = target; 810c55617f1Sdlg 811d313c28bSjsing if (ioctl(bioh, BIOCBLINK, &blink)) 812da3b0664Shenning err(1, "BIOCBLINK"); 81350d3c4dcSdlg 814d313c28bSjsing bio_status(&blink.bb_bio.bio_status); 815d313c28bSjsing 81650d3c4dcSdlg close(bioh); 817c55617f1Sdlg } 8187195049bSmarco 8197195049bSmarco void 8200054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk) 8217195049bSmarco { 8227195049bSmarco struct bioc_createraid create; 823aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 824aef7fe28Shshoexer struct sr_crypto_kdf_pbkdf2 kdfhint; 8250054cd36Sjsing struct stat sb; 8268b0d0f28Sjsing int rv, no_dev, fd; 8277f8eae2bSnicm dev_t *dt; 8287195049bSmarco u_int16_t min_disks = 0; 8297195049bSmarco 8307195049bSmarco if (!dev_list) 8317195049bSmarco errx(1, "no devices specified"); 8327195049bSmarco 833f9b0dfcfStedu dt = calloc(1, BIOC_CRMAXLEN); 83446bc198bSmarco if (!dt) 83546bc198bSmarco err(1, "not enough memory for dev_t list"); 83646bc198bSmarco 83746bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 83846bc198bSmarco 8397195049bSmarco switch (level) { 8407195049bSmarco case 0: 84184e48fabSmarco min_disks = 2; 8427195049bSmarco break; 8437195049bSmarco case 1: 8447195049bSmarco min_disks = 2; 8457195049bSmarco break; 846e717853eSmarco case 5: 847e717853eSmarco min_disks = 3; 848e717853eSmarco break; 84984e48fabSmarco case 'C': 850aef7fe28Shshoexer min_disks = 1; 85184e48fabSmarco break; 85298b750e4Stedu case 'c': 8538fe6c343Sjsing min_disks = 2; 85498b750e4Stedu break; 8557195049bSmarco default: 85623afedbfSgrunk errx(1, "unsupported raid level"); 8577195049bSmarco } 8587195049bSmarco 85984e48fabSmarco if (no_dev < min_disks) 86084e48fabSmarco errx(1, "not enough disks"); 86184e48fabSmarco 862aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 863aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 864818b0595Shalex errx(1, "not exactly one partition"); 865aef7fe28Shshoexer 8667195049bSmarco memset(&create, 0, sizeof(create)); 867545c4d7fSjsing create.bc_bio.bio_cookie = bio_cookie; 8687195049bSmarco create.bc_level = level; 86946bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 87046bc198bSmarco create.bc_dev_list = dt; 871e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 8720054cd36Sjsing create.bc_key_disk = NODEV; 8737195049bSmarco 874e7d4f752Sderaadt if (level == 'C' && key_disk == NULL) { 8750054cd36Sjsing 876aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 877aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 878aef7fe28Shshoexer 8790054cd36Sjsing create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 8800054cd36Sjsing 881aef7fe28Shshoexer create.bc_opaque = &kdfhint; 882aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 883aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 884aef7fe28Shshoexer 885aef7fe28Shshoexer /* try to get KDF hint */ 886d313c28bSjsing if (ioctl(devh, BIOCCREATERAID, &create)) 88783e979edShshoexer err(1, "ioctl"); 88883e979edShshoexer 889d313c28bSjsing bio_status(&create.bc_bio.bio_status); 890d313c28bSjsing 89183e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 892c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 893aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 894aef7fe28Shshoexer } else { 895aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 896aef7fe28Shshoexer } 897aef7fe28Shshoexer 898aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 899aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 900aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 9010054cd36Sjsing 9020054cd36Sjsing } else if (level == 'C' && key_disk != NULL) { 9030054cd36Sjsing 9048b0d0f28Sjsing /* Get device number for key disk. */ 9058b0d0f28Sjsing fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL); 9068b0d0f28Sjsing if (fd == -1) 9078b0d0f28Sjsing err(1, "could not open %s", key_disk); 9088b0d0f28Sjsing if (fstat(fd, &sb) == -1) { 909ffb4dd05Sguenther int saved_errno = errno; 9108b0d0f28Sjsing close(fd); 911ffb4dd05Sguenther errc(1, saved_errno, "could not stat %s", key_disk); 9128b0d0f28Sjsing } 9138b0d0f28Sjsing close(fd); 9140054cd36Sjsing create.bc_key_disk = sb.st_rdev; 9150054cd36Sjsing 9160054cd36Sjsing memset(&kdfinfo, 0, sizeof(kdfinfo)); 9170054cd36Sjsing 9180054cd36Sjsing kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf); 9190054cd36Sjsing kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK; 9200054cd36Sjsing kdfinfo.len = sizeof(kdfinfo); 9210054cd36Sjsing kdfinfo.flags = SR_CRYPTOKDF_HINT; 9220054cd36Sjsing 9230054cd36Sjsing create.bc_opaque = &kdfinfo; 9240054cd36Sjsing create.bc_opaque_size = sizeof(kdfinfo); 9250054cd36Sjsing create.bc_opaque_flags = BIOC_SOIN; 9260054cd36Sjsing 927aef7fe28Shshoexer } 928aef7fe28Shshoexer 9297195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 9300a488504Spelikan explicit_bzero(&kdfinfo, sizeof(kdfinfo)); 931d313c28bSjsing if (rv == -1) 932da3b0664Shenning err(1, "BIOCCREATERAID"); 933d313c28bSjsing 934d313c28bSjsing bio_status(&create.bc_bio.bio_status); 93546bc198bSmarco 93646bc198bSmarco free(dt); 93746bc198bSmarco } 93846bc198bSmarco 939aef7fe28Shshoexer void 940aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 941c6446370Sjsing *kdfhint, char* prompt, int verify) 942aef7fe28Shshoexer { 943aef7fe28Shshoexer if (!kdfinfo) 944aef7fe28Shshoexer errx(1, "invalid KDF info"); 945aef7fe28Shshoexer if (!kdfhint) 946aef7fe28Shshoexer errx(1, "invalid KDF hint"); 947aef7fe28Shshoexer 948aef7fe28Shshoexer if (kdfhint->len != sizeof(*kdfhint)) 949aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 950aef7fe28Shshoexer 951aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 952aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 953aef7fe28Shshoexer 954*61f93244Sjsing derive_key_pkcs(kdfhint->type, kdfhint->rounds, 955aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 956*61f93244Sjsing kdfhint->salt, sizeof(kdfhint->salt), 957*61f93244Sjsing prompt, verify); 958aef7fe28Shshoexer } 959aef7fe28Shshoexer 960aef7fe28Shshoexer void 961aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 962aef7fe28Shshoexer { 963aef7fe28Shshoexer if (!kdfinfo) 964aef7fe28Shshoexer errx(1, "invalid KDF info"); 965aef7fe28Shshoexer 966aef7fe28Shshoexer kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 967aef7fe28Shshoexer kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 968aedd4f07Sdjm kdfinfo->pbkdf2.rounds = rflag; 969*61f93244Sjsing 9700054cd36Sjsing kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT; 971*61f93244Sjsing kdfinfo->len = sizeof(*kdfinfo); 972aef7fe28Shshoexer 973aef7fe28Shshoexer /* generate salt */ 974aef7fe28Shshoexer arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 975aef7fe28Shshoexer 976*61f93244Sjsing derive_key_pkcs(kdfinfo->pbkdf2.type, kdfinfo->pbkdf2.rounds, 977aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 978c6446370Sjsing kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 979c6446370Sjsing "New passphrase: ", 1); 980aef7fe28Shshoexer } 981aef7fe28Shshoexer 98246bc198bSmarco int 98346bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 98446bc198bSmarco { 98546bc198bSmarco char *s, *e; 98646bc198bSmarco u_int32_t sz = 0; 98746bc198bSmarco int no_dev = 0, i, x; 98846bc198bSmarco struct stat sb; 989b9fc9a72Sderaadt char dev[PATH_MAX]; 990e37c64dbSjsing int fd; 99146bc198bSmarco 99246bc198bSmarco if (!lst) 99346bc198bSmarco errx(1, "invalid device list"); 99446bc198bSmarco 99546bc198bSmarco s = e = lst; 99646bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 99746bc198bSmarco while (*e != '\0') { 99846bc198bSmarco if (*e == ',') 99946bc198bSmarco s = e + 1; 100046bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 100146bc198bSmarco /* got one */ 100246bc198bSmarco sz = e - s + 1; 10035c1f8f6bSdjm strlcpy(dev, s, sz + 1); 1004e37c64dbSjsing fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL); 1005e37c64dbSjsing if (fd == -1) 1006e37c64dbSjsing err(1, "could not open %s", dev); 1007e37c64dbSjsing if (fstat(fd, &sb) == -1) { 1008ffb4dd05Sguenther int saved_errno = errno; 1009e37c64dbSjsing close(fd); 1010ffb4dd05Sguenther errc(1, saved_errno, "could not stat %s", dev); 1011e37c64dbSjsing } 1012e37c64dbSjsing close(fd); 101346bc198bSmarco dt[no_dev] = sb.st_rdev; 101446bc198bSmarco no_dev++; 10155c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 101646bc198bSmarco errx(1, "too many devices on device list"); 101746bc198bSmarco } 101846bc198bSmarco e++; 101946bc198bSmarco } 102046bc198bSmarco 102146bc198bSmarco for (i = 0; i < no_dev; i++) 102246bc198bSmarco for (x = 0; x < no_dev; x++) 102346bc198bSmarco if (dt[i] == dt[x] && x != i) 102446bc198bSmarco errx(1, "duplicate device in list"); 102546bc198bSmarco 102646bc198bSmarco return (no_dev); 10277195049bSmarco } 1028e8a57fdeSmarco 1029e8a57fdeSmarco u_int32_t 1030e8a57fdeSmarco bio_createflags(char *lst) 1031e8a57fdeSmarco { 1032e8a57fdeSmarco char *s, *e, fs[32]; 1033e8a57fdeSmarco u_int32_t sz = 0; 1034e8a57fdeSmarco u_int32_t flags = 0; 1035e8a57fdeSmarco 1036e8a57fdeSmarco if (!lst) 1037e8a57fdeSmarco errx(1, "invalid flags list"); 1038e8a57fdeSmarco 1039e8a57fdeSmarco s = e = lst; 1040e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 1041e8a57fdeSmarco while (*e != '\0') { 1042e8a57fdeSmarco if (*e == ',') 1043e8a57fdeSmarco s = e + 1; 1044e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 1045e8a57fdeSmarco /* got one */ 1046e8a57fdeSmarco sz = e - s + 1; 1047e8a57fdeSmarco switch (s[0]) { 1048e8a57fdeSmarco case 'f': 1049e8a57fdeSmarco flags |= BIOC_SCFORCE; 1050e8a57fdeSmarco break; 1051e8a57fdeSmarco case 'n': 1052e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 1053e8a57fdeSmarco break; 1054e8a57fdeSmarco default: 1055e8a57fdeSmarco strlcpy(fs, s, sz + 1); 1056e8a57fdeSmarco errx(1, "invalid flag %s", fs); 1057e8a57fdeSmarco } 1058e8a57fdeSmarco } 1059e8a57fdeSmarco e++; 1060e8a57fdeSmarco } 1061e8a57fdeSmarco 1062e8a57fdeSmarco return (flags); 1063e8a57fdeSmarco } 106403b2dfbfShenning 1065c7c3e8aaSmarco void 1066c7c3e8aaSmarco bio_deleteraid(char *dev) 1067c7c3e8aaSmarco { 1068c7c3e8aaSmarco struct bioc_deleteraid bd; 1069c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 1070c7c3e8aaSmarco 1071545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 1072a15048bbSmarco /* XXX make this a dev_t instead of a string */ 1073c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 1074c7c3e8aaSmarco if (ioctl(devh, BIOCDELETERAID, &bd)) 1075d313c28bSjsing err(1, "BIOCDELETERAID"); 1076d313c28bSjsing 1077d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1078c7c3e8aaSmarco } 1079c7c3e8aaSmarco 1080c6446370Sjsing void 1081c6446370Sjsing bio_changepass(char *dev) 1082c6446370Sjsing { 1083c6446370Sjsing struct bioc_discipline bd; 1084c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 1085c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 1086c6446370Sjsing struct sr_crypto_kdf_pbkdf2 kdfhint; 1087c6446370Sjsing int rv; 1088c6446370Sjsing 1089c6446370Sjsing memset(&bd, 0, sizeof(bd)); 1090c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 1091c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 1092c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 1093c6446370Sjsing 1094c6446370Sjsing /* XXX use dev_t instead of string. */ 1095c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 1096c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 1097c6446370Sjsing bd.bd_size = sizeof(kdfhint); 1098c6446370Sjsing bd.bd_data = &kdfhint; 1099c6446370Sjsing 1100c6446370Sjsing if (ioctl(devh, BIOCDISCIPLINE, &bd)) 1101d313c28bSjsing err(1, "BIOCDISCIPLINE"); 1102d313c28bSjsing 1103d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1104c6446370Sjsing 1105c6446370Sjsing /* Current passphrase. */ 1106c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 1107c6446370Sjsing 1108c6446370Sjsing /* New passphrase. */ 11092c98a0f7Sjsing bio_kdf_generate(&kdfinfo2); 1110c6446370Sjsing 1111c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 1112c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 1113c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 1114c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 1115c6446370Sjsing 1116c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 1117c6446370Sjsing bd.bd_size = sizeof(kdfpair); 1118c6446370Sjsing bd.bd_data = &kdfpair; 1119c6446370Sjsing 1120c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 1121c6446370Sjsing 1122c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 11230a488504Spelikan explicit_bzero(&kdfinfo1, sizeof(kdfinfo1)); 11240a488504Spelikan explicit_bzero(&kdfinfo2, sizeof(kdfinfo2)); 1125c6446370Sjsing 1126d313c28bSjsing if (rv) 1127d313c28bSjsing err(1, "BIOCDISCIPLINE"); 1128d313c28bSjsing 1129d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1130c6446370Sjsing } 1131c6446370Sjsing 113203b2dfbfShenning #define BIOCTL_VIS_NBUF 4 113303b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 113403b2dfbfShenning 113503b2dfbfShenning char * 113603b2dfbfShenning bio_vis(char *s) 113703b2dfbfShenning { 113803b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 113903b2dfbfShenning static uint idx = 0; 114003b2dfbfShenning char *buf; 114103b2dfbfShenning 114203b2dfbfShenning buf = rbuf[idx++]; 114303b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 114403b2dfbfShenning idx = 0; 114503b2dfbfShenning 114603b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 114703b2dfbfShenning return (buf); 114803b2dfbfShenning } 114903b2dfbfShenning 115003b2dfbfShenning void 115103b2dfbfShenning bio_diskinq(char *sd_dev) 115203b2dfbfShenning { 115303b2dfbfShenning struct dk_inquiry di; 115403b2dfbfShenning 1155da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 1156da3b0664Shenning err(1, "DIOCINQ"); 115703b2dfbfShenning 115803b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 115903b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 116003b2dfbfShenning } 1161aef7fe28Shshoexer 1162aef7fe28Shshoexer void 1163d865b7d2Suebayasi bio_patrol(char *arg) 1164d865b7d2Suebayasi { 1165d865b7d2Suebayasi struct bioc_patrol bp; 1166d865b7d2Suebayasi struct timing timing; 1167d865b7d2Suebayasi const char *errstr; 1168d865b7d2Suebayasi 1169d865b7d2Suebayasi memset(&bp, 0, sizeof(bp)); 1170d865b7d2Suebayasi bp.bp_bio.bio_cookie = bio_cookie; 1171d865b7d2Suebayasi 1172d865b7d2Suebayasi switch (arg[0]) { 1173d865b7d2Suebayasi case 'a': 1174d865b7d2Suebayasi bp.bp_opcode = BIOC_SPAUTO; 1175d865b7d2Suebayasi break; 1176d865b7d2Suebayasi 1177d865b7d2Suebayasi case 'm': 1178d865b7d2Suebayasi bp.bp_opcode = BIOC_SPMANUAL; 1179d865b7d2Suebayasi break; 1180d865b7d2Suebayasi 1181d865b7d2Suebayasi case 'd': 1182d865b7d2Suebayasi bp.bp_opcode = BIOC_SPDISABLE; 1183d865b7d2Suebayasi break; 1184d865b7d2Suebayasi 1185d865b7d2Suebayasi case 'g': /* get patrol state */ 1186d865b7d2Suebayasi bp.bp_opcode = BIOC_GPSTATUS; 1187d865b7d2Suebayasi break; 1188d865b7d2Suebayasi 1189d865b7d2Suebayasi case 's': /* start/stop patrol */ 1190d865b7d2Suebayasi if (strncmp("sta", arg, 3) == 0) 1191d865b7d2Suebayasi bp.bp_opcode = BIOC_SPSTART; 1192d865b7d2Suebayasi else 1193d865b7d2Suebayasi bp.bp_opcode = BIOC_SPSTOP; 1194d865b7d2Suebayasi break; 1195d865b7d2Suebayasi 1196d865b7d2Suebayasi default: 1197d865b7d2Suebayasi errx(1, "invalid patrol function: %s", arg); 1198d865b7d2Suebayasi } 1199d865b7d2Suebayasi 1200d865b7d2Suebayasi switch (arg[0]) { 1201d865b7d2Suebayasi case 'a': 1202d865b7d2Suebayasi errstr = str2patrol(arg, &timing); 1203d865b7d2Suebayasi if (errstr) 1204d865b7d2Suebayasi errx(1, "Patrol %s: %s", arg, errstr); 1205d865b7d2Suebayasi bp.bp_autoival = timing.interval; 1206d865b7d2Suebayasi bp.bp_autonext = timing.start; 1207d865b7d2Suebayasi break; 1208d865b7d2Suebayasi } 1209d865b7d2Suebayasi 1210d865b7d2Suebayasi if (ioctl(devh, BIOCPATROL, &bp)) 1211d865b7d2Suebayasi err(1, "BIOCPATROL"); 1212d865b7d2Suebayasi 1213d865b7d2Suebayasi bio_status(&bp.bp_bio.bio_status); 1214d865b7d2Suebayasi 1215d865b7d2Suebayasi if (arg[0] == 'g') { 1216d865b7d2Suebayasi const char *mode, *status; 1217d865b7d2Suebayasi char interval[40]; 1218d865b7d2Suebayasi 1219d865b7d2Suebayasi interval[0] = '\0'; 1220d865b7d2Suebayasi 1221d865b7d2Suebayasi switch (bp.bp_mode) { 1222d865b7d2Suebayasi case BIOC_SPMAUTO: 1223d865b7d2Suebayasi mode = "auto"; 1224d865b7d2Suebayasi snprintf(interval, sizeof interval, 1225d865b7d2Suebayasi " interval=%d next=%d", bp.bp_autoival, 1226d865b7d2Suebayasi bp.bp_autonext - bp.bp_autonow); 1227d865b7d2Suebayasi break; 1228d865b7d2Suebayasi case BIOC_SPMMANUAL: 1229d865b7d2Suebayasi mode = "manual"; 1230d865b7d2Suebayasi break; 1231d865b7d2Suebayasi case BIOC_SPMDISABLED: 1232d865b7d2Suebayasi mode = "disabled"; 1233d865b7d2Suebayasi break; 1234d865b7d2Suebayasi default: 12352ad5ec6fSuebayasi mode = "unknown"; 1236d865b7d2Suebayasi break; 1237d865b7d2Suebayasi } 1238d865b7d2Suebayasi switch (bp.bp_status) { 1239d865b7d2Suebayasi case BIOC_SPSSTOPPED: 1240d865b7d2Suebayasi status = "stopped"; 1241d865b7d2Suebayasi break; 1242d865b7d2Suebayasi case BIOC_SPSREADY: 1243d865b7d2Suebayasi status = "ready"; 1244d865b7d2Suebayasi break; 1245d865b7d2Suebayasi case BIOC_SPSACTIVE: 1246d865b7d2Suebayasi status = "active"; 1247d865b7d2Suebayasi break; 1248d865b7d2Suebayasi case BIOC_SPSABORTED: 1249d865b7d2Suebayasi status = "aborted"; 1250d865b7d2Suebayasi break; 1251d865b7d2Suebayasi default: 1252d865b7d2Suebayasi status = "unknown"; 1253d865b7d2Suebayasi break; 1254d865b7d2Suebayasi } 1255d865b7d2Suebayasi printf("patrol mode: %s%s\n", mode, interval); 1256d865b7d2Suebayasi printf("patrol status: %s\n", status); 1257d865b7d2Suebayasi } 1258d865b7d2Suebayasi } 1259d865b7d2Suebayasi 1260d865b7d2Suebayasi void 1261*61f93244Sjsing derive_key_pkcs(u_int32_t type, int rounds, u_int8_t *key, size_t keysz, 1262*61f93244Sjsing u_int8_t *salt, size_t saltsz, char *prompt, int verify) 1263aef7fe28Shshoexer { 126486735da2Smarco FILE *f; 126586735da2Smarco size_t pl; 126686735da2Smarco struct stat sb; 12679e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 1268aef7fe28Shshoexer 1269aef7fe28Shshoexer if (!key) 1270aef7fe28Shshoexer errx(1, "Invalid key"); 1271aef7fe28Shshoexer if (!salt) 1272aef7fe28Shshoexer errx(1, "Invalid salt"); 1273*61f93244Sjsing 1274*61f93244Sjsing if (type != SR_CRYPTOKDFT_PBKDF2) 1275*61f93244Sjsing errx(1, "unknown KDF type %d", type); 1276aef7fe28Shshoexer if (rounds < 1000) 1277*61f93244Sjsing errx(1, "number of KDF rounds is too small: %d", rounds); 1278aef7fe28Shshoexer 1279aef7fe28Shshoexer /* get passphrase */ 1280ba3d8661Smarco if (password) { 128186735da2Smarco if ((f = fopen(password, "r")) == NULL) 128286735da2Smarco err(1, "invalid passphrase file"); 128386735da2Smarco 128486735da2Smarco if (fstat(fileno(f), &sb) == -1) 128586735da2Smarco err(1, "can't stat passphrase file"); 128686735da2Smarco if (sb.st_uid != 0) 128786735da2Smarco errx(1, "passphrase file must be owned by root"); 128886735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 128986735da2Smarco errx(1, "passphrase file has the wrong permissions"); 129086735da2Smarco 129186735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 129286735da2Smarco err(1, "can't read passphrase file"); 129386735da2Smarco pl = strlen(passphrase); 129486735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 129586735da2Smarco passphrase[pl - 1] = '\0'; 129686735da2Smarco else 129786735da2Smarco errx(1, "invalid passphrase length"); 129886735da2Smarco 129986735da2Smarco fclose(f); 1300ba3d8661Smarco } else { 1301c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1302b96c6ce2Sckuethe rpp_flag) == NULL) 13037eef0726Stedu err(1, "unable to read passphrase"); 1304ba3d8661Smarco } 13059e8c6f5bShshoexer 13064c688d0dShalex if (verify && !password) { 13079e8c6f5bShshoexer /* request user to re-type it */ 13089e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 1309b96c6ce2Sckuethe sizeof(verifybuf), rpp_flag) == NULL) { 13100a488504Spelikan explicit_bzero(passphrase, sizeof(passphrase)); 13117eef0726Stedu err(1, "unable to read passphrase"); 13129e8c6f5bShshoexer } 13139e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 13149e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 13150a488504Spelikan explicit_bzero(passphrase, sizeof(passphrase)); 13160a488504Spelikan explicit_bzero(verifybuf, sizeof(verifybuf)); 13179e8c6f5bShshoexer errx(1, "Passphrases did not match"); 13189e8c6f5bShshoexer } 13199e8c6f5bShshoexer /* forget the re-typed one */ 13200a488504Spelikan explicit_bzero(verifybuf, sizeof(verifybuf)); 13219e8c6f5bShshoexer } 1322aef7fe28Shshoexer 1323aef7fe28Shshoexer /* derive key from passphrase */ 13245c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 13255c1f8f6bSdjm key, keysz, rounds) != 0) 13265c1f8f6bSdjm errx(1, "pbkdf2 failed"); 1327aef7fe28Shshoexer 1328aef7fe28Shshoexer /* forget passphrase */ 13290a488504Spelikan explicit_bzero(passphrase, sizeof(passphrase)); 1330aef7fe28Shshoexer 1331aef7fe28Shshoexer return; 1332aef7fe28Shshoexer } 1333