1 /* $OpenBSD: bioctl.c,v 1.78 2009/02/22 07:46:55 jmc Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 Marco Peereboom 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/ioctl.h> 31 #include <sys/param.h> 32 #include <sys/queue.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <scsi/scsi_disk.h> 36 #include <scsi/scsi_all.h> 37 #include <dev/biovar.h> 38 #include <dev/softraidvar.h> 39 40 #include <errno.h> 41 #include <err.h> 42 #include <fcntl.h> 43 #include <util.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <ctype.h> 49 #include <util.h> 50 #include <vis.h> 51 #include <readpassphrase.h> 52 53 #include "pbkdf2.h" 54 55 struct locator { 56 int channel; 57 int target; 58 int lun; 59 }; 60 61 void usage(void); 62 const char *str2locator(const char *, struct locator *); 63 void cleanup(void); 64 int bio_parse_devlist(char *, dev_t *); 65 void bio_kdf_derive(struct sr_crypto_kdfinfo *, 66 struct sr_crypto_kdf_pbkdf2 *); 67 void bio_kdf_generate(struct sr_crypto_kdfinfo *); 68 void derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *, 69 size_t, int); 70 71 void bio_inq(char *); 72 void bio_alarm(char *); 73 int bio_getvolbyname(char *); 74 void bio_setstate(char *, int, char *); 75 void bio_setblink(char *, char *, int); 76 void bio_blink(char *, int, int); 77 void bio_createraid(u_int16_t, char *); 78 void bio_deleteraid(char *); 79 u_int32_t bio_createflags(char *); 80 char *bio_vis(char *); 81 void bio_diskinq(char *); 82 83 int devh = -1; 84 int human; 85 int verbose; 86 u_int32_t cflags = 0; 87 int rflag = 8192; 88 89 struct bio_locate bl; 90 91 int 92 main(int argc, char *argv[]) 93 { 94 extern char *optarg; 95 u_int64_t func = 0; 96 /* u_int64_t subfunc = 0; */ 97 char *bioc_dev = NULL, *sd_dev = NULL; 98 char *realname = NULL, *al_arg = NULL; 99 char *bl_arg = NULL, *dev_list = NULL; 100 const char *errstr; 101 int ch, rv, blink = 0, diskinq = 0, ss_func = 0; 102 u_int16_t cr_level = 0; 103 104 if (argc < 2) 105 usage(); 106 107 while ((ch = getopt(argc, argv, "a:b:C:c:dH:hil:qr:R:vu:")) != -1) { 108 switch (ch) { 109 case 'a': /* alarm */ 110 func |= BIOC_ALARM; 111 al_arg = optarg; 112 break; 113 case 'b': /* blink */ 114 func |= BIOC_BLINK; 115 blink = BIOC_SBBLINK; 116 bl_arg = optarg; 117 break; 118 case 'C': /* creation flags */ 119 cflags = bio_createflags(optarg); 120 break; 121 case 'c': /* create */ 122 func |= BIOC_CREATERAID; 123 if (isdigit(*optarg)) 124 cr_level = atoi(optarg); 125 else 126 cr_level = *optarg; 127 break; 128 case 'd': 129 /* delete volume */ 130 func |= BIOC_DELETERAID; 131 break; 132 case 'u': /* unblink */ 133 func |= BIOC_BLINK; 134 blink = BIOC_SBUNBLINK; 135 bl_arg = optarg; 136 break; 137 case 'H': /* set hotspare */ 138 func |= BIOC_SETSTATE; 139 ss_func = BIOC_SSHOTSPARE; 140 al_arg = optarg; 141 break; 142 case 'h': 143 human = 1; 144 break; 145 case 'i': /* inquiry */ 146 func |= BIOC_INQ; 147 break; 148 case 'l': /* device list */ 149 func |= BIOC_DEVLIST; 150 dev_list = optarg; 151 break; 152 case 'r': 153 rflag = strtonum(optarg, 1000, 1<<30, &errstr); 154 if (errstr != NULL) 155 errx(1, "Number of rounds is %s: %s", 156 errstr, optarg); 157 break; 158 case 'R': 159 /* rebuild to provided chunk/CTL */ 160 func |= BIOC_SETSTATE; 161 ss_func = BIOC_SSREBUILD; 162 al_arg = optarg; 163 break; 164 case 'v': 165 verbose = 1; 166 break; 167 case 'q': 168 diskinq = 1; 169 break; 170 default: 171 usage(); 172 /* NOTREACHED */ 173 } 174 } 175 argc -= optind; 176 argv += optind; 177 178 if (argc != 1) 179 usage(); 180 181 if (func == 0) 182 func |= BIOC_INQ; 183 184 /* if at least glob sd[0-9]*, it is a drive identifier */ 185 if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 && 186 isdigit(argv[0][2])) 187 sd_dev = argv[0]; 188 else 189 bioc_dev = argv[0]; 190 191 if (bioc_dev) { 192 devh = open("/dev/bio", O_RDWR); 193 if (devh == -1) 194 err(1, "Can't open %s", "/dev/bio"); 195 196 bl.bl_name = bioc_dev; 197 rv = ioctl(devh, BIOCLOCATE, &bl); 198 if (rv == -1) 199 errx(1, "Can't locate %s device via %s", 200 bl.bl_name, "/dev/bio"); 201 } else if (sd_dev) { 202 devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname); 203 if (devh == -1) 204 err(1, "Can't open %s", sd_dev); 205 } else 206 errx(1, "need -d or -f parameter"); 207 208 if (diskinq) { 209 bio_diskinq(sd_dev); 210 } else if (func & BIOC_INQ) { 211 bio_inq(sd_dev); 212 } else if (func == BIOC_ALARM) { 213 bio_alarm(al_arg); 214 } else if (func == BIOC_BLINK) { 215 bio_setblink(sd_dev, bl_arg, blink); 216 } else if (func == BIOC_SETSTATE) { 217 bio_setstate(al_arg, ss_func, argv[0]); 218 } else if (func == BIOC_DELETERAID && sd_dev != NULL) { 219 bio_deleteraid(sd_dev); 220 } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) { 221 if (!(func & BIOC_CREATERAID)) 222 errx(1, "need -c parameter"); 223 if (!(func & BIOC_DEVLIST)) 224 errx(1, "need -l parameter"); 225 if (sd_dev) 226 errx(1, "can't use sd device"); 227 bio_createraid(cr_level, dev_list); 228 } 229 230 return (0); 231 } 232 233 void 234 usage(void) 235 { 236 extern char *__progname; 237 238 fprintf(stderr, 239 "usage: %s [-hiqv] [-a alarm-function] " 240 "[-b channel:target[.lun]]\n" 241 "\t[-H channel:target[.lun]] " 242 "[-R device | channel:target[.lun]\n" 243 "\t[-u channel:target[.lun]] " 244 "device\n" 245 " %s [-dhiqv] " 246 "[-C flag[,flag,...]] [-c raidlevel]\n" 247 "\t[-l special[,special,...]] " 248 "[-R device | channel:target[.lun]\n" 249 "\t[-r rounds] " 250 "device\n", __progname, __progname); 251 252 exit(1); 253 } 254 255 const char * 256 str2locator(const char *string, struct locator *location) 257 { 258 const char *errstr; 259 char parse[80], *targ, *lun; 260 261 strlcpy(parse, string, sizeof parse); 262 targ = strchr(parse, ':'); 263 if (targ == NULL) 264 return ("target not specified"); 265 *targ++ = '\0'; 266 267 lun = strchr(targ, '.'); 268 if (lun != NULL) { 269 *lun++ = '\0'; 270 location->lun = strtonum(lun, 0, 256, &errstr); 271 if (errstr) 272 return (errstr); 273 } else 274 location->lun = 0; 275 276 location->target = strtonum(targ, 0, 256, &errstr); 277 if (errstr) 278 return (errstr); 279 location->channel = strtonum(parse, 0, 256, &errstr); 280 if (errstr) 281 return (errstr); 282 return (NULL); 283 } 284 285 void 286 bio_inq(char *name) 287 { 288 char *status, size[64], scsiname[16], volname[32]; 289 char percent[10], seconds[20]; 290 int rv, i, d, volheader, hotspare, unused; 291 char encname[16], serial[32]; 292 struct bioc_disk bd; 293 struct bioc_inq bi; 294 struct bioc_vol bv; 295 296 memset(&bi, 0, sizeof(bi)); 297 298 bi.bi_cookie = bl.bl_cookie; 299 300 rv = ioctl(devh, BIOCINQ, &bi); 301 if (rv == -1) { 302 if (errno == ENOTTY) 303 bio_diskinq(name); 304 else 305 err(1, "BIOCINQ"); 306 return; 307 } 308 309 volheader = 0; 310 for (i = 0; i < bi.bi_novol; i++) { 311 memset(&bv, 0, sizeof(bv)); 312 bv.bv_cookie = bl.bl_cookie; 313 bv.bv_volid = i; 314 bv.bv_percent = -1; 315 bv.bv_seconds = 0; 316 317 rv = ioctl(devh, BIOCVOL, &bv); 318 if (rv == -1) 319 err(1, "BIOCVOL"); 320 321 if (name && strcmp(name, bv.bv_dev) != 0) 322 continue; 323 324 if (!volheader) { 325 volheader = 1; 326 printf("%-7s %-10s %14s %-8s\n", 327 "Volume", "Status", "Size", "Device"); 328 } 329 330 percent[0] = '\0'; 331 seconds[0] = '\0'; 332 if (bv.bv_percent != -1) 333 snprintf(percent, sizeof percent, 334 " %d%% done", bv.bv_percent); 335 if (bv.bv_seconds) 336 snprintf(seconds, sizeof seconds, 337 " %u seconds", bv.bv_seconds); 338 switch (bv.bv_status) { 339 case BIOC_SVONLINE: 340 status = BIOC_SVONLINE_S; 341 break; 342 case BIOC_SVOFFLINE: 343 status = BIOC_SVOFFLINE_S; 344 break; 345 case BIOC_SVDEGRADED: 346 status = BIOC_SVDEGRADED_S; 347 break; 348 case BIOC_SVBUILDING: 349 status = BIOC_SVBUILDING_S; 350 break; 351 case BIOC_SVREBUILD: 352 status = BIOC_SVREBUILD_S; 353 break; 354 case BIOC_SVSCRUB: 355 status = BIOC_SVSCRUB_S; 356 break; 357 case BIOC_SVINVALID: 358 default: 359 status = BIOC_SVINVALID_S; 360 } 361 362 snprintf(volname, sizeof volname, "%s %u", 363 bi.bi_dev, bv.bv_volid); 364 365 unused = 0; 366 hotspare = 0; 367 if (bv.bv_level == -1 && bv.bv_nodisk == 1) 368 hotspare = 1; 369 else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 370 unused = 1; 371 else { 372 if (human) 373 fmt_scaled(bv.bv_size, size); 374 else 375 snprintf(size, sizeof size, "%14llu", 376 bv.bv_size); 377 switch (bv.bv_level) { 378 case 'C': 379 printf("%7s %-10s %14s %-7s CRYPTO%s%s\n", 380 volname, status, size, bv.bv_dev, 381 percent, seconds); 382 break; 383 default: 384 printf("%7s %-10s %14s %-7s RAID%u%s%s\n", 385 volname, status, size, bv.bv_dev, 386 bv.bv_level, percent, seconds); 387 break; 388 } 389 390 } 391 392 for (d = 0; d < bv.bv_nodisk; d++) { 393 memset(&bd, 0, sizeof(bd)); 394 bd.bd_cookie = bl.bl_cookie; 395 bd.bd_diskid = d; 396 bd.bd_volid = i; 397 398 rv = ioctl(devh, BIOCDISK, &bd); 399 if (rv == -1) 400 err(1, "BIOCDISK"); 401 402 switch (bd.bd_status) { 403 case BIOC_SDONLINE: 404 status = BIOC_SDONLINE_S; 405 break; 406 case BIOC_SDOFFLINE: 407 status = BIOC_SDOFFLINE_S; 408 break; 409 case BIOC_SDFAILED: 410 status = BIOC_SDFAILED_S; 411 break; 412 case BIOC_SDREBUILD: 413 status = BIOC_SDREBUILD_S; 414 break; 415 case BIOC_SDHOTSPARE: 416 status = BIOC_SDHOTSPARE_S; 417 break; 418 case BIOC_SDUNUSED: 419 status = BIOC_SDUNUSED_S; 420 break; 421 case BIOC_SDSCRUB: 422 status = BIOC_SDSCRUB_S; 423 break; 424 case BIOC_SDINVALID: 425 default: 426 status = BIOC_SDINVALID_S; 427 } 428 429 if (hotspare || unused) 430 ; /* use volname from parent volume */ 431 else 432 snprintf(volname, sizeof volname, " %3u", 433 bd.bd_diskid); 434 435 if (human) 436 fmt_scaled(bd.bd_size, size); 437 else 438 snprintf(size, sizeof size, "%14llu", 439 bd.bd_size); 440 snprintf(scsiname, sizeof scsiname, 441 "%u:%u.%u", 442 bd.bd_channel, bd.bd_target, bd.bd_lun); 443 if (bd.bd_procdev[0]) 444 strlcpy(encname, bd.bd_procdev, sizeof encname); 445 else 446 strlcpy(encname, "noencl", sizeof encname); 447 if (bd.bd_serial[0]) 448 strlcpy(serial, bd.bd_serial, sizeof serial); 449 else 450 strlcpy(serial, "unknown serial", sizeof serial); 451 452 printf("%7s %-10s %14s %-7s %-6s <%s>\n", 453 volname, status, size, scsiname, encname, 454 bd.bd_vendor); 455 if (verbose) 456 printf("%7s %-10s %14s %-7s %-6s '%s'\n", 457 "", "", "", "", "", serial); 458 } 459 } 460 } 461 462 void 463 bio_alarm(char *arg) 464 { 465 int rv; 466 struct bioc_alarm ba; 467 468 ba.ba_cookie = bl.bl_cookie; 469 470 switch (arg[0]) { 471 case 'q': /* silence alarm */ 472 /* FALLTHROUGH */ 473 case 's': 474 ba.ba_opcode = BIOC_SASILENCE; 475 break; 476 477 case 'e': /* enable alarm */ 478 ba.ba_opcode = BIOC_SAENABLE; 479 break; 480 481 case 'd': /* disable alarm */ 482 ba.ba_opcode = BIOC_SADISABLE; 483 break; 484 485 case 't': /* test alarm */ 486 ba.ba_opcode = BIOC_SATEST; 487 break; 488 489 case 'g': /* get alarm state */ 490 ba.ba_opcode = BIOC_GASTATUS; 491 break; 492 493 default: 494 errx(1, "invalid alarm function: %s", arg); 495 } 496 497 rv = ioctl(devh, BIOCALARM, &ba); 498 if (rv == -1) 499 err(1, "BIOCALARM"); 500 501 if (arg[0] == 'g') { 502 printf("alarm is currently %s\n", 503 ba.ba_status ? "enabled" : "disabled"); 504 505 } 506 } 507 508 int 509 bio_getvolbyname(char *name) 510 { 511 int id = -1, i, rv; 512 struct bioc_inq bi; 513 struct bioc_vol bv; 514 515 memset(&bi, 0, sizeof(bi)); 516 bi.bi_cookie = bl.bl_cookie; 517 rv = ioctl(devh, BIOCINQ, &bi); 518 if (rv == -1) 519 err(1, "BIOCINQ"); 520 521 for (i = 0; i < bi.bi_novol; i++) { 522 memset(&bv, 0, sizeof(bv)); 523 bv.bv_cookie = bl.bl_cookie; 524 bv.bv_volid = i; 525 rv = ioctl(devh, BIOCVOL, &bv); 526 if (rv == -1) 527 err(1, "BIOCVOL"); 528 529 if (name && strcmp(name, bv.bv_dev) != 0) 530 continue; 531 id = i; 532 break; 533 } 534 535 return (id); 536 } 537 538 void 539 bio_setstate(char *arg, int status, char *devicename) 540 { 541 struct bioc_setstate bs; 542 struct locator location; 543 struct stat sb; 544 const char *errstr; 545 int rv; 546 547 memset(&bs, 0, sizeof(bs)); 548 if (stat(arg, &sb) == -1) { 549 /* use CTL */ 550 errstr = str2locator(arg, &location); 551 if (errstr) 552 errx(1, "Target %s: %s", arg, errstr); 553 bs.bs_channel = location.channel; 554 bs.bs_target = location.target; 555 bs.bs_lun = location.lun; 556 } else { 557 /* use other id */ 558 bs.bs_other_id = sb.st_rdev; 559 bs.bs_other_id_type = BIOC_SSOTHER_DEVT; 560 } 561 562 bs.bs_cookie = bl.bl_cookie; 563 bs.bs_status = status; 564 565 /* make sure user supplied a sd device */ 566 bs.bs_volid = bio_getvolbyname(devicename); 567 if (bs.bs_volid == -1) 568 errx(1, "invalid device %s", devicename); 569 570 rv = ioctl(devh, BIOCSETSTATE, &bs); 571 if (rv == -1) 572 err(1, "BIOCSETSTATE"); 573 } 574 575 void 576 bio_setblink(char *name, char *arg, int blink) 577 { 578 struct locator location; 579 struct bioc_inq bi; 580 struct bioc_vol bv; 581 struct bioc_disk bd; 582 struct bioc_blink bb; 583 const char *errstr; 584 int v, d, rv; 585 586 errstr = str2locator(arg, &location); 587 if (errstr) 588 errx(1, "Target %s: %s", arg, errstr); 589 590 /* try setting blink on the device directly */ 591 memset(&bb, 0, sizeof(bb)); 592 bb.bb_cookie = bl.bl_cookie; 593 bb.bb_status = blink; 594 bb.bb_target = location.target; 595 bb.bb_channel = location.channel; 596 rv = ioctl(devh, BIOCBLINK, &bb); 597 if (rv == 0) 598 return; 599 600 /* if the blink didnt work, try to find something that will */ 601 602 memset(&bi, 0, sizeof(bi)); 603 bi.bi_cookie = bl.bl_cookie; 604 rv = ioctl(devh, BIOCINQ, &bi); 605 if (rv == -1) 606 err(1, "BIOCINQ"); 607 608 for (v = 0; v < bi.bi_novol; v++) { 609 memset(&bv, 0, sizeof(bv)); 610 bv.bv_cookie = bl.bl_cookie; 611 bv.bv_volid = v; 612 rv = ioctl(devh, BIOCVOL, &bv); 613 if (rv == -1) 614 err(1, "BIOCVOL"); 615 616 if (name && strcmp(name, bv.bv_dev) != 0) 617 continue; 618 619 for (d = 0; d < bv.bv_nodisk; d++) { 620 memset(&bd, 0, sizeof(bd)); 621 bd.bd_cookie = bl.bl_cookie; 622 bd.bd_volid = v; 623 bd.bd_diskid = d; 624 625 rv = ioctl(devh, BIOCDISK, &bd); 626 if (rv == -1) 627 err(1, "BIOCDISK"); 628 629 if (bd.bd_channel == location.channel && 630 bd.bd_target == location.target && 631 bd.bd_lun == location.lun) { 632 if (bd.bd_procdev[0] != '\0') { 633 bio_blink(bd.bd_procdev, 634 location.target, blink); 635 } else 636 warnx("Disk %s is not in an enclosure", arg); 637 return; 638 } 639 } 640 } 641 642 warnx("Disk %s does not exist", arg); 643 return; 644 } 645 646 void 647 bio_blink(char *enclosure, int target, int blinktype) 648 { 649 int bioh; 650 struct bio_locate bio; 651 struct bioc_blink blink; 652 int rv; 653 654 bioh = open("/dev/bio", O_RDWR); 655 if (bioh == -1) 656 err(1, "Can't open %s", "/dev/bio"); 657 658 bio.bl_name = enclosure; 659 rv = ioctl(bioh, BIOCLOCATE, &bio); 660 if (rv == -1) 661 errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio"); 662 663 memset(&blink, 0, sizeof(blink)); 664 blink.bb_cookie = bio.bl_cookie; 665 blink.bb_status = blinktype; 666 blink.bb_target = target; 667 668 rv = ioctl(bioh, BIOCBLINK, &blink); 669 if (rv == -1) 670 err(1, "BIOCBLINK"); 671 672 close(bioh); 673 } 674 675 void 676 bio_createraid(u_int16_t level, char *dev_list) 677 { 678 struct bioc_createraid create; 679 struct sr_crypto_kdfinfo kdfinfo; 680 struct sr_crypto_kdf_pbkdf2 kdfhint; 681 int rv, no_dev; 682 dev_t *dt; 683 u_int16_t min_disks = 0; 684 685 if (!dev_list) 686 errx(1, "no devices specified"); 687 688 dt = (dev_t *)malloc(BIOC_CRMAXLEN); 689 if (!dt) 690 err(1, "not enough memory for dev_t list"); 691 memset(dt, 0, BIOC_CRMAXLEN); 692 693 no_dev = bio_parse_devlist(dev_list, dt); 694 695 switch (level) { 696 case 0: 697 min_disks = 2; 698 break; 699 case 1: 700 min_disks = 2; 701 break; 702 case 'C': 703 min_disks = 1; 704 break; 705 case 'c': 706 min_disks = 1; 707 break; 708 default: 709 errx(1, "unsupported raid level"); 710 } 711 712 if (no_dev < min_disks) 713 errx(1, "not enough disks"); 714 715 /* for crypto raid we only allow one single chunk */ 716 if (level == 'C' && no_dev != min_disks) 717 errx(1, "not exactly one disks"); 718 719 720 memset(&create, 0, sizeof(create)); 721 create.bc_cookie = bl.bl_cookie; 722 create.bc_level = level; 723 create.bc_dev_list_len = no_dev * sizeof(dev_t); 724 create.bc_dev_list = dt; 725 create.bc_flags = BIOC_SCDEVT | cflags; 726 727 if (level == 'C') { 728 memset(&kdfinfo, 0, sizeof(kdfinfo)); 729 memset(&kdfhint, 0, sizeof(kdfhint)); 730 731 create.bc_opaque = &kdfhint; 732 create.bc_opaque_size = sizeof(kdfhint); 733 create.bc_opaque_flags = BIOC_SOOUT; 734 735 /* try to get KDF hint */ 736 if (ioctl(devh, BIOCCREATERAID, &create) == -1) 737 err(1, "ioctl"); 738 739 if (create.bc_opaque_status == BIOC_SOINOUT_OK) { 740 bio_kdf_derive(&kdfinfo, &kdfhint); 741 memset(&kdfhint, 0, sizeof(kdfhint)); 742 } else { 743 bio_kdf_generate(&kdfinfo); 744 /* no auto assembling */ 745 create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; 746 } 747 748 create.bc_opaque = &kdfinfo; 749 create.bc_opaque_size = sizeof(kdfinfo); 750 create.bc_opaque_flags = BIOC_SOIN; 751 } 752 753 rv = ioctl(devh, BIOCCREATERAID, &create); 754 memset(&kdfinfo, 0, sizeof(kdfinfo)); 755 memset(&create, 0, sizeof(create)); 756 if (rv == -1) { 757 if (errno == EPERM) 758 errx(1, "Incorrect passphrase"); 759 err(1, "BIOCCREATERAID"); 760 } 761 762 free(dt); 763 } 764 765 void 766 bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2 767 *kdfhint) 768 { 769 if (!kdfinfo) 770 errx(1, "invalid KDF info"); 771 if (!kdfhint) 772 errx(1, "invalid KDF hint"); 773 774 if (kdfhint->len != sizeof(*kdfhint)) 775 errx(1, "KDF hint has invalid size"); 776 if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2) 777 errx(1, "unknown KDF type %d", kdfhint->type); 778 if (kdfhint->rounds < 1000) 779 errx(1, "number of KDF rounds too low: %d", kdfhint->rounds); 780 781 kdfinfo->flags = SR_CRYPTOKDF_KEY; 782 kdfinfo->len = sizeof(*kdfinfo); 783 784 derive_key_pkcs(kdfhint->rounds, 785 kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 786 kdfhint->salt, sizeof(kdfhint->salt), 0); 787 } 788 789 void 790 bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo) 791 { 792 if (!kdfinfo) 793 errx(1, "invalid KDF info"); 794 795 kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2); 796 kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2; 797 kdfinfo->pbkdf2.rounds = rflag; 798 kdfinfo->len = sizeof(*kdfinfo); 799 kdfinfo->flags = (SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT); 800 801 /* generate salt */ 802 arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt)); 803 804 derive_key_pkcs(kdfinfo->pbkdf2.rounds, 805 kdfinfo->maskkey, sizeof(kdfinfo->maskkey), 806 kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), 1); 807 } 808 809 int 810 bio_parse_devlist(char *lst, dev_t *dt) 811 { 812 char *s, *e; 813 u_int32_t sz = 0; 814 int no_dev = 0, i, x; 815 struct stat sb; 816 char dev[MAXPATHLEN]; 817 818 if (!lst) 819 errx(1, "invalid device list"); 820 821 s = e = lst; 822 /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */ 823 while (*e != '\0') { 824 if (*e == ',') 825 s = e + 1; 826 else if (*(e + 1) == '\0' || *(e + 1) == ',') { 827 /* got one */ 828 sz = e - s + 1; 829 strlcpy(dev, s, sz + 1); 830 if (stat(dev, &sb) == -1) 831 err(1, "could not stat %s", dev); 832 dt[no_dev] = sb.st_rdev; 833 no_dev++; 834 if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t))) 835 errx(1, "too many devices on device list"); 836 } 837 e++; 838 } 839 840 for (i = 0; i < no_dev; i++) 841 for (x = 0; x < no_dev; x++) 842 if (dt[i] == dt[x] && x != i) 843 errx(1, "duplicate device in list"); 844 845 return (no_dev); 846 } 847 848 u_int32_t 849 bio_createflags(char *lst) 850 { 851 char *s, *e, fs[32]; 852 u_int32_t sz = 0; 853 u_int32_t flags = 0; 854 855 if (!lst) 856 errx(1, "invalid flags list"); 857 858 s = e = lst; 859 /* make sure we have a valid flags list like force,noassemeble */ 860 while (*e != '\0') { 861 if (*e == ',') 862 s = e + 1; 863 else if (*(e + 1) == '\0' || *(e + 1) == ',') { 864 /* got one */ 865 sz = e - s + 1; 866 switch (s[0]) { 867 case 'f': 868 flags |= BIOC_SCFORCE; 869 break; 870 case 'n': 871 flags |= BIOC_SCNOAUTOASSEMBLE; 872 break; 873 default: 874 strlcpy(fs, s, sz + 1); 875 errx(1, "invalid flag %s", fs); 876 } 877 } 878 e++; 879 } 880 881 return (flags); 882 } 883 884 void 885 bio_deleteraid(char *dev) 886 { 887 struct bioc_deleteraid bd; 888 memset(&bd, 0, sizeof(bd)); 889 890 bd.bd_cookie = bd.bd_cookie; 891 /* XXX make this a dev_t instead of a string */ 892 strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev); 893 if (ioctl(devh, BIOCDELETERAID, &bd)) 894 errx(1, "delete volume %s failed", dev); 895 } 896 897 #define BIOCTL_VIS_NBUF 4 898 #define BIOCTL_VIS_BUFLEN 80 899 900 char * 901 bio_vis(char *s) 902 { 903 static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN]; 904 static uint idx = 0; 905 char *buf; 906 907 buf = rbuf[idx++]; 908 if (idx == BIOCTL_VIS_NBUF) 909 idx = 0; 910 911 strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE); 912 return (buf); 913 } 914 915 void 916 bio_diskinq(char *sd_dev) 917 { 918 struct dk_inquiry di; 919 920 if (ioctl(devh, DIOCINQ, &di) == -1) 921 err(1, "DIOCINQ"); 922 923 printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor), 924 bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial)); 925 } 926 927 void 928 derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt, 929 size_t saltsz, int verify) 930 { 931 char passphrase[1024], verifybuf[1024]; 932 933 if (!key) 934 errx(1, "Invalid key"); 935 if (!salt) 936 errx(1, "Invalid salt"); 937 if (rounds < 1000) 938 errx(1, "Too less rounds: %d", rounds); 939 940 /* get passphrase */ 941 if (readpassphrase("Passphrase: ", passphrase, sizeof(passphrase), 942 RPP_REQUIRE_TTY) == NULL) 943 errx(1, "unable to read passphrase"); 944 945 if (verify) { 946 /* request user to re-type it */ 947 if (readpassphrase("Re-type passphrase: ", verifybuf, 948 sizeof(verifybuf), RPP_REQUIRE_TTY) == NULL) { 949 memset(passphrase, 0, sizeof(passphrase)); 950 errx(1, "unable to read passphrase"); 951 } 952 if ((strlen(passphrase) != strlen(verifybuf)) || 953 (strcmp(passphrase, verifybuf) != 0)) { 954 memset(passphrase, 0, sizeof(passphrase)); 955 memset(verifybuf, 0, sizeof(verifybuf)); 956 errx(1, "Passphrases did not match"); 957 } 958 /* forget the re-typed one */ 959 memset(verifybuf, 0, strlen(verifybuf)); 960 } 961 962 /* derive key from passphrase */ 963 if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz, 964 key, keysz, rounds) != 0) 965 errx(1, "pbkdf2 failed"); 966 967 /* forget passphrase */ 968 memset(passphrase, 0, sizeof(passphrase)); 969 970 return; 971 } 972