1*4bfefca2Skn /* $OpenBSD: bioctl.c,v 1.153 2023/08/21 08:13:37 kn 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> 45ef0eb24eSjsing #include <time.h> 46db2730c1Smarco #include <unistd.h> 47b9fc9a72Sderaadt #include <limits.h> 4803b2dfbfShenning #include <vis.h> 499e8c6f5bShshoexer #include <readpassphrase.h> 50db2730c1Smarco 516de960dcSmarco struct locator { 526de960dcSmarco int channel; 536de960dcSmarco int target; 546de960dcSmarco int lun; 556de960dcSmarco }; 566de960dcSmarco 57d865b7d2Suebayasi struct timing { 58d865b7d2Suebayasi int interval; 59d865b7d2Suebayasi int start; 60d865b7d2Suebayasi }; 61d865b7d2Suebayasi 621f610680Stb static void __dead usage(void); 6341eccc89Sderaadt const char *str2locator(const char *, struct locator *); 64d865b7d2Suebayasi const char *str2patrol(const char *, struct timing *); 65d313c28bSjsing void bio_status(struct bio_status *); 6646bc198bSmarco int bio_parse_devlist(char *, dev_t *); 67aef7fe28Shshoexer void bio_kdf_derive(struct sr_crypto_kdfinfo *, 683487a6b1Sjsing struct sr_crypto_pbkdf *, char *, int); 69aef7fe28Shshoexer void bio_kdf_generate(struct sr_crypto_kdfinfo *); 70ef0eb24eSjsing int bcrypt_pbkdf_autorounds(void); 713487a6b1Sjsing void derive_key(u_int32_t, int, u_int8_t *, size_t, 7261f93244Sjsing u_int8_t *, 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 *); 86d865b7d2Suebayasi void bio_patrol(char *); 873af9de98Smarco 883af9de98Smarco int devh = -1; 89abe9d68eSderaadt int human; 90abe9d68eSderaadt int verbose; 91e8a57fdeSmarco u_int32_t cflags = 0; 921f1fa78aSjsing int rflag = 0; 9386735da2Smarco char *password; 943af9de98Smarco 95545c4d7fSjsing void *bio_cookie; 96545c4d7fSjsing 975f219970Skn int interactive = 1; 983af9de98Smarco 993af9de98Smarco int 1003af9de98Smarco main(int argc, char *argv[]) 1013af9de98Smarco { 102545c4d7fSjsing struct bio_locate bl; 103db2730c1Smarco u_int64_t func = 0; 104e63d8b1dSdtucker char *devicename = NULL; 105cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 1067195049bSmarco char *bl_arg = NULL, *dev_list = NULL; 1070054cd36Sjsing char *key_disk = NULL; 108aedd4f07Sdjm const char *errstr; 109d313c28bSjsing int ch, blink = 0, changepass = 0, diskinq = 0; 110c6446370Sjsing int ss_func = 0; 1119ecba717Sderaadt u_int16_t cr_level = 0; 112e37c64dbSjsing int biodev = 0; 1133af9de98Smarco 1143af9de98Smarco if (argc < 2) 1153af9de98Smarco usage(); 1163af9de98Smarco 117d865b7d2Suebayasi while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:O:Pp:qr:R:st:u:v")) != 118c6446370Sjsing -1) { 1193af9de98Smarco switch (ch) { 120edfd9792Smarco case 'a': /* alarm */ 121edfd9792Smarco func |= BIOC_ALARM; 122edfd9792Smarco al_arg = optarg; 123edfd9792Smarco break; 124c55617f1Sdlg case 'b': /* blink */ 125c55617f1Sdlg func |= BIOC_BLINK; 126a928c459Sderaadt blink = BIOC_SBBLINK; 127a928c459Sderaadt bl_arg = optarg; 128a928c459Sderaadt break; 129e8a57fdeSmarco case 'C': /* creation flags */ 130e8a57fdeSmarco cflags = bio_createflags(optarg); 131e8a57fdeSmarco break; 1327195049bSmarco case 'c': /* create */ 1337195049bSmarco func |= BIOC_CREATERAID; 13401de20b5Sstsp if (strcmp(optarg, "1C") == 0) { 13501de20b5Sstsp cr_level = 0x1C; 13601de20b5Sstsp } else if (isdigit((unsigned char)*optarg)) { 13792d21b5cStedu cr_level = strtonum(optarg, 0, 10, &errstr); 13892d21b5cStedu if (errstr != NULL) 13992d21b5cStedu errx(1, "Invalid RAID level"); 14024b6f6bcSkn } else if (strlen(optarg) == 1) { 14198b750e4Stedu cr_level = *optarg; 14224b6f6bcSkn } else { 14324b6f6bcSkn errx(1, "Invalid RAID level"); 14424b6f6bcSkn } 1457195049bSmarco break; 146c7c3e8aaSmarco case 'd': 147c7c3e8aaSmarco /* delete volume */ 148c7c3e8aaSmarco func |= BIOC_DELETERAID; 149c7c3e8aaSmarco break; 150a928c459Sderaadt case 'u': /* unblink */ 151a928c459Sderaadt func |= BIOC_BLINK; 152a928c459Sderaadt blink = BIOC_SBUNBLINK; 153c55617f1Sdlg bl_arg = optarg; 154c55617f1Sdlg break; 1556de960dcSmarco case 'H': /* set hotspare */ 1566de960dcSmarco func |= BIOC_SETSTATE; 157a15048bbSmarco ss_func = BIOC_SSHOTSPARE; 1586de960dcSmarco al_arg = optarg; 1596de960dcSmarco break; 1608ccdd032Sderaadt case 'h': 1618ccdd032Sderaadt human = 1; 1628ccdd032Sderaadt break; 163db2730c1Smarco case 'i': /* inquiry */ 164db2730c1Smarco func |= BIOC_INQ; 1653af9de98Smarco break; 1660054cd36Sjsing case 'k': /* Key disk. */ 1670054cd36Sjsing key_disk = optarg; 1680054cd36Sjsing break; 1697195049bSmarco case 'l': /* device list */ 1707195049bSmarco func |= BIOC_DEVLIST; 1717195049bSmarco dev_list = optarg; 1727195049bSmarco break; 173c6446370Sjsing case 'P': 174c6446370Sjsing /* Change passphrase. */ 175c6446370Sjsing changepass = 1; 176c6446370Sjsing break; 17786735da2Smarco case 'p': 17886735da2Smarco password = optarg; 17986735da2Smarco break; 180aedd4f07Sdjm case 'r': 181ef0eb24eSjsing if (strcmp(optarg, "auto") == 0) { 182ef0eb24eSjsing rflag = -1; 183ef0eb24eSjsing break; 184ef0eb24eSjsing } 1852ba69c71Sjsing rflag = strtonum(optarg, 4, 1<<30, &errstr); 186aedd4f07Sdjm if (errstr != NULL) 18761f93244Sjsing errx(1, "number of KDF rounds is %s: %s", 188aedd4f07Sdjm errstr, optarg); 189aedd4f07Sdjm break; 19050e55a42Sjsing case 'O': 19150e55a42Sjsing /* set a chunk to offline */ 19250e55a42Sjsing func |= BIOC_SETSTATE; 19350e55a42Sjsing ss_func = BIOC_SSOFFLINE; 19450e55a42Sjsing al_arg = optarg; 19550e55a42Sjsing break; 196a15048bbSmarco case 'R': 197a15048bbSmarco /* rebuild to provided chunk/CTL */ 198a15048bbSmarco func |= BIOC_SETSTATE; 199a15048bbSmarco ss_func = BIOC_SSREBUILD; 200a15048bbSmarco al_arg = optarg; 201a15048bbSmarco break; 202b96c6ce2Sckuethe case 's': 2035f219970Skn interactive = 0; 204b96c6ce2Sckuethe break; 205d865b7d2Suebayasi case 't': /* patrol */ 206d865b7d2Suebayasi func |= BIOC_PATROL; 207d865b7d2Suebayasi al_arg = optarg; 208d865b7d2Suebayasi break; 209abe9d68eSderaadt case 'v': 210abe9d68eSderaadt verbose = 1; 211abe9d68eSderaadt break; 21203b2dfbfShenning case 'q': 21303b2dfbfShenning diskinq = 1; 21403b2dfbfShenning break; 2153af9de98Smarco default: 2163af9de98Smarco usage(); 2173af9de98Smarco /* NOTREACHED */ 2183af9de98Smarco } 2193af9de98Smarco } 220cf6503d7Sderaadt argc -= optind; 221cf6503d7Sderaadt argv += optind; 2223af9de98Smarco 223c6446370Sjsing if (argc != 1 || (changepass && func != 0)) 224cf6503d7Sderaadt usage(); 225cf6503d7Sderaadt 226dcbaf4c8Sderaadt if (func == 0) 227dcbaf4c8Sderaadt func |= BIOC_INQ; 228dcbaf4c8Sderaadt 229e63d8b1dSdtucker devicename = argv[0]; 230e63d8b1dSdtucker if (devicename == NULL) 231e37c64dbSjsing errx(1, "need device"); 23210b411a7Smarco 233e63d8b1dSdtucker devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname); 234e37c64dbSjsing if (devh == -1) { 23541eccc89Sderaadt devh = open("/dev/bio", O_RDWR); 2363af9de98Smarco if (devh == -1) 23741eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 2383af9de98Smarco 239281272dcSpatrick memset(&bl, 0, sizeof(bl)); 240e63d8b1dSdtucker bl.bl_name = devicename; 241df69c215Sderaadt if (ioctl(devh, BIOCLOCATE, &bl) == -1) 24210b411a7Smarco errx(1, "Can't locate %s device via %s", 24341eccc89Sderaadt bl.bl_name, "/dev/bio"); 244d313c28bSjsing 245545c4d7fSjsing bio_cookie = bl.bl_bio.bio_cookie; 246e37c64dbSjsing biodev = 1; 247e63d8b1dSdtucker devicename = NULL; 248e37c64dbSjsing } 2493af9de98Smarco 25003b2dfbfShenning if (diskinq) { 251e63d8b1dSdtucker bio_diskinq(devicename); 252e37c64dbSjsing } else if (changepass && !biodev) { 253e63d8b1dSdtucker bio_changepass(devicename); 25403b2dfbfShenning } else if (func & BIOC_INQ) { 255e63d8b1dSdtucker bio_inq(devicename); 256edfd9792Smarco } else if (func == BIOC_ALARM) { 257edfd9792Smarco bio_alarm(al_arg); 258c55617f1Sdlg } else if (func == BIOC_BLINK) { 259e63d8b1dSdtucker bio_setblink(devicename, bl_arg, blink); 260d865b7d2Suebayasi } else if (func == BIOC_PATROL) { 261d865b7d2Suebayasi bio_patrol(al_arg); 2626de960dcSmarco } else if (func == BIOC_SETSTATE) { 263a15048bbSmarco bio_setstate(al_arg, ss_func, argv[0]); 264e37c64dbSjsing } else if (func == BIOC_DELETERAID && !biodev) { 265e63d8b1dSdtucker bio_deleteraid(devicename); 2667195049bSmarco } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 2677195049bSmarco if (!(func & BIOC_CREATERAID)) 2687195049bSmarco errx(1, "need -c parameter"); 2697195049bSmarco if (!(func & BIOC_DEVLIST)) 2707195049bSmarco errx(1, "need -l parameter"); 271e37c64dbSjsing if (!biodev) 272e37c64dbSjsing errx(1, "must use bio device"); 2730054cd36Sjsing bio_createraid(cr_level, dev_list, key_disk); 2743af9de98Smarco } 2753af9de98Smarco 2763af9de98Smarco return (0); 2773af9de98Smarco } 2783af9de98Smarco 2791f610680Stb static void __dead 2803af9de98Smarco usage(void) 2813af9de98Smarco { 2823af9de98Smarco extern char *__progname; 2833af9de98Smarco 284d90b5d8bSjmc fprintf(stderr, 285d0b772c8Sjmc "usage: %s [-hiqv] [-a alarm-function] " 286d90b5d8bSjmc "[-b channel:target[.lun]]\n" 287d0b772c8Sjmc "\t[-H channel:target[.lun]] " 2881e4c8201Sschwarze "[-R chunk | channel:target[.lun]]\n" 2892e6b119fSjmc "\t[-t patrol-function] " 2902e6b119fSjmc "[-u channel:target[.lun]] " 291d0b772c8Sjmc "device\n" 292b96c6ce2Sckuethe " %s [-dhiPqsv] " 293889853deSkn "[-C flag[,...]] [-c raidlevel] [-k keydisk]\n" 294889853deSkn "\t[-l chunk[,...]] " 29550e55a42Sjsing "[-O device | channel:target[.lun]]\n" 2961e4c8201Sschwarze "\t[-p passfile] [-R chunk | channel:target[.lun]]\n" 2972e6b119fSjmc "\t[-r rounds] " 298d0b772c8Sjmc "device\n", __progname, __progname); 299d90b5d8bSjmc 3003af9de98Smarco exit(1); 3013af9de98Smarco } 3023af9de98Smarco 30341eccc89Sderaadt const char * 3046de960dcSmarco str2locator(const char *string, struct locator *location) 3056de960dcSmarco { 30650d3c4dcSdlg const char *errstr; 30741eccc89Sderaadt char parse[80], *targ, *lun; 3086de960dcSmarco 30941eccc89Sderaadt strlcpy(parse, string, sizeof parse); 31041eccc89Sderaadt targ = strchr(parse, ':'); 3116de960dcSmarco if (targ == NULL) 31241eccc89Sderaadt return ("target not specified"); 3136de960dcSmarco *targ++ = '\0'; 3146de960dcSmarco 31550d3c4dcSdlg lun = strchr(targ, '.'); 3166de960dcSmarco if (lun != NULL) { 3176de960dcSmarco *lun++ = '\0'; 31850d3c4dcSdlg location->lun = strtonum(lun, 0, 256, &errstr); 31950d3c4dcSdlg if (errstr) 32041eccc89Sderaadt return (errstr); 3216de960dcSmarco } else 3226de960dcSmarco location->lun = 0; 3236de960dcSmarco 32450d3c4dcSdlg location->target = strtonum(targ, 0, 256, &errstr); 32550d3c4dcSdlg if (errstr) 32641eccc89Sderaadt return (errstr); 32741eccc89Sderaadt location->channel = strtonum(parse, 0, 256, &errstr); 32850d3c4dcSdlg if (errstr) 32941eccc89Sderaadt return (errstr); 33041eccc89Sderaadt return (NULL); 3316de960dcSmarco } 3326de960dcSmarco 333d865b7d2Suebayasi const char * 334d865b7d2Suebayasi str2patrol(const char *string, struct timing *timing) 335d865b7d2Suebayasi { 336d865b7d2Suebayasi const char *errstr; 337d865b7d2Suebayasi char parse[80], *interval = NULL, *start = NULL; 338d865b7d2Suebayasi 339d865b7d2Suebayasi timing->interval = 0; 340d865b7d2Suebayasi timing->start = 0; 341d865b7d2Suebayasi 342d865b7d2Suebayasi strlcpy(parse, string, sizeof parse); 343d865b7d2Suebayasi 344d865b7d2Suebayasi interval = strchr(parse, '.'); 345d865b7d2Suebayasi if (interval != NULL) { 346d865b7d2Suebayasi *interval++ = '\0'; 347d865b7d2Suebayasi start = strchr(interval, '.'); 348d865b7d2Suebayasi if (start != NULL) 349d865b7d2Suebayasi *start++ = '\0'; 350d865b7d2Suebayasi } 351d865b7d2Suebayasi if (interval != NULL) { 352d865b7d2Suebayasi /* -1 == continuously */ 353d865b7d2Suebayasi timing->interval = strtonum(interval, -1, INT_MAX, &errstr); 354d865b7d2Suebayasi if (errstr) 355d865b7d2Suebayasi return (errstr); 356d865b7d2Suebayasi } 357d865b7d2Suebayasi if (start != NULL) { 358d865b7d2Suebayasi timing->start = strtonum(start, 0, INT_MAX, &errstr); 359d865b7d2Suebayasi if (errstr) 360d865b7d2Suebayasi return (errstr); 361d865b7d2Suebayasi } 362d865b7d2Suebayasi 363d865b7d2Suebayasi return (NULL); 364d865b7d2Suebayasi } 365d865b7d2Suebayasi 3663af9de98Smarco void 367d313c28bSjsing bio_status(struct bio_status *bs) 368d313c28bSjsing { 3690a69bfccSjsing extern char *__progname; 3700a69bfccSjsing char *prefix; 371d313c28bSjsing int i; 372d313c28bSjsing 373d313c28bSjsing if (strlen(bs->bs_controller)) 3740a69bfccSjsing prefix = bs->bs_controller; 3750a69bfccSjsing else 3760a69bfccSjsing prefix = __progname; 377d313c28bSjsing 3780a69bfccSjsing for (i = 0; i < bs->bs_msg_count; i++) 379*4bfefca2Skn fprintf(bs->bs_msgs[i].bm_type == BIO_MSG_INFO ? 380*4bfefca2Skn stdout : stderr, "%s: %s\n", prefix, bs->bs_msgs[i].bm_msg); 3810a69bfccSjsing 3820a69bfccSjsing if (bs->bs_status == BIO_STATUS_ERROR) { 3830a69bfccSjsing if (bs->bs_msg_count == 0) 3840a69bfccSjsing errx(1, "unknown error"); 3850a69bfccSjsing else 386d313c28bSjsing exit(1); 387d313c28bSjsing } 3880a69bfccSjsing } 389d313c28bSjsing 390d313c28bSjsing void 3918ccdd032Sderaadt bio_inq(char *name) 392d4546a56Sdlg { 393cc711184Skettenis char *status, *cache; 394cc711184Skettenis char size[64], scsiname[16], volname[32]; 395d865b7d2Suebayasi char percent[20], seconds[20]; 396d313c28bSjsing int i, d, volheader, hotspare, unused; 397aa65acf1Sderaadt char encname[16], serial[32]; 3988ccdd032Sderaadt struct bioc_inq bi; 3998ccdd032Sderaadt struct bioc_vol bv; 400c2b1f828Sderaadt struct bioc_disk bd; 401db2730c1Smarco 402db2730c1Smarco memset(&bi, 0, sizeof(bi)); 4033af9de98Smarco 404545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 4053af9de98Smarco 406df69c215Sderaadt if (ioctl(devh, BIOCINQ, &bi) == -1) { 40703b2dfbfShenning if (errno == ENOTTY) 40803b2dfbfShenning bio_diskinq(name); 40903b2dfbfShenning else 410da3b0664Shenning err(1, "BIOCINQ"); 4113af9de98Smarco return; 4123af9de98Smarco } 4133af9de98Smarco 414d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 415d313c28bSjsing 4168ccdd032Sderaadt volheader = 0; 4178ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 418db2730c1Smarco memset(&bv, 0, sizeof(bv)); 419545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 4208ccdd032Sderaadt bv.bv_volid = i; 4210a92ff65Sderaadt bv.bv_percent = -1; 4229017fb97Sderaadt bv.bv_seconds = 0; 42370a2ae7bSmarco 424df69c215Sderaadt if (ioctl(devh, BIOCVOL, &bv) == -1) 425da3b0664Shenning err(1, "BIOCVOL"); 4263af9de98Smarco 427d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 428d313c28bSjsing 4298ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 4308ccdd032Sderaadt continue; 4318ccdd032Sderaadt 4328ccdd032Sderaadt if (!volheader) { 4338ccdd032Sderaadt volheader = 1; 434150c22bbSjcs printf("%-11s %-10s %14s %-8s\n", 4358ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 4368ccdd032Sderaadt } 4378ccdd032Sderaadt 4380a92ff65Sderaadt percent[0] = '\0'; 4399017fb97Sderaadt seconds[0] = '\0'; 4400a92ff65Sderaadt if (bv.bv_percent != -1) 4410a92ff65Sderaadt snprintf(percent, sizeof percent, 4420a92ff65Sderaadt " %d%% done", bv.bv_percent); 4439017fb97Sderaadt if (bv.bv_seconds) 4449017fb97Sderaadt snprintf(seconds, sizeof seconds, 4459017fb97Sderaadt " %u seconds", bv.bv_seconds); 4468ccdd032Sderaadt switch (bv.bv_status) { 447db2730c1Smarco case BIOC_SVONLINE: 4488ccdd032Sderaadt status = BIOC_SVONLINE_S; 449db2730c1Smarco break; 450db2730c1Smarco case BIOC_SVOFFLINE: 4518ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 452db2730c1Smarco break; 453db2730c1Smarco case BIOC_SVDEGRADED: 4548ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 455db2730c1Smarco break; 4560a92ff65Sderaadt case BIOC_SVBUILDING: 4570a92ff65Sderaadt status = BIOC_SVBUILDING_S; 4580a92ff65Sderaadt break; 4590a92ff65Sderaadt case BIOC_SVREBUILD: 4600a92ff65Sderaadt status = BIOC_SVREBUILD_S; 4610a92ff65Sderaadt break; 4620a92ff65Sderaadt case BIOC_SVSCRUB: 4630a92ff65Sderaadt status = BIOC_SVSCRUB_S; 4640a92ff65Sderaadt break; 465db2730c1Smarco case BIOC_SVINVALID: 466db2730c1Smarco default: 4678ccdd032Sderaadt status = BIOC_SVINVALID_S; 468d4546a56Sdlg } 469cc711184Skettenis switch (bv.bv_cache) { 470cc711184Skettenis case BIOC_CVWRITEBACK: 471cc711184Skettenis cache = BIOC_CVWRITEBACK_S; 472cc711184Skettenis break; 473cc711184Skettenis case BIOC_CVWRITETHROUGH: 474cc711184Skettenis cache = BIOC_CVWRITETHROUGH_S; 475cc711184Skettenis break; 476cc711184Skettenis case BIOC_CVUNKNOWN: 477cc711184Skettenis default: 478cc711184Skettenis cache = BIOC_CVUNKNOWN_S; 479cc711184Skettenis } 4803af9de98Smarco 481aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 4828ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 483b9950701Smarco 4849ecba717Sderaadt unused = 0; 4859ecba717Sderaadt hotspare = 0; 486aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 487aa65acf1Sderaadt hotspare = 1; 488b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 489b9950701Smarco unused = 1; 490aa65acf1Sderaadt else { 4918ccdd032Sderaadt if (human) 4928ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 4938ccdd032Sderaadt else 4948ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 4958ccdd032Sderaadt bv.bv_size); 496d5e6461fSkn printf("%11s %-10s %14s %-7s ", 497d5e6461fSkn volname, status, size, bv.bv_dev); 498da935596Stodd switch (bv.bv_level) { 499da935596Stodd case 'C': 500d5e6461fSkn printf("CRYPTO%s%s\n", 501da935596Stodd percent, seconds); 502da935596Stodd break; 5032b5fc845Sjsing case 'c': 504d5e6461fSkn printf("CONCAT%s%s\n", 5052b5fc845Sjsing percent, seconds); 5062b5fc845Sjsing break; 50701de20b5Sstsp case 0x1C: 50833c65cd8Skn case 0x1E: 509d5e6461fSkn printf("RAID%X%s%s %s\n", 51001de20b5Sstsp bv.bv_level, percent, seconds, cache); 51101de20b5Sstsp break; 512da935596Stodd default: 513d5e6461fSkn printf("RAID%u%s%s %s\n", 514cc711184Skettenis bv.bv_level, percent, seconds, cache); 515da935596Stodd break; 516da935596Stodd } 517da935596Stodd 518aa65acf1Sderaadt } 5198ccdd032Sderaadt 5208ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 521db2730c1Smarco memset(&bd, 0, sizeof(bd)); 522545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 5238ccdd032Sderaadt bd.bd_diskid = d; 5248ccdd032Sderaadt bd.bd_volid = i; 525d865b7d2Suebayasi bd.bd_patrol.bdp_percent = -1; 526d865b7d2Suebayasi bd.bd_patrol.bdp_seconds = 0; 5273af9de98Smarco 528df69c215Sderaadt if (ioctl(devh, BIOCDISK, &bd) == -1) 529da3b0664Shenning err(1, "BIOCDISK"); 5303af9de98Smarco 531d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 532d313c28bSjsing 5338ccdd032Sderaadt switch (bd.bd_status) { 534db2730c1Smarco case BIOC_SDONLINE: 5358ccdd032Sderaadt status = BIOC_SDONLINE_S; 536d4546a56Sdlg break; 537db2730c1Smarco case BIOC_SDOFFLINE: 5388ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 539d4546a56Sdlg break; 540db2730c1Smarco case BIOC_SDFAILED: 5418ccdd032Sderaadt status = BIOC_SDFAILED_S; 542db2730c1Smarco break; 543db2730c1Smarco case BIOC_SDREBUILD: 5448ccdd032Sderaadt status = BIOC_SDREBUILD_S; 545db2730c1Smarco break; 546db2730c1Smarco case BIOC_SDHOTSPARE: 5478ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 548db2730c1Smarco break; 549db2730c1Smarco case BIOC_SDUNUSED: 5508ccdd032Sderaadt status = BIOC_SDUNUSED_S; 551db2730c1Smarco break; 552e1dfb373Sderaadt case BIOC_SDSCRUB: 553e1dfb373Sderaadt status = BIOC_SDSCRUB_S; 554e1dfb373Sderaadt break; 555db2730c1Smarco case BIOC_SDINVALID: 556d4546a56Sdlg default: 5578ccdd032Sderaadt status = BIOC_SDINVALID_S; 558d4546a56Sdlg } 559aa65acf1Sderaadt 560b9950701Smarco if (hotspare || unused) 561aa65acf1Sderaadt ; /* use volname from parent volume */ 562aa65acf1Sderaadt else 563aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 564aa65acf1Sderaadt bd.bd_diskid); 565aa65acf1Sderaadt 5660054cd36Sjsing if (bv.bv_level == 'C' && bd.bd_size == 0) 5670054cd36Sjsing snprintf(size, sizeof size, "%14s", "key disk"); 5680054cd36Sjsing else if (human) 5698ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 5708ccdd032Sderaadt else 5718ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 5728ccdd032Sderaadt bd.bd_size); 5738ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 57443d61178Sderaadt "%u:%u.%u", 57543d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 5765978b28dSderaadt if (bd.bd_procdev[0]) 577abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 5785978b28dSderaadt else 579abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 580abe9d68eSderaadt if (bd.bd_serial[0]) 581abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 582abe9d68eSderaadt else 583abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 5848ccdd032Sderaadt 585d865b7d2Suebayasi percent[0] = '\0'; 586d865b7d2Suebayasi seconds[0] = '\0'; 587d865b7d2Suebayasi if (bd.bd_patrol.bdp_percent != -1) 588d865b7d2Suebayasi snprintf(percent, sizeof percent, 589d865b7d2Suebayasi " patrol %d%% done", bd.bd_patrol.bdp_percent); 590d865b7d2Suebayasi if (bd.bd_patrol.bdp_seconds) 591d865b7d2Suebayasi snprintf(seconds, sizeof seconds, 592d865b7d2Suebayasi " %u seconds", bd.bd_patrol.bdp_seconds); 593d865b7d2Suebayasi 594150c22bbSjcs printf("%11s %-10s %14s %-7s %-6s <%s>\n", 595aa65acf1Sderaadt volname, status, size, scsiname, encname, 5968ccdd032Sderaadt bd.bd_vendor); 597abe9d68eSderaadt if (verbose) 598d865b7d2Suebayasi printf("%11s %-10s %14s %-7s %-6s '%s'%s%s\n", 599d865b7d2Suebayasi "", "", "", "", "", serial, percent, seconds); 600d4546a56Sdlg } 601d4546a56Sdlg } 602d4546a56Sdlg } 603edfd9792Smarco 604edfd9792Smarco void 605edfd9792Smarco bio_alarm(char *arg) 606edfd9792Smarco { 6078ccdd032Sderaadt struct bioc_alarm ba; 608edfd9792Smarco 609c2b1f828Sderaadt memset(&ba, 0, sizeof(ba)); 610545c4d7fSjsing ba.ba_bio.bio_cookie = bio_cookie; 611edfd9792Smarco 612edfd9792Smarco switch (arg[0]) { 613edfd9792Smarco case 'q': /* silence alarm */ 614edfd9792Smarco /* FALLTHROUGH */ 615edfd9792Smarco case 's': 6168ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 617edfd9792Smarco break; 618edfd9792Smarco 619edfd9792Smarco case 'e': /* enable alarm */ 6208ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 621edfd9792Smarco break; 622edfd9792Smarco 623edfd9792Smarco case 'd': /* disable alarm */ 6248ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 625edfd9792Smarco break; 626edfd9792Smarco 627edfd9792Smarco case 't': /* test alarm */ 6288ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 629edfd9792Smarco break; 630edfd9792Smarco 631edfd9792Smarco case 'g': /* get alarm state */ 6328ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 633edfd9792Smarco break; 634edfd9792Smarco 635edfd9792Smarco default: 636da3b0664Shenning errx(1, "invalid alarm function: %s", arg); 637edfd9792Smarco } 638edfd9792Smarco 639df69c215Sderaadt if (ioctl(devh, BIOCALARM, &ba) == -1) 640da3b0664Shenning err(1, "BIOCALARM"); 641edfd9792Smarco 642d313c28bSjsing bio_status(&ba.ba_bio.bio_status); 643d313c28bSjsing 644d313c28bSjsing if (arg[0] == 'g') 645edfd9792Smarco printf("alarm is currently %s\n", 6468ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 647edfd9792Smarco } 6486de960dcSmarco 649a15048bbSmarco int 650a15048bbSmarco bio_getvolbyname(char *name) 651a15048bbSmarco { 652d313c28bSjsing int id = -1, i; 653a15048bbSmarco struct bioc_inq bi; 654a15048bbSmarco struct bioc_vol bv; 655a15048bbSmarco 656a15048bbSmarco memset(&bi, 0, sizeof(bi)); 657545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 658df69c215Sderaadt if (ioctl(devh, BIOCINQ, &bi) == -1) 659a15048bbSmarco err(1, "BIOCINQ"); 660a15048bbSmarco 661d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 662d313c28bSjsing 663a15048bbSmarco for (i = 0; i < bi.bi_novol; i++) { 664a15048bbSmarco memset(&bv, 0, sizeof(bv)); 665545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 666a15048bbSmarco bv.bv_volid = i; 667df69c215Sderaadt if (ioctl(devh, BIOCVOL, &bv) == -1) 668a15048bbSmarco err(1, "BIOCVOL"); 669a15048bbSmarco 670d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 671d313c28bSjsing 672a15048bbSmarco if (name && strcmp(name, bv.bv_dev) != 0) 673a15048bbSmarco continue; 674a15048bbSmarco id = i; 675a15048bbSmarco break; 676a15048bbSmarco } 677a15048bbSmarco 678a15048bbSmarco return (id); 679a15048bbSmarco } 680a15048bbSmarco 681ebaf584eSderaadt void 6828d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename) 6836de960dcSmarco { 6846de960dcSmarco struct bioc_setstate bs; 6856de960dcSmarco struct locator location; 686a15048bbSmarco struct stat sb; 68741eccc89Sderaadt const char *errstr; 6886de960dcSmarco 689a15048bbSmarco memset(&bs, 0, sizeof(bs)); 690a15048bbSmarco if (stat(arg, &sb) == -1) { 691a15048bbSmarco /* use CTL */ 69241eccc89Sderaadt errstr = str2locator(arg, &location); 69341eccc89Sderaadt if (errstr) 69441eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 6956de960dcSmarco bs.bs_channel = location.channel; 6966de960dcSmarco bs.bs_target = location.target; 6976de960dcSmarco bs.bs_lun = location.lun; 698a15048bbSmarco } else { 699a15048bbSmarco /* use other id */ 700a15048bbSmarco bs.bs_other_id = sb.st_rdev; 701a15048bbSmarco bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 702a15048bbSmarco } 703a15048bbSmarco 704545c4d7fSjsing bs.bs_bio.bio_cookie = bio_cookie; 705a15048bbSmarco bs.bs_status = status; 706a15048bbSmarco 707d2647ac1Sjsing if (status != BIOC_SSHOTSPARE) { 708a15048bbSmarco /* make sure user supplied a sd device */ 7098d8693a2Sdtucker bs.bs_volid = bio_getvolbyname(devicename); 710a15048bbSmarco if (bs.bs_volid == -1) 7118d8693a2Sdtucker errx(1, "invalid device %s", devicename); 712d2647ac1Sjsing } 7136de960dcSmarco 714df69c215Sderaadt if (ioctl(devh, BIOCSETSTATE, &bs) == -1) 715da3b0664Shenning err(1, "BIOCSETSTATE"); 716d313c28bSjsing 717d313c28bSjsing bio_status(&bs.bs_bio.bio_status); 7186de960dcSmarco } 719c55617f1Sdlg 720c55617f1Sdlg void 721a928c459Sderaadt bio_setblink(char *name, char *arg, int blink) 722c55617f1Sdlg { 72350d3c4dcSdlg struct locator location; 724c2b1f828Sderaadt struct bioc_blink bb; 72550d3c4dcSdlg struct bioc_inq bi; 72650d3c4dcSdlg struct bioc_vol bv; 72750d3c4dcSdlg struct bioc_disk bd; 72841eccc89Sderaadt const char *errstr; 72950d3c4dcSdlg int v, d, rv; 730c55617f1Sdlg 73141eccc89Sderaadt errstr = str2locator(arg, &location); 73241eccc89Sderaadt if (errstr) 73341eccc89Sderaadt errx(1, "Target %s: %s", arg, errstr); 73450d3c4dcSdlg 7350505205bSdlg /* try setting blink on the device directly */ 7360505205bSdlg memset(&bb, 0, sizeof(bb)); 737545c4d7fSjsing bb.bb_bio.bio_cookie = bio_cookie; 7380505205bSdlg bb.bb_status = blink; 7390505205bSdlg bb.bb_target = location.target; 740649724a4Smarco bb.bb_channel = location.channel; 7410505205bSdlg rv = ioctl(devh, BIOCBLINK, &bb); 742d313c28bSjsing 743d313c28bSjsing if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_UNKNOWN) 7440505205bSdlg return; 7450505205bSdlg 746d313c28bSjsing if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_SUCCESS) { 747d313c28bSjsing bio_status(&bb.bb_bio.bio_status); 748d313c28bSjsing return; 749d313c28bSjsing } 750d313c28bSjsing 751855d4e83Ssobrado /* if the blink didn't work, try to find something that will */ 7520505205bSdlg 75350d3c4dcSdlg memset(&bi, 0, sizeof(bi)); 754545c4d7fSjsing bi.bi_bio.bio_cookie = bio_cookie; 755df69c215Sderaadt if (ioctl(devh, BIOCINQ, &bi) == -1) 756da3b0664Shenning err(1, "BIOCINQ"); 75750d3c4dcSdlg 758d313c28bSjsing bio_status(&bi.bi_bio.bio_status); 759d313c28bSjsing 76050d3c4dcSdlg for (v = 0; v < bi.bi_novol; v++) { 76150d3c4dcSdlg memset(&bv, 0, sizeof(bv)); 762545c4d7fSjsing bv.bv_bio.bio_cookie = bio_cookie; 76350d3c4dcSdlg bv.bv_volid = v; 764df69c215Sderaadt if (ioctl(devh, BIOCVOL, &bv) == -1) 765da3b0664Shenning err(1, "BIOCVOL"); 76650d3c4dcSdlg 767d313c28bSjsing bio_status(&bv.bv_bio.bio_status); 768d313c28bSjsing 76950d3c4dcSdlg if (name && strcmp(name, bv.bv_dev) != 0) 77050d3c4dcSdlg continue; 77150d3c4dcSdlg 77250d3c4dcSdlg for (d = 0; d < bv.bv_nodisk; d++) { 77350d3c4dcSdlg memset(&bd, 0, sizeof(bd)); 774545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 77550d3c4dcSdlg bd.bd_volid = v; 77650d3c4dcSdlg bd.bd_diskid = d; 77750d3c4dcSdlg 778df69c215Sderaadt if (ioctl(devh, BIOCDISK, &bd) == -1) 779da3b0664Shenning err(1, "BIOCDISK"); 78050d3c4dcSdlg 781d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 782d313c28bSjsing 78350d3c4dcSdlg if (bd.bd_channel == location.channel && 78450d3c4dcSdlg bd.bd_target == location.target && 78550d3c4dcSdlg bd.bd_lun == location.lun) { 786d313c28bSjsing if (bd.bd_procdev[0] != '\0') 78750d3c4dcSdlg bio_blink(bd.bd_procdev, 788a928c459Sderaadt location.target, blink); 789d313c28bSjsing else 790d313c28bSjsing warnx("Disk %s is not in an enclosure", 791d313c28bSjsing arg); 79250d3c4dcSdlg return; 79350d3c4dcSdlg } 79450d3c4dcSdlg } 79550d3c4dcSdlg } 79650d3c4dcSdlg 79741eccc89Sderaadt warnx("Disk %s does not exist", arg); 79850d3c4dcSdlg } 79950d3c4dcSdlg 80050d3c4dcSdlg void 801a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype) 80250d3c4dcSdlg { 80350d3c4dcSdlg int bioh; 804d313c28bSjsing struct bio_locate bl; 80550d3c4dcSdlg struct bioc_blink blink; 80650d3c4dcSdlg 80741eccc89Sderaadt bioh = open("/dev/bio", O_RDWR); 80850d3c4dcSdlg if (bioh == -1) 80941eccc89Sderaadt err(1, "Can't open %s", "/dev/bio"); 81050d3c4dcSdlg 811c2b1f828Sderaadt memset(&bl, 0, sizeof(bl)); 812d313c28bSjsing bl.bl_name = enclosure; 813df69c215Sderaadt if (ioctl(bioh, BIOCLOCATE, &bl) == -1) 81441eccc89Sderaadt errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 815c55617f1Sdlg 816c55617f1Sdlg memset(&blink, 0, sizeof(blink)); 817545c4d7fSjsing blink.bb_bio.bio_cookie = bio_cookie; 818a928c459Sderaadt blink.bb_status = blinktype; 819c55617f1Sdlg blink.bb_target = target; 820c55617f1Sdlg 821df69c215Sderaadt if (ioctl(bioh, BIOCBLINK, &blink) == -1) 822da3b0664Shenning err(1, "BIOCBLINK"); 82350d3c4dcSdlg 824d313c28bSjsing bio_status(&blink.bb_bio.bio_status); 825d313c28bSjsing 82650d3c4dcSdlg close(bioh); 827c55617f1Sdlg } 8287195049bSmarco 8297195049bSmarco void 8300054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk) 8317195049bSmarco { 8327195049bSmarco struct bioc_createraid create; 833aef7fe28Shshoexer struct sr_crypto_kdfinfo kdfinfo; 8343487a6b1Sjsing struct sr_crypto_pbkdf kdfhint; 8350054cd36Sjsing struct stat sb; 8368b0d0f28Sjsing int rv, no_dev, fd; 8377f8eae2bSnicm dev_t *dt; 8387195049bSmarco u_int16_t min_disks = 0; 8397195049bSmarco 8407195049bSmarco if (!dev_list) 8417195049bSmarco errx(1, "no devices specified"); 8427195049bSmarco 843f9b0dfcfStedu dt = calloc(1, BIOC_CRMAXLEN); 84446bc198bSmarco if (!dt) 84546bc198bSmarco err(1, "not enough memory for dev_t list"); 84646bc198bSmarco 84746bc198bSmarco no_dev = bio_parse_devlist(dev_list, dt); 84846bc198bSmarco 8497195049bSmarco switch (level) { 8507195049bSmarco case 0: 85184e48fabSmarco min_disks = 2; 8527195049bSmarco break; 8537195049bSmarco case 1: 8547195049bSmarco min_disks = 2; 8557195049bSmarco break; 856e717853eSmarco case 5: 857e717853eSmarco min_disks = 3; 858e717853eSmarco break; 85984e48fabSmarco case 'C': 86001de20b5Sstsp case 0x1C: 861aef7fe28Shshoexer min_disks = 1; 86284e48fabSmarco break; 86398b750e4Stedu case 'c': 864b346a95bSkrw min_disks = 1; 86598b750e4Stedu break; 8667195049bSmarco default: 86724b6f6bcSkn errx(1, "unsupported RAID level"); 8687195049bSmarco } 8697195049bSmarco 87084e48fabSmarco if (no_dev < min_disks) 87184e48fabSmarco errx(1, "not enough disks"); 87284e48fabSmarco 873aef7fe28Shshoexer /* for crypto raid we only allow one single chunk */ 874aef7fe28Shshoexer if (level == 'C' && no_dev != min_disks) 875818b0595Shalex errx(1, "not exactly one partition"); 876aef7fe28Shshoexer 8777195049bSmarco memset(&create, 0, sizeof(create)); 878545c4d7fSjsing create.bc_bio.bio_cookie = bio_cookie; 8797195049bSmarco create.bc_level = level; 88046bc198bSmarco create.bc_dev_list_len = no_dev * sizeof(dev_t); 88146bc198bSmarco create.bc_dev_list = dt; 882e8a57fdeSmarco create.bc_flags = BIOC_SCDEVT | cflags; 8830054cd36Sjsing create.bc_key_disk = NODEV; 8847195049bSmarco 88501de20b5Sstsp if ((level == 'C' || level == 0x1C) && key_disk == NULL) { 8860054cd36Sjsing 887aef7fe28Shshoexer memset(&kdfinfo, 0, sizeof(kdfinfo)); 888aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 889aef7fe28Shshoexer 8900054cd36Sjsing create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 8910054cd36Sjsing 892aef7fe28Shshoexer create.bc_opaque = &kdfhint; 893aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfhint); 894aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOOUT; 895aef7fe28Shshoexer 896aef7fe28Shshoexer /* try to get KDF hint */ 897df69c215Sderaadt if (ioctl(devh, BIOCCREATERAID, &create) == -1) 89883e979edShshoexer err(1, "ioctl"); 89983e979edShshoexer 900d313c28bSjsing bio_status(&create.bc_bio.bio_status); 901d313c28bSjsing 90283e979edShshoexer if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 903c6446370Sjsing bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0); 904aef7fe28Shshoexer memset(&kdfhint, 0, sizeof(kdfhint)); 905aef7fe28Shshoexer } else { 906aef7fe28Shshoexer bio_kdf_generate(&kdfinfo); 907aef7fe28Shshoexer } 908aef7fe28Shshoexer 909aef7fe28Shshoexer create.bc_opaque = &kdfinfo; 910aef7fe28Shshoexer create.bc_opaque_size = sizeof(kdfinfo); 911aef7fe28Shshoexer create.bc_opaque_flags = BIOC_SOIN; 9120054cd36Sjsing 91301de20b5Sstsp } else if ((level == 'C' || level == 0x1C) && key_disk != NULL) { 9140054cd36Sjsing 9158b0d0f28Sjsing /* Get device number for key disk. */ 9168b0d0f28Sjsing fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL); 9178b0d0f28Sjsing if (fd == -1) 9188b0d0f28Sjsing err(1, "could not open %s", key_disk); 9198b0d0f28Sjsing if (fstat(fd, &sb) == -1) { 920ffb4dd05Sguenther int saved_errno = errno; 9218b0d0f28Sjsing close(fd); 922ffb4dd05Sguenther errc(1, saved_errno, "could not stat %s", key_disk); 9238b0d0f28Sjsing } 9248b0d0f28Sjsing close(fd); 9250054cd36Sjsing create.bc_key_disk = sb.st_rdev; 9260054cd36Sjsing 9270054cd36Sjsing memset(&kdfinfo, 0, sizeof(kdfinfo)); 9280054cd36Sjsing 9290054cd36Sjsing kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf); 9300054cd36Sjsing kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK; 9310054cd36Sjsing kdfinfo.len = sizeof(kdfinfo); 9320054cd36Sjsing kdfinfo.flags = SR_CRYPTOKDF_HINT; 9330054cd36Sjsing 9340054cd36Sjsing create.bc_opaque = &kdfinfo; 9350054cd36Sjsing create.bc_opaque_size = sizeof(kdfinfo); 9360054cd36Sjsing create.bc_opaque_flags = BIOC_SOIN; 9370054cd36Sjsing 938aef7fe28Shshoexer } 939aef7fe28Shshoexer 9407195049bSmarco rv = ioctl(devh, BIOCCREATERAID, &create); 9410a488504Spelikan explicit_bzero(&kdfinfo, sizeof(kdfinfo)); 942d313c28bSjsing if (rv == -1) 943da3b0664Shenning err(1, "BIOCCREATERAID"); 944d313c28bSjsing 945d313c28bSjsing bio_status(&create.bc_bio.bio_status); 94646bc198bSmarco 94746bc198bSmarco free(dt); 94846bc198bSmarco } 94946bc198bSmarco 950aef7fe28Shshoexer void 9513487a6b1Sjsing bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_pbkdf 952c6446370Sjsing *kdfhint, char* prompt, int verify) 953aef7fe28Shshoexer { 954aef7fe28Shshoexer if (!kdfinfo) 955aef7fe28Shshoexer errx(1, "invalid KDF info"); 956aef7fe28Shshoexer if (!kdfhint) 957aef7fe28Shshoexer errx(1, "invalid KDF hint"); 958aef7fe28Shshoexer 9593487a6b1Sjsing if (kdfhint->generic.len != sizeof(*kdfhint)) 960aef7fe28Shshoexer errx(1, "KDF hint has invalid size"); 961aef7fe28Shshoexer 962aef7fe28Shshoexer kdfinfo->flags = SR_CRYPTOKDF_KEY; 963aef7fe28Shshoexer kdfinfo->len = sizeof(*kdfinfo); 964aef7fe28Shshoexer 9653487a6b1Sjsing derive_key(kdfhint->generic.type, kdfhint->rounds, 966aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 96761f93244Sjsing kdfhint->salt, sizeof(kdfhint->salt), 96861f93244Sjsing prompt, verify); 969aef7fe28Shshoexer } 970aef7fe28Shshoexer 971aef7fe28Shshoexer void 972aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 973aef7fe28Shshoexer { 974aef7fe28Shshoexer if (!kdfinfo) 975aef7fe28Shshoexer errx(1, "invalid KDF info"); 976aef7fe28Shshoexer 977ef0eb24eSjsing if (rflag == -1) 978ef0eb24eSjsing rflag = bcrypt_pbkdf_autorounds(); 979ef0eb24eSjsing 9803487a6b1Sjsing kdfinfo->pbkdf.generic.len = sizeof(kdfinfo->pbkdf); 9812ba69c71Sjsing kdfinfo->pbkdf.generic.type = SR_CRYPTOKDFT_BCRYPT_PBKDF; 9822ba69c71Sjsing kdfinfo->pbkdf.rounds = rflag ? rflag : 16; 98361f93244Sjsing 9840054cd36Sjsing kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT; 98561f93244Sjsing kdfinfo->len = sizeof(*kdfinfo); 986aef7fe28Shshoexer 987aef7fe28Shshoexer /* generate salt */ 9883487a6b1Sjsing arc4random_buf(kdfinfo->pbkdf.salt, sizeof(kdfinfo->pbkdf.salt)); 989aef7fe28Shshoexer 9903487a6b1Sjsing derive_key(kdfinfo->pbkdf.generic.type, kdfinfo->pbkdf.rounds, 991aef7fe28Shshoexer kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 9923487a6b1Sjsing kdfinfo->pbkdf.salt, sizeof(kdfinfo->pbkdf.salt), 9935f219970Skn "New passphrase: ", interactive); 994aef7fe28Shshoexer } 995aef7fe28Shshoexer 99646bc198bSmarco int 99746bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt) 99846bc198bSmarco { 99946bc198bSmarco char *s, *e; 100046bc198bSmarco u_int32_t sz = 0; 100146bc198bSmarco int no_dev = 0, i, x; 100246bc198bSmarco struct stat sb; 1003b9fc9a72Sderaadt char dev[PATH_MAX]; 1004e37c64dbSjsing int fd; 100546bc198bSmarco 100646bc198bSmarco if (!lst) 100746bc198bSmarco errx(1, "invalid device list"); 100846bc198bSmarco 100946bc198bSmarco s = e = lst; 101046bc198bSmarco /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 101146bc198bSmarco while (*e != '\0') { 101246bc198bSmarco if (*e == ',') 101346bc198bSmarco s = e + 1; 101446bc198bSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 101546bc198bSmarco /* got one */ 101646bc198bSmarco sz = e - s + 1; 10175c1f8f6bSdjm strlcpy(dev, s, sz + 1); 1018e37c64dbSjsing fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL); 1019e37c64dbSjsing if (fd == -1) 1020e37c64dbSjsing err(1, "could not open %s", dev); 1021e37c64dbSjsing if (fstat(fd, &sb) == -1) { 1022ffb4dd05Sguenther int saved_errno = errno; 1023e37c64dbSjsing close(fd); 1024ffb4dd05Sguenther errc(1, saved_errno, "could not stat %s", dev); 1025e37c64dbSjsing } 1026e37c64dbSjsing close(fd); 102746bc198bSmarco dt[no_dev] = sb.st_rdev; 102846bc198bSmarco no_dev++; 10295c1f8f6bSdjm if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 103046bc198bSmarco errx(1, "too many devices on device list"); 103146bc198bSmarco } 103246bc198bSmarco e++; 103346bc198bSmarco } 103446bc198bSmarco 103546bc198bSmarco for (i = 0; i < no_dev; i++) 103646bc198bSmarco for (x = 0; x < no_dev; x++) 103746bc198bSmarco if (dt[i] == dt[x] && x != i) 103846bc198bSmarco errx(1, "duplicate device in list"); 103946bc198bSmarco 104046bc198bSmarco return (no_dev); 10417195049bSmarco } 1042e8a57fdeSmarco 1043e8a57fdeSmarco u_int32_t 1044e8a57fdeSmarco bio_createflags(char *lst) 1045e8a57fdeSmarco { 1046e8a57fdeSmarco char *s, *e, fs[32]; 1047e8a57fdeSmarco u_int32_t sz = 0; 1048e8a57fdeSmarco u_int32_t flags = 0; 1049e8a57fdeSmarco 1050e8a57fdeSmarco if (!lst) 1051e8a57fdeSmarco errx(1, "invalid flags list"); 1052e8a57fdeSmarco 1053e8a57fdeSmarco s = e = lst; 1054e8a57fdeSmarco /* make sure we have a valid flags list like force,noassemeble */ 1055e8a57fdeSmarco while (*e != '\0') { 1056e8a57fdeSmarco if (*e == ',') 1057e8a57fdeSmarco s = e + 1; 1058e8a57fdeSmarco else if (*(e + 1) == '\0' || *(e + 1) == ',') { 1059e8a57fdeSmarco /* got one */ 1060e8a57fdeSmarco sz = e - s + 1; 1061e8a57fdeSmarco switch (s[0]) { 1062e8a57fdeSmarco case 'f': 1063e8a57fdeSmarco flags |= BIOC_SCFORCE; 1064e8a57fdeSmarco break; 1065e8a57fdeSmarco case 'n': 1066e8a57fdeSmarco flags |= BIOC_SCNOAUTOASSEMBLE; 1067e8a57fdeSmarco break; 1068e8a57fdeSmarco default: 1069e8a57fdeSmarco strlcpy(fs, s, sz + 1); 1070e8a57fdeSmarco errx(1, "invalid flag %s", fs); 1071e8a57fdeSmarco } 1072e8a57fdeSmarco } 1073e8a57fdeSmarco e++; 1074e8a57fdeSmarco } 1075e8a57fdeSmarco 1076e8a57fdeSmarco return (flags); 1077e8a57fdeSmarco } 107803b2dfbfShenning 1079c7c3e8aaSmarco void 1080c7c3e8aaSmarco bio_deleteraid(char *dev) 1081c7c3e8aaSmarco { 1082c7c3e8aaSmarco struct bioc_deleteraid bd; 1083c7c3e8aaSmarco memset(&bd, 0, sizeof(bd)); 1084c7c3e8aaSmarco 1085545c4d7fSjsing bd.bd_bio.bio_cookie = bio_cookie; 1086a15048bbSmarco /* XXX make this a dev_t instead of a string */ 1087c7c3e8aaSmarco strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 1088df69c215Sderaadt if (ioctl(devh, BIOCDELETERAID, &bd) == -1) 1089d313c28bSjsing err(1, "BIOCDELETERAID"); 1090d313c28bSjsing 1091d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1092c7c3e8aaSmarco } 1093c7c3e8aaSmarco 1094c6446370Sjsing void 1095c6446370Sjsing bio_changepass(char *dev) 1096c6446370Sjsing { 1097c6446370Sjsing struct bioc_discipline bd; 1098c6446370Sjsing struct sr_crypto_kdfpair kdfpair; 1099c6446370Sjsing struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2; 11003487a6b1Sjsing struct sr_crypto_pbkdf kdfhint; 1101c6446370Sjsing int rv; 1102c6446370Sjsing 1103c6446370Sjsing memset(&bd, 0, sizeof(bd)); 1104c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 1105c6446370Sjsing memset(&kdfinfo1, 0, sizeof(kdfinfo1)); 1106c6446370Sjsing memset(&kdfinfo2, 0, sizeof(kdfinfo2)); 1107c6446370Sjsing 1108c6446370Sjsing /* XXX use dev_t instead of string. */ 1109c6446370Sjsing strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev)); 1110c6446370Sjsing bd.bd_cmd = SR_IOCTL_GET_KDFHINT; 1111c6446370Sjsing bd.bd_size = sizeof(kdfhint); 1112c6446370Sjsing bd.bd_data = &kdfhint; 1113c6446370Sjsing 1114df69c215Sderaadt if (ioctl(devh, BIOCDISCIPLINE, &bd) == -1) 1115d313c28bSjsing err(1, "BIOCDISCIPLINE"); 1116d313c28bSjsing 1117d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1118c6446370Sjsing 1119c6446370Sjsing /* Current passphrase. */ 1120c6446370Sjsing bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0); 1121c6446370Sjsing 11222ba69c71Sjsing /* 11232ba69c71Sjsing * Unless otherwise specified, keep the previous number of rounds as 11242ba69c71Sjsing * long as we're using the same KDF. 11252ba69c71Sjsing */ 11262ba69c71Sjsing if (kdfhint.generic.type == SR_CRYPTOKDFT_BCRYPT_PBKDF && !rflag) 11271f1fa78aSjsing rflag = kdfhint.rounds; 11281f1fa78aSjsing 1129c6446370Sjsing /* New passphrase. */ 11302c98a0f7Sjsing bio_kdf_generate(&kdfinfo2); 1131c6446370Sjsing 1132c6446370Sjsing kdfpair.kdfinfo1 = &kdfinfo1; 1133c6446370Sjsing kdfpair.kdfsize1 = sizeof(kdfinfo1); 1134c6446370Sjsing kdfpair.kdfinfo2 = &kdfinfo2; 1135c6446370Sjsing kdfpair.kdfsize2 = sizeof(kdfinfo2); 1136c6446370Sjsing 1137c6446370Sjsing bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE; 1138c6446370Sjsing bd.bd_size = sizeof(kdfpair); 1139c6446370Sjsing bd.bd_data = &kdfpair; 1140c6446370Sjsing 1141c6446370Sjsing rv = ioctl(devh, BIOCDISCIPLINE, &bd); 1142c6446370Sjsing 1143c6446370Sjsing memset(&kdfhint, 0, sizeof(kdfhint)); 11440a488504Spelikan explicit_bzero(&kdfinfo1, sizeof(kdfinfo1)); 11450a488504Spelikan explicit_bzero(&kdfinfo2, sizeof(kdfinfo2)); 1146c6446370Sjsing 1147df69c215Sderaadt if (rv == -1) 1148d313c28bSjsing err(1, "BIOCDISCIPLINE"); 1149d313c28bSjsing 1150d313c28bSjsing bio_status(&bd.bd_bio.bio_status); 1151c6446370Sjsing } 1152c6446370Sjsing 115303b2dfbfShenning #define BIOCTL_VIS_NBUF 4 115403b2dfbfShenning #define BIOCTL_VIS_BUFLEN 80 115503b2dfbfShenning 115603b2dfbfShenning char * 115703b2dfbfShenning bio_vis(char *s) 115803b2dfbfShenning { 115903b2dfbfShenning static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 116003b2dfbfShenning static uint idx = 0; 116103b2dfbfShenning char *buf; 116203b2dfbfShenning 116303b2dfbfShenning buf = rbuf[idx++]; 116403b2dfbfShenning if (idx == BIOCTL_VIS_NBUF) 116503b2dfbfShenning idx = 0; 116603b2dfbfShenning 116703b2dfbfShenning strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 116803b2dfbfShenning return (buf); 116903b2dfbfShenning } 117003b2dfbfShenning 117103b2dfbfShenning void 117203b2dfbfShenning bio_diskinq(char *sd_dev) 117303b2dfbfShenning { 117403b2dfbfShenning struct dk_inquiry di; 117503b2dfbfShenning 1176da3b0664Shenning if (ioctl(devh, DIOCINQ, &di) == -1) 1177da3b0664Shenning err(1, "DIOCINQ"); 117803b2dfbfShenning 117903b2dfbfShenning printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 118003b2dfbfShenning bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 118103b2dfbfShenning } 1182aef7fe28Shshoexer 1183aef7fe28Shshoexer void 1184d865b7d2Suebayasi bio_patrol(char *arg) 1185d865b7d2Suebayasi { 1186d865b7d2Suebayasi struct bioc_patrol bp; 1187d865b7d2Suebayasi struct timing timing; 1188d865b7d2Suebayasi const char *errstr; 1189d865b7d2Suebayasi 1190d865b7d2Suebayasi memset(&bp, 0, sizeof(bp)); 1191d865b7d2Suebayasi bp.bp_bio.bio_cookie = bio_cookie; 1192d865b7d2Suebayasi 1193d865b7d2Suebayasi switch (arg[0]) { 1194d865b7d2Suebayasi case 'a': 1195d865b7d2Suebayasi bp.bp_opcode = BIOC_SPAUTO; 1196d865b7d2Suebayasi break; 1197d865b7d2Suebayasi 1198d865b7d2Suebayasi case 'm': 1199d865b7d2Suebayasi bp.bp_opcode = BIOC_SPMANUAL; 1200d865b7d2Suebayasi break; 1201d865b7d2Suebayasi 1202d865b7d2Suebayasi case 'd': 1203d865b7d2Suebayasi bp.bp_opcode = BIOC_SPDISABLE; 1204d865b7d2Suebayasi break; 1205d865b7d2Suebayasi 1206d865b7d2Suebayasi case 'g': /* get patrol state */ 1207d865b7d2Suebayasi bp.bp_opcode = BIOC_GPSTATUS; 1208d865b7d2Suebayasi break; 1209d865b7d2Suebayasi 1210d865b7d2Suebayasi case 's': /* start/stop patrol */ 1211d865b7d2Suebayasi if (strncmp("sta", arg, 3) == 0) 1212d865b7d2Suebayasi bp.bp_opcode = BIOC_SPSTART; 1213d865b7d2Suebayasi else 1214d865b7d2Suebayasi bp.bp_opcode = BIOC_SPSTOP; 1215d865b7d2Suebayasi break; 1216d865b7d2Suebayasi 1217d865b7d2Suebayasi default: 1218d865b7d2Suebayasi errx(1, "invalid patrol function: %s", arg); 1219d865b7d2Suebayasi } 1220d865b7d2Suebayasi 1221d865b7d2Suebayasi switch (arg[0]) { 1222d865b7d2Suebayasi case 'a': 1223d865b7d2Suebayasi errstr = str2patrol(arg, &timing); 1224d865b7d2Suebayasi if (errstr) 1225d865b7d2Suebayasi errx(1, "Patrol %s: %s", arg, errstr); 1226d865b7d2Suebayasi bp.bp_autoival = timing.interval; 1227d865b7d2Suebayasi bp.bp_autonext = timing.start; 1228d865b7d2Suebayasi break; 1229d865b7d2Suebayasi } 1230d865b7d2Suebayasi 1231df69c215Sderaadt if (ioctl(devh, BIOCPATROL, &bp) == -1) 1232d865b7d2Suebayasi err(1, "BIOCPATROL"); 1233d865b7d2Suebayasi 1234d865b7d2Suebayasi bio_status(&bp.bp_bio.bio_status); 1235d865b7d2Suebayasi 1236d865b7d2Suebayasi if (arg[0] == 'g') { 1237d865b7d2Suebayasi const char *mode, *status; 1238d865b7d2Suebayasi char interval[40]; 1239d865b7d2Suebayasi 1240d865b7d2Suebayasi interval[0] = '\0'; 1241d865b7d2Suebayasi 1242d865b7d2Suebayasi switch (bp.bp_mode) { 1243d865b7d2Suebayasi case BIOC_SPMAUTO: 1244d865b7d2Suebayasi mode = "auto"; 1245d865b7d2Suebayasi snprintf(interval, sizeof interval, 1246d865b7d2Suebayasi " interval=%d next=%d", bp.bp_autoival, 1247d865b7d2Suebayasi bp.bp_autonext - bp.bp_autonow); 1248d865b7d2Suebayasi break; 1249d865b7d2Suebayasi case BIOC_SPMMANUAL: 1250d865b7d2Suebayasi mode = "manual"; 1251d865b7d2Suebayasi break; 1252d865b7d2Suebayasi case BIOC_SPMDISABLED: 1253d865b7d2Suebayasi mode = "disabled"; 1254d865b7d2Suebayasi break; 1255d865b7d2Suebayasi default: 12562ad5ec6fSuebayasi mode = "unknown"; 1257d865b7d2Suebayasi break; 1258d865b7d2Suebayasi } 1259d865b7d2Suebayasi switch (bp.bp_status) { 1260d865b7d2Suebayasi case BIOC_SPSSTOPPED: 1261d865b7d2Suebayasi status = "stopped"; 1262d865b7d2Suebayasi break; 1263d865b7d2Suebayasi case BIOC_SPSREADY: 1264d865b7d2Suebayasi status = "ready"; 1265d865b7d2Suebayasi break; 1266d865b7d2Suebayasi case BIOC_SPSACTIVE: 1267d865b7d2Suebayasi status = "active"; 1268d865b7d2Suebayasi break; 1269d865b7d2Suebayasi case BIOC_SPSABORTED: 1270d865b7d2Suebayasi status = "aborted"; 1271d865b7d2Suebayasi break; 1272d865b7d2Suebayasi default: 1273d865b7d2Suebayasi status = "unknown"; 1274d865b7d2Suebayasi break; 1275d865b7d2Suebayasi } 1276d865b7d2Suebayasi printf("patrol mode: %s%s\n", mode, interval); 1277d865b7d2Suebayasi printf("patrol status: %s\n", status); 1278d865b7d2Suebayasi } 1279d865b7d2Suebayasi } 1280d865b7d2Suebayasi 1281ef0eb24eSjsing /* 1282ef0eb24eSjsing * Measure this system's performance by measuring the time for 100 rounds. 1283ef0eb24eSjsing * We are aiming for something that takes around 1s. 1284ef0eb24eSjsing */ 1285ef0eb24eSjsing int 1286ef0eb24eSjsing bcrypt_pbkdf_autorounds(void) 1287ef0eb24eSjsing { 1288ef0eb24eSjsing struct timespec before, after; 1289ef0eb24eSjsing char buf[SR_CRYPTO_MAXKEYBYTES], salt[128]; 1290ef0eb24eSjsing int r = 100; 1291ef0eb24eSjsing int duration; 1292ef0eb24eSjsing 1293ef0eb24eSjsing clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before); 1294ef0eb24eSjsing if (bcrypt_pbkdf("testpassword", strlen("testpassword"), 1295ef0eb24eSjsing salt, sizeof(salt), buf, sizeof(buf), r) != 0) 1296ef0eb24eSjsing errx(1, "bcrypt pbkdf failed"); 1297ef0eb24eSjsing clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after); 1298ef0eb24eSjsing 1299ef0eb24eSjsing duration = after.tv_sec - before.tv_sec; 1300ef0eb24eSjsing duration *= 1000000; 1301ef0eb24eSjsing duration += (after.tv_nsec - before.tv_nsec) / 1000; 1302ef0eb24eSjsing 1303ef0eb24eSjsing duration /= r; 1304ef0eb24eSjsing r = 1000000 / duration; 1305ef0eb24eSjsing 1306ef0eb24eSjsing if (r < 16) 1307ef0eb24eSjsing r = 16; 1308ef0eb24eSjsing 1309ef0eb24eSjsing return r; 1310ef0eb24eSjsing } 1311ef0eb24eSjsing 1312d865b7d2Suebayasi void 13133487a6b1Sjsing derive_key(u_int32_t type, int rounds, u_int8_t *key, size_t keysz, 131461f93244Sjsing u_int8_t *salt, size_t saltsz, char *prompt, int verify) 1315aef7fe28Shshoexer { 131686735da2Smarco FILE *f; 131786735da2Smarco size_t pl; 131886735da2Smarco struct stat sb; 13199e8c6f5bShshoexer char passphrase[1024], verifybuf[1024]; 13205f219970Skn int rpp_flag = RPP_ECHO_OFF; 1321aef7fe28Shshoexer 1322aef7fe28Shshoexer if (!key) 1323aef7fe28Shshoexer errx(1, "Invalid key"); 1324aef7fe28Shshoexer if (!salt) 1325aef7fe28Shshoexer errx(1, "Invalid salt"); 132661f93244Sjsing 13271a8c43f6Sjsing if (type != SR_CRYPTOKDFT_PKCS5_PBKDF2 && 13281a8c43f6Sjsing type != SR_CRYPTOKDFT_BCRYPT_PBKDF) 132961f93244Sjsing errx(1, "unknown KDF type %d", type); 13301a8c43f6Sjsing 13311a8c43f6Sjsing if (rounds < (type == SR_CRYPTOKDFT_PKCS5_PBKDF2 ? 1000 : 4)) 133261f93244Sjsing errx(1, "number of KDF rounds is too small: %d", rounds); 1333aef7fe28Shshoexer 1334aef7fe28Shshoexer /* get passphrase */ 1335ba3d8661Smarco if (password) { 133686735da2Smarco if ((f = fopen(password, "r")) == NULL) 133786735da2Smarco err(1, "invalid passphrase file"); 133886735da2Smarco 133986735da2Smarco if (fstat(fileno(f), &sb) == -1) 134086735da2Smarco err(1, "can't stat passphrase file"); 134186735da2Smarco if (sb.st_uid != 0) 134286735da2Smarco errx(1, "passphrase file must be owned by root"); 134386735da2Smarco if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR)) 134486735da2Smarco errx(1, "passphrase file has the wrong permissions"); 134586735da2Smarco 134686735da2Smarco if (fgets(passphrase, sizeof(passphrase), f) == NULL) 134786735da2Smarco err(1, "can't read passphrase file"); 134886735da2Smarco pl = strlen(passphrase); 134986735da2Smarco if (pl > 0 && passphrase[pl - 1] == '\n') 135086735da2Smarco passphrase[pl - 1] = '\0'; 135186735da2Smarco else 135286735da2Smarco errx(1, "invalid passphrase length"); 135386735da2Smarco 135486735da2Smarco fclose(f); 1355ba3d8661Smarco } else { 13565f219970Skn rpp_flag |= interactive ? RPP_REQUIRE_TTY : RPP_STDIN; 13575f219970Skn 1358c6446370Sjsing if (readpassphrase(prompt, passphrase, sizeof(passphrase), 1359b96c6ce2Sckuethe rpp_flag) == NULL) 13607eef0726Stedu err(1, "unable to read passphrase"); 1361ba3d8661Smarco } 13629e8c6f5bShshoexer 13634c688d0dShalex if (verify && !password) { 13649e8c6f5bShshoexer /* request user to re-type it */ 13659e8c6f5bShshoexer if (readpassphrase("Re-type passphrase: ", verifybuf, 1366b96c6ce2Sckuethe sizeof(verifybuf), rpp_flag) == NULL) { 13670a488504Spelikan explicit_bzero(passphrase, sizeof(passphrase)); 13687eef0726Stedu err(1, "unable to read passphrase"); 13699e8c6f5bShshoexer } 13709e8c6f5bShshoexer if ((strlen(passphrase) != strlen(verifybuf)) || 13719e8c6f5bShshoexer (strcmp(passphrase, verifybuf) != 0)) { 13720a488504Spelikan explicit_bzero(passphrase, sizeof(passphrase)); 13730a488504Spelikan explicit_bzero(verifybuf, sizeof(verifybuf)); 13749e8c6f5bShshoexer errx(1, "Passphrases did not match"); 13759e8c6f5bShshoexer } 13769e8c6f5bShshoexer /* forget the re-typed one */ 13770a488504Spelikan explicit_bzero(verifybuf, sizeof(verifybuf)); 13789e8c6f5bShshoexer } 1379aef7fe28Shshoexer 1380aef7fe28Shshoexer /* derive key from passphrase */ 13811a8c43f6Sjsing if (type == SR_CRYPTOKDFT_PKCS5_PBKDF2) { 1382ef0eb24eSjsing if (verbose) 1383ef0eb24eSjsing printf("Deriving key using PKCS#5 PBKDF2 with %i rounds...\n", 1384ef0eb24eSjsing rounds); 13855c1f8f6bSdjm if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 13865c1f8f6bSdjm key, keysz, rounds) != 0) 13871a8c43f6Sjsing errx(1, "pkcs5_pbkdf2 failed"); 13881a8c43f6Sjsing } else if (type == SR_CRYPTOKDFT_BCRYPT_PBKDF) { 1389ef0eb24eSjsing if (verbose) 1390ef0eb24eSjsing printf("Deriving key using bcrypt PBKDF with %i rounds...\n", 1391ef0eb24eSjsing rounds); 13921a8c43f6Sjsing if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, saltsz, 13931a8c43f6Sjsing key, keysz, rounds) != 0) 13941a8c43f6Sjsing errx(1, "bcrypt_pbkdf failed"); 13951a8c43f6Sjsing } else { 13961a8c43f6Sjsing errx(1, "unknown KDF type %d", type); 13971a8c43f6Sjsing } 1398aef7fe28Shshoexer 1399aef7fe28Shshoexer /* forget passphrase */ 14000a488504Spelikan explicit_bzero(passphrase, sizeof(passphrase)); 1401aef7fe28Shshoexer } 1402