1 /* $OpenBSD: bioctl.c,v 1.158 2024/07/15 05:36:08 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/param.h> /* NODEV */
31 #include <sys/ioctl.h>
32 #include <sys/dkio.h>
33 #include <sys/stat.h>
34 #include <dev/softraidvar.h>
35 #include <dev/biovar.h>
36
37 #include <errno.h>
38 #include <err.h>
39 #include <fcntl.h>
40 #include <util.h>
41 #include <ctype.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include <limits.h>
48 #include <vis.h>
49 #include <readpassphrase.h>
50
51 struct locator {
52 int channel;
53 int target;
54 int lun;
55 };
56
57 struct timing {
58 int interval;
59 int start;
60 };
61
62 static void __dead usage(void);
63 const char *str2locator(const char *, struct locator *);
64 const char *str2patrol(const char *, struct timing *);
65 void bio_status(struct bio_status *);
66 int bio_parse_devlist(char *, dev_t *);
67 void bio_kdf_derive(struct sr_crypto_kdfinfo *,
68 struct sr_crypto_pbkdf *, char *, int);
69 void bio_kdf_generate(struct sr_crypto_kdfinfo *);
70 int bcrypt_pbkdf_autorounds(void);
71 void derive_key(u_int32_t, int, u_int8_t *, size_t,
72 u_int8_t *, size_t, char *, int);
73
74 void bio_inq(char *);
75 void bio_alarm(char *);
76 int bio_getvolbyname(char *);
77 void bio_setstate(char *, int, char *);
78 void bio_setblink(char *, char *, int);
79 void bio_blink(char *, int, int);
80 void bio_createraid(u_int16_t, char *, char *);
81 void bio_deleteraid(char *);
82 void bio_changepass(char *);
83 u_int32_t bio_createflags(char *);
84 char *bio_vis(char *);
85 void bio_diskinq(char *);
86 void bio_patrol(char *);
87
88 int devh = -1;
89 int human;
90 int verbose;
91 u_int32_t cflags = 0;
92 int rflag = -1; /* auto */
93 char *passfile;
94
95 void *bio_cookie;
96
97 int interactive = 1;
98
99 int
main(int argc,char * argv[])100 main(int argc, char *argv[])
101 {
102 struct bio_locate bl;
103 u_int64_t func = 0;
104 char *devicename = NULL;
105 char *realname = NULL, *al_arg = NULL;
106 char *bl_arg = NULL, *dev_list = NULL;
107 char *key_disk = NULL;
108 const char *errstr;
109 int ch, blink = 0, changepass = 0, diskinq = 0;
110 int ss_func = 0;
111 u_int16_t cr_level = 0;
112 int biodev = 0;
113
114 if (argc < 2)
115 usage();
116
117 while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:O:Pp:qr:R:st:u:v")) !=
118 -1) {
119 switch (ch) {
120 case 'a': /* alarm */
121 func |= BIOC_ALARM;
122 al_arg = optarg;
123 break;
124 case 'b': /* blink */
125 func |= BIOC_BLINK;
126 blink = BIOC_SBBLINK;
127 bl_arg = optarg;
128 break;
129 case 'C': /* creation flags */
130 cflags = bio_createflags(optarg);
131 break;
132 case 'c': /* create */
133 func |= BIOC_CREATERAID;
134 if (strcmp(optarg, "1C") == 0) {
135 cr_level = 0x1C;
136 } else if (isdigit((unsigned char)*optarg)) {
137 cr_level = strtonum(optarg, 0, 10, &errstr);
138 if (errstr != NULL)
139 errx(1, "Invalid RAID level");
140 } else if (strlen(optarg) == 1) {
141 cr_level = *optarg;
142 } else {
143 errx(1, "Invalid RAID level");
144 }
145 break;
146 case 'd':
147 /* delete volume */
148 func |= BIOC_DELETERAID;
149 break;
150 case 'u': /* unblink */
151 func |= BIOC_BLINK;
152 blink = BIOC_SBUNBLINK;
153 bl_arg = optarg;
154 break;
155 case 'H': /* set hotspare */
156 func |= BIOC_SETSTATE;
157 ss_func = BIOC_SSHOTSPARE;
158 al_arg = optarg;
159 break;
160 case 'h':
161 human = 1;
162 break;
163 case 'i': /* inquiry */
164 func |= BIOC_INQ;
165 break;
166 case 'k': /* Key disk. */
167 key_disk = optarg;
168 break;
169 case 'l': /* device list */
170 func |= BIOC_DEVLIST;
171 dev_list = optarg;
172 break;
173 case 'P':
174 /* Change passphrase. */
175 changepass = 1;
176 break;
177 case 'p':
178 passfile = optarg;
179 break;
180 case 'r':
181 if (strcmp(optarg, "auto") == 0) {
182 rflag = -1;
183 break;
184 }
185 rflag = strtonum(optarg, 16, 1<<30, &errstr);
186 if (errstr != NULL)
187 errx(1, "number of KDF rounds is %s: %s",
188 errstr, optarg);
189 break;
190 case 'O':
191 /* set a chunk to offline */
192 func |= BIOC_SETSTATE;
193 ss_func = BIOC_SSOFFLINE;
194 al_arg = optarg;
195 break;
196 case 'R':
197 /* rebuild to provided chunk/CTL */
198 func |= BIOC_SETSTATE;
199 ss_func = BIOC_SSREBUILD;
200 al_arg = optarg;
201 break;
202 case 's':
203 interactive = 0;
204 break;
205 case 't': /* patrol */
206 func |= BIOC_PATROL;
207 al_arg = optarg;
208 break;
209 case 'v':
210 verbose = 1;
211 break;
212 case 'q':
213 diskinq = 1;
214 break;
215 default:
216 usage();
217 /* NOTREACHED */
218 }
219 }
220 argc -= optind;
221 argv += optind;
222
223 if (argc != 1 || (changepass && func != 0))
224 usage();
225
226 if (func == 0)
227 func |= BIOC_INQ;
228
229 devicename = argv[0];
230 if (devicename == NULL)
231 errx(1, "need device");
232
233 devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname);
234 if (devh == -1) {
235 devh = open("/dev/bio", O_RDWR);
236 if (devh == -1)
237 err(1, "Can't open %s", "/dev/bio");
238
239 memset(&bl, 0, sizeof(bl));
240 bl.bl_name = devicename;
241 if (ioctl(devh, BIOCLOCATE, &bl) == -1)
242 errx(1, "Can't locate %s device via %s",
243 bl.bl_name, "/dev/bio");
244
245 bio_cookie = bl.bl_bio.bio_cookie;
246 biodev = 1;
247 devicename = NULL;
248 }
249
250 if (diskinq) {
251 bio_diskinq(devicename);
252 } else if (changepass && !biodev) {
253 bio_changepass(devicename);
254 } else if (func & BIOC_INQ) {
255 bio_inq(devicename);
256 } else if (func == BIOC_ALARM) {
257 bio_alarm(al_arg);
258 } else if (func == BIOC_BLINK) {
259 bio_setblink(devicename, bl_arg, blink);
260 } else if (func == BIOC_PATROL) {
261 bio_patrol(al_arg);
262 } else if (func == BIOC_SETSTATE) {
263 bio_setstate(al_arg, ss_func, argv[0]);
264 } else if (func == BIOC_DELETERAID && !biodev) {
265 bio_deleteraid(devicename);
266 } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
267 if (!(func & BIOC_CREATERAID))
268 errx(1, "need -c parameter");
269 if (!(func & BIOC_DEVLIST))
270 errx(1, "need -l parameter");
271 if (!biodev)
272 errx(1, "must use bio device");
273 bio_createraid(cr_level, dev_list, key_disk);
274 }
275
276 return (0);
277 }
278
279 static void __dead
usage(void)280 usage(void)
281 {
282 extern char *__progname;
283
284 fprintf(stderr,
285 "usage: %s [-hiqv] [-a alarm-function] "
286 "[-b channel:target[.lun]]\n"
287 "\t[-H channel:target[.lun]] "
288 "[-R chunk | channel:target[.lun]]\n"
289 "\t[-t patrol-function] "
290 "[-u channel:target[.lun]] "
291 "device\n\n"
292 " %s [-dhiPqsv] "
293 "[-C flag[,...]] [-c raidlevel] [-k keydisk]\n"
294 "\t[-l chunk[,...]] "
295 "[-O device | channel:target[.lun]] [-p passfile]\n"
296 "\t[-R chunk | channel:target[.lun]] [-r rounds] "
297 "device\n", __progname, __progname);
298
299 exit(1);
300 }
301
302 const char *
str2locator(const char * string,struct locator * location)303 str2locator(const char *string, struct locator *location)
304 {
305 const char *errstr;
306 char parse[80], *targ, *lun;
307
308 strlcpy(parse, string, sizeof parse);
309 targ = strchr(parse, ':');
310 if (targ == NULL)
311 return ("target not specified");
312 *targ++ = '\0';
313
314 lun = strchr(targ, '.');
315 if (lun != NULL) {
316 *lun++ = '\0';
317 location->lun = strtonum(lun, 0, 256, &errstr);
318 if (errstr)
319 return (errstr);
320 } else
321 location->lun = 0;
322
323 location->target = strtonum(targ, 0, 256, &errstr);
324 if (errstr)
325 return (errstr);
326 location->channel = strtonum(parse, 0, 256, &errstr);
327 if (errstr)
328 return (errstr);
329 return (NULL);
330 }
331
332 const char *
str2patrol(const char * string,struct timing * timing)333 str2patrol(const char *string, struct timing *timing)
334 {
335 const char *errstr;
336 char parse[80], *interval = NULL, *start = NULL;
337
338 timing->interval = 0;
339 timing->start = 0;
340
341 strlcpy(parse, string, sizeof parse);
342
343 interval = strchr(parse, '.');
344 if (interval != NULL) {
345 *interval++ = '\0';
346 start = strchr(interval, '.');
347 if (start != NULL)
348 *start++ = '\0';
349 }
350 if (interval != NULL) {
351 /* -1 == continuously */
352 timing->interval = strtonum(interval, -1, INT_MAX, &errstr);
353 if (errstr)
354 return (errstr);
355 }
356 if (start != NULL) {
357 timing->start = strtonum(start, 0, INT_MAX, &errstr);
358 if (errstr)
359 return (errstr);
360 }
361
362 return (NULL);
363 }
364
365 void
bio_status(struct bio_status * bs)366 bio_status(struct bio_status *bs)
367 {
368 extern char *__progname;
369 char *prefix;
370 int i;
371
372 if (strlen(bs->bs_controller))
373 prefix = bs->bs_controller;
374 else
375 prefix = __progname;
376
377 for (i = 0; i < bs->bs_msg_count; i++)
378 fprintf(bs->bs_msgs[i].bm_type == BIO_MSG_INFO ?
379 stdout : stderr, "%s: %s\n", prefix, bs->bs_msgs[i].bm_msg);
380
381 if (bs->bs_status == BIO_STATUS_ERROR) {
382 if (bs->bs_msg_count == 0)
383 errx(1, "unknown error");
384 else
385 exit(1);
386 }
387 }
388
389 void
bio_inq(char * name)390 bio_inq(char *name)
391 {
392 char *status, *cache;
393 char size[64], scsiname[16], volname[32];
394 char percent[20], seconds[20];
395 int i, d, volheader, hotspare, unused;
396 char encname[16], serial[32];
397 struct bioc_inq bi;
398 struct bioc_vol bv;
399 struct bioc_disk bd;
400
401 memset(&bi, 0, sizeof(bi));
402
403 bi.bi_bio.bio_cookie = bio_cookie;
404
405 if (ioctl(devh, BIOCINQ, &bi) == -1) {
406 if (errno == ENOTTY)
407 bio_diskinq(name);
408 else
409 err(1, "BIOCINQ");
410 return;
411 }
412
413 bio_status(&bi.bi_bio.bio_status);
414
415 volheader = 0;
416 for (i = 0; i < bi.bi_novol; i++) {
417 memset(&bv, 0, sizeof(bv));
418 bv.bv_bio.bio_cookie = bio_cookie;
419 bv.bv_volid = i;
420 bv.bv_percent = -1;
421 bv.bv_seconds = 0;
422
423 if (ioctl(devh, BIOCVOL, &bv) == -1)
424 err(1, "BIOCVOL");
425
426 bio_status(&bv.bv_bio.bio_status);
427
428 if (name && strcmp(name, bv.bv_dev) != 0)
429 continue;
430
431 if (!volheader) {
432 volheader = 1;
433 printf("%-11s %-10s %14s %-8s\n",
434 "Volume", "Status", "Size", "Device");
435 }
436
437 percent[0] = '\0';
438 seconds[0] = '\0';
439 if (bv.bv_percent != -1)
440 snprintf(percent, sizeof percent,
441 " %d%% done", bv.bv_percent);
442 if (bv.bv_seconds)
443 snprintf(seconds, sizeof seconds,
444 " %u seconds", bv.bv_seconds);
445 switch (bv.bv_status) {
446 case BIOC_SVONLINE:
447 status = BIOC_SVONLINE_S;
448 break;
449 case BIOC_SVOFFLINE:
450 status = BIOC_SVOFFLINE_S;
451 break;
452 case BIOC_SVDEGRADED:
453 status = BIOC_SVDEGRADED_S;
454 break;
455 case BIOC_SVBUILDING:
456 status = BIOC_SVBUILDING_S;
457 break;
458 case BIOC_SVREBUILD:
459 status = BIOC_SVREBUILD_S;
460 break;
461 case BIOC_SVSCRUB:
462 status = BIOC_SVSCRUB_S;
463 break;
464 case BIOC_SVINVALID:
465 default:
466 status = BIOC_SVINVALID_S;
467 }
468 switch (bv.bv_cache) {
469 case BIOC_CVWRITEBACK:
470 cache = BIOC_CVWRITEBACK_S;
471 break;
472 case BIOC_CVWRITETHROUGH:
473 cache = BIOC_CVWRITETHROUGH_S;
474 break;
475 case BIOC_CVUNKNOWN:
476 default:
477 cache = BIOC_CVUNKNOWN_S;
478 }
479
480 snprintf(volname, sizeof volname, "%s %u",
481 bi.bi_dev, bv.bv_volid);
482
483 unused = 0;
484 hotspare = 0;
485 if (bv.bv_level == -1 && bv.bv_nodisk == 1)
486 hotspare = 1;
487 else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
488 unused = 1;
489 else {
490 if (human)
491 fmt_scaled(bv.bv_size, size);
492 else
493 snprintf(size, sizeof size, "%14llu",
494 bv.bv_size);
495 printf("%11s %-10s %14s %-7s ",
496 volname, status, size, bv.bv_dev);
497 switch (bv.bv_level) {
498 case 'C':
499 printf("CRYPTO%s%s\n",
500 percent, seconds);
501 break;
502 case 'c':
503 printf("CONCAT%s%s\n",
504 percent, seconds);
505 break;
506 case 0x1C:
507 case 0x1E:
508 printf("RAID%X%s%s %s\n",
509 bv.bv_level, percent, seconds, cache);
510 break;
511 default:
512 printf("RAID%u%s%s %s\n",
513 bv.bv_level, percent, seconds, cache);
514 break;
515 }
516
517 }
518
519 for (d = 0; d < bv.bv_nodisk; d++) {
520 memset(&bd, 0, sizeof(bd));
521 bd.bd_bio.bio_cookie = bio_cookie;
522 bd.bd_diskid = d;
523 bd.bd_volid = i;
524 bd.bd_patrol.bdp_percent = -1;
525 bd.bd_patrol.bdp_seconds = 0;
526
527 if (ioctl(devh, BIOCDISK, &bd) == -1)
528 err(1, "BIOCDISK");
529
530 bio_status(&bd.bd_bio.bio_status);
531
532 switch (bd.bd_status) {
533 case BIOC_SDONLINE:
534 status = BIOC_SDONLINE_S;
535 break;
536 case BIOC_SDOFFLINE:
537 status = BIOC_SDOFFLINE_S;
538 break;
539 case BIOC_SDFAILED:
540 status = BIOC_SDFAILED_S;
541 break;
542 case BIOC_SDREBUILD:
543 status = BIOC_SDREBUILD_S;
544 break;
545 case BIOC_SDHOTSPARE:
546 status = BIOC_SDHOTSPARE_S;
547 break;
548 case BIOC_SDUNUSED:
549 status = BIOC_SDUNUSED_S;
550 break;
551 case BIOC_SDSCRUB:
552 status = BIOC_SDSCRUB_S;
553 break;
554 case BIOC_SDINVALID:
555 default:
556 status = BIOC_SDINVALID_S;
557 }
558
559 if (hotspare || unused)
560 ; /* use volname from parent volume */
561 else
562 snprintf(volname, sizeof volname, " %3u",
563 bd.bd_diskid);
564
565 if (bv.bv_level == 'C' && bd.bd_size == 0)
566 snprintf(size, sizeof size, "%14s", "key disk");
567 else if (human)
568 fmt_scaled(bd.bd_size, size);
569 else
570 snprintf(size, sizeof size, "%14llu",
571 bd.bd_size);
572 snprintf(scsiname, sizeof scsiname,
573 "%u:%u.%u",
574 bd.bd_channel, bd.bd_target, bd.bd_lun);
575 if (bd.bd_procdev[0])
576 strlcpy(encname, bd.bd_procdev, sizeof encname);
577 else
578 strlcpy(encname, "noencl", sizeof encname);
579 if (bd.bd_serial[0])
580 strlcpy(serial, bd.bd_serial, sizeof serial);
581 else
582 strlcpy(serial, "unknown serial", sizeof serial);
583
584 percent[0] = '\0';
585 seconds[0] = '\0';
586 if (bd.bd_patrol.bdp_percent != -1)
587 snprintf(percent, sizeof percent,
588 " patrol %d%% done", bd.bd_patrol.bdp_percent);
589 if (bd.bd_patrol.bdp_seconds)
590 snprintf(seconds, sizeof seconds,
591 " %u seconds", bd.bd_patrol.bdp_seconds);
592
593 printf("%11s %-10s %14s %-7s %-6s <%s>\n",
594 volname, status, size, scsiname, encname,
595 bd.bd_vendor);
596 if (verbose)
597 printf("%11s %-10s %14s %-7s %-6s '%s'%s%s\n",
598 "", "", "", "", "", serial, percent, seconds);
599 }
600 }
601 }
602
603 void
bio_alarm(char * arg)604 bio_alarm(char *arg)
605 {
606 struct bioc_alarm ba;
607
608 memset(&ba, 0, sizeof(ba));
609 ba.ba_bio.bio_cookie = bio_cookie;
610
611 switch (arg[0]) {
612 case 'q': /* silence alarm */
613 /* FALLTHROUGH */
614 case 's':
615 ba.ba_opcode = BIOC_SASILENCE;
616 break;
617
618 case 'e': /* enable alarm */
619 ba.ba_opcode = BIOC_SAENABLE;
620 break;
621
622 case 'd': /* disable alarm */
623 ba.ba_opcode = BIOC_SADISABLE;
624 break;
625
626 case 't': /* test alarm */
627 ba.ba_opcode = BIOC_SATEST;
628 break;
629
630 case 'g': /* get alarm state */
631 ba.ba_opcode = BIOC_GASTATUS;
632 break;
633
634 default:
635 errx(1, "invalid alarm function: %s", arg);
636 }
637
638 if (ioctl(devh, BIOCALARM, &ba) == -1)
639 err(1, "BIOCALARM");
640
641 bio_status(&ba.ba_bio.bio_status);
642
643 if (arg[0] == 'g')
644 printf("alarm is currently %s\n",
645 ba.ba_status ? "enabled" : "disabled");
646 }
647
648 int
bio_getvolbyname(char * name)649 bio_getvolbyname(char *name)
650 {
651 int id = -1, i;
652 struct bioc_inq bi;
653 struct bioc_vol bv;
654
655 memset(&bi, 0, sizeof(bi));
656 bi.bi_bio.bio_cookie = bio_cookie;
657 if (ioctl(devh, BIOCINQ, &bi) == -1)
658 err(1, "BIOCINQ");
659
660 bio_status(&bi.bi_bio.bio_status);
661
662 for (i = 0; i < bi.bi_novol; i++) {
663 memset(&bv, 0, sizeof(bv));
664 bv.bv_bio.bio_cookie = bio_cookie;
665 bv.bv_volid = i;
666 if (ioctl(devh, BIOCVOL, &bv) == -1)
667 err(1, "BIOCVOL");
668
669 bio_status(&bv.bv_bio.bio_status);
670
671 if (name && strcmp(name, bv.bv_dev) != 0)
672 continue;
673 id = i;
674 break;
675 }
676
677 return (id);
678 }
679
680 void
bio_setstate(char * arg,int status,char * devicename)681 bio_setstate(char *arg, int status, char *devicename)
682 {
683 struct bioc_setstate bs;
684 struct locator location;
685 struct stat sb;
686 const char *errstr;
687
688 memset(&bs, 0, sizeof(bs));
689 if (stat(arg, &sb) == -1) {
690 /* use CTL */
691 errstr = str2locator(arg, &location);
692 if (errstr)
693 errx(1, "Target %s: %s", arg, errstr);
694 bs.bs_channel = location.channel;
695 bs.bs_target = location.target;
696 bs.bs_lun = location.lun;
697 } else {
698 /* use other id */
699 bs.bs_other_id = sb.st_rdev;
700 bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
701 }
702
703 bs.bs_bio.bio_cookie = bio_cookie;
704 bs.bs_status = status;
705
706 if (status != BIOC_SSHOTSPARE) {
707 /* make sure user supplied a sd device */
708 bs.bs_volid = bio_getvolbyname(devicename);
709 if (bs.bs_volid == -1)
710 errx(1, "invalid device %s", devicename);
711 }
712
713 if (ioctl(devh, BIOCSETSTATE, &bs) == -1)
714 err(1, "BIOCSETSTATE");
715
716 bio_status(&bs.bs_bio.bio_status);
717 }
718
719 void
bio_setblink(char * name,char * arg,int blink)720 bio_setblink(char *name, char *arg, int blink)
721 {
722 struct locator location;
723 struct bioc_blink bb;
724 struct bioc_inq bi;
725 struct bioc_vol bv;
726 struct bioc_disk bd;
727 const char *errstr;
728 int v, d, rv;
729
730 errstr = str2locator(arg, &location);
731 if (errstr)
732 errx(1, "Target %s: %s", arg, errstr);
733
734 /* try setting blink on the device directly */
735 memset(&bb, 0, sizeof(bb));
736 bb.bb_bio.bio_cookie = bio_cookie;
737 bb.bb_status = blink;
738 bb.bb_target = location.target;
739 bb.bb_channel = location.channel;
740 rv = ioctl(devh, BIOCBLINK, &bb);
741
742 if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_UNKNOWN)
743 return;
744
745 if (rv == 0 && bb.bb_bio.bio_status.bs_status == BIO_STATUS_SUCCESS) {
746 bio_status(&bb.bb_bio.bio_status);
747 return;
748 }
749
750 /* if the blink didn't work, try to find something that will */
751
752 memset(&bi, 0, sizeof(bi));
753 bi.bi_bio.bio_cookie = bio_cookie;
754 if (ioctl(devh, BIOCINQ, &bi) == -1)
755 err(1, "BIOCINQ");
756
757 bio_status(&bi.bi_bio.bio_status);
758
759 for (v = 0; v < bi.bi_novol; v++) {
760 memset(&bv, 0, sizeof(bv));
761 bv.bv_bio.bio_cookie = bio_cookie;
762 bv.bv_volid = v;
763 if (ioctl(devh, BIOCVOL, &bv) == -1)
764 err(1, "BIOCVOL");
765
766 bio_status(&bv.bv_bio.bio_status);
767
768 if (name && strcmp(name, bv.bv_dev) != 0)
769 continue;
770
771 for (d = 0; d < bv.bv_nodisk; d++) {
772 memset(&bd, 0, sizeof(bd));
773 bd.bd_bio.bio_cookie = bio_cookie;
774 bd.bd_volid = v;
775 bd.bd_diskid = d;
776
777 if (ioctl(devh, BIOCDISK, &bd) == -1)
778 err(1, "BIOCDISK");
779
780 bio_status(&bd.bd_bio.bio_status);
781
782 if (bd.bd_channel == location.channel &&
783 bd.bd_target == location.target &&
784 bd.bd_lun == location.lun) {
785 if (bd.bd_procdev[0] != '\0')
786 bio_blink(bd.bd_procdev,
787 location.target, blink);
788 else
789 warnx("Disk %s is not in an enclosure",
790 arg);
791 return;
792 }
793 }
794 }
795
796 warnx("Disk %s does not exist", arg);
797 }
798
799 void
bio_blink(char * enclosure,int target,int blinktype)800 bio_blink(char *enclosure, int target, int blinktype)
801 {
802 int bioh;
803 struct bio_locate bl;
804 struct bioc_blink blink;
805
806 bioh = open("/dev/bio", O_RDWR);
807 if (bioh == -1)
808 err(1, "Can't open %s", "/dev/bio");
809
810 memset(&bl, 0, sizeof(bl));
811 bl.bl_name = enclosure;
812 if (ioctl(bioh, BIOCLOCATE, &bl) == -1)
813 errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
814
815 memset(&blink, 0, sizeof(blink));
816 blink.bb_bio.bio_cookie = bio_cookie;
817 blink.bb_status = blinktype;
818 blink.bb_target = target;
819
820 if (ioctl(bioh, BIOCBLINK, &blink) == -1)
821 err(1, "BIOCBLINK");
822
823 bio_status(&blink.bb_bio.bio_status);
824
825 close(bioh);
826 }
827
828 void
bio_createraid(u_int16_t level,char * dev_list,char * key_disk)829 bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
830 {
831 struct bioc_createraid create;
832 struct sr_crypto_kdfinfo kdfinfo;
833 struct sr_crypto_pbkdf kdfhint;
834 struct stat sb;
835 int rv, no_dev, fd;
836 dev_t *dt;
837 u_int16_t min_disks = 0;
838
839 if (!dev_list)
840 errx(1, "no devices specified");
841
842 dt = calloc(1, BIOC_CRMAXLEN);
843 if (!dt)
844 err(1, "not enough memory for dev_t list");
845
846 no_dev = bio_parse_devlist(dev_list, dt);
847
848 switch (level) {
849 case 0:
850 min_disks = 2;
851 break;
852 case 1:
853 min_disks = 2;
854 break;
855 case 5:
856 min_disks = 3;
857 break;
858 case 'C':
859 case 0x1C:
860 min_disks = 1;
861 break;
862 case 'c':
863 min_disks = 1;
864 break;
865 default:
866 errx(1, "unsupported RAID level");
867 }
868
869 if (no_dev < min_disks)
870 errx(1, "not enough disks");
871
872 /* for crypto raid we only allow one single chunk */
873 if (level == 'C' && no_dev != min_disks)
874 errx(1, "not exactly one partition");
875
876 memset(&create, 0, sizeof(create));
877 create.bc_bio.bio_cookie = bio_cookie;
878 create.bc_level = level;
879 create.bc_dev_list_len = no_dev * sizeof(dev_t);
880 create.bc_dev_list = dt;
881 create.bc_flags = BIOC_SCDEVT | cflags;
882 create.bc_key_disk = NODEV;
883
884 if ((level == 'C' || level == 0x1C) && key_disk == NULL) {
885
886 memset(&kdfinfo, 0, sizeof(kdfinfo));
887 memset(&kdfhint, 0, sizeof(kdfhint));
888
889 create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
890
891 create.bc_opaque = &kdfhint;
892 create.bc_opaque_size = sizeof(kdfhint);
893 create.bc_opaque_flags = BIOC_SOOUT;
894
895 /* try to get KDF hint */
896 if (ioctl(devh, BIOCCREATERAID, &create) == -1)
897 err(1, "ioctl");
898
899 bio_status(&create.bc_bio.bio_status);
900
901 if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
902 bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
903 memset(&kdfhint, 0, sizeof(kdfhint));
904 } else {
905 bio_kdf_generate(&kdfinfo);
906 }
907
908 create.bc_opaque = &kdfinfo;
909 create.bc_opaque_size = sizeof(kdfinfo);
910 create.bc_opaque_flags = BIOC_SOIN;
911
912 } else if ((level == 'C' || level == 0x1C) && key_disk != NULL) {
913
914 /* Get device number for key disk. */
915 fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL);
916 if (fd == -1)
917 err(1, "could not open %s", key_disk);
918 if (fstat(fd, &sb) == -1) {
919 int saved_errno = errno;
920 close(fd);
921 errc(1, saved_errno, "could not stat %s", key_disk);
922 }
923 close(fd);
924 create.bc_key_disk = sb.st_rdev;
925
926 memset(&kdfinfo, 0, sizeof(kdfinfo));
927
928 kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf);
929 kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK;
930 kdfinfo.len = sizeof(kdfinfo);
931 kdfinfo.flags = SR_CRYPTOKDF_HINT;
932
933 create.bc_opaque = &kdfinfo;
934 create.bc_opaque_size = sizeof(kdfinfo);
935 create.bc_opaque_flags = BIOC_SOIN;
936
937 }
938
939 rv = ioctl(devh, BIOCCREATERAID, &create);
940 explicit_bzero(&kdfinfo, sizeof(kdfinfo));
941 if (rv == -1)
942 err(1, "BIOCCREATERAID");
943
944 bio_status(&create.bc_bio.bio_status);
945
946 free(dt);
947 }
948
949 void
bio_kdf_derive(struct sr_crypto_kdfinfo * kdfinfo,struct sr_crypto_pbkdf * kdfhint,char * prompt,int verify)950 bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_pbkdf
951 *kdfhint, char* prompt, int verify)
952 {
953 if (!kdfinfo)
954 errx(1, "invalid KDF info");
955 if (!kdfhint)
956 errx(1, "invalid KDF hint");
957
958 if (kdfhint->generic.len != sizeof(*kdfhint))
959 errx(1, "KDF hint has invalid size");
960
961 kdfinfo->flags = SR_CRYPTOKDF_KEY;
962 kdfinfo->len = sizeof(*kdfinfo);
963
964 derive_key(kdfhint->generic.type, kdfhint->rounds,
965 kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
966 kdfhint->salt, sizeof(kdfhint->salt),
967 prompt, verify);
968 }
969
970 void
bio_kdf_generate(struct sr_crypto_kdfinfo * kdfinfo)971 bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
972 {
973 if (!kdfinfo)
974 errx(1, "invalid KDF info");
975
976 if (rflag == -1)
977 rflag = bcrypt_pbkdf_autorounds();
978
979 kdfinfo->pbkdf.generic.len = sizeof(kdfinfo->pbkdf);
980 kdfinfo->pbkdf.generic.type = SR_CRYPTOKDFT_BCRYPT_PBKDF;
981 kdfinfo->pbkdf.rounds = rflag;
982
983 kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT;
984 kdfinfo->len = sizeof(*kdfinfo);
985
986 /* generate salt */
987 arc4random_buf(kdfinfo->pbkdf.salt, sizeof(kdfinfo->pbkdf.salt));
988
989 derive_key(kdfinfo->pbkdf.generic.type, kdfinfo->pbkdf.rounds,
990 kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
991 kdfinfo->pbkdf.salt, sizeof(kdfinfo->pbkdf.salt),
992 "New passphrase: ", interactive);
993 }
994
995 int
bio_parse_devlist(char * lst,dev_t * dt)996 bio_parse_devlist(char *lst, dev_t *dt)
997 {
998 char *s, *e;
999 u_int32_t sz = 0;
1000 int no_dev = 0, i, x;
1001 struct stat sb;
1002 char dev[PATH_MAX];
1003 int fd;
1004
1005 if (!lst)
1006 errx(1, "invalid device list");
1007
1008 s = e = lst;
1009 /* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
1010 while (*e != '\0') {
1011 if (*e == ',')
1012 s = e + 1;
1013 else if (*(e + 1) == '\0' || *(e + 1) == ',') {
1014 /* got one */
1015 sz = e - s + 1;
1016 strlcpy(dev, s, sz + 1);
1017 fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL);
1018 if (fd == -1)
1019 err(1, "could not open %s", dev);
1020 if (fstat(fd, &sb) == -1) {
1021 int saved_errno = errno;
1022 close(fd);
1023 errc(1, saved_errno, "could not stat %s", dev);
1024 }
1025 close(fd);
1026 dt[no_dev] = sb.st_rdev;
1027 no_dev++;
1028 if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
1029 errx(1, "too many devices on device list");
1030 }
1031 e++;
1032 }
1033
1034 for (i = 0; i < no_dev; i++)
1035 for (x = 0; x < no_dev; x++)
1036 if (dt[i] == dt[x] && x != i)
1037 errx(1, "duplicate device in list");
1038
1039 return (no_dev);
1040 }
1041
1042 u_int32_t
bio_createflags(char * lst)1043 bio_createflags(char *lst)
1044 {
1045 char *s, *e, fs[32];
1046 u_int32_t sz = 0;
1047 u_int32_t flags = 0;
1048
1049 if (!lst)
1050 errx(1, "invalid flags list");
1051
1052 s = e = lst;
1053 /* make sure we have a valid flags list like force,noassemeble */
1054 while (*e != '\0') {
1055 if (*e == ',')
1056 s = e + 1;
1057 else if (*(e + 1) == '\0' || *(e + 1) == ',') {
1058 /* got one */
1059 sz = e - s + 1;
1060 switch (s[0]) {
1061 case 'f':
1062 flags |= BIOC_SCFORCE;
1063 break;
1064 case 'n':
1065 flags |= BIOC_SCNOAUTOASSEMBLE;
1066 break;
1067 default:
1068 strlcpy(fs, s, sz + 1);
1069 errx(1, "invalid flag %s", fs);
1070 }
1071 }
1072 e++;
1073 }
1074
1075 return (flags);
1076 }
1077
1078 void
bio_deleteraid(char * dev)1079 bio_deleteraid(char *dev)
1080 {
1081 struct bioc_deleteraid bd;
1082 memset(&bd, 0, sizeof(bd));
1083
1084 bd.bd_bio.bio_cookie = bio_cookie;
1085 /* XXX make this a dev_t instead of a string */
1086 strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
1087 if (ioctl(devh, BIOCDELETERAID, &bd) == -1)
1088 err(1, "BIOCDELETERAID");
1089
1090 bio_status(&bd.bd_bio.bio_status);
1091 }
1092
1093 void
bio_changepass(char * dev)1094 bio_changepass(char *dev)
1095 {
1096 struct bioc_discipline bd;
1097 struct sr_crypto_kdfpair kdfpair;
1098 struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
1099 struct sr_crypto_pbkdf kdfhint;
1100 int rv;
1101
1102 memset(&bd, 0, sizeof(bd));
1103 memset(&kdfhint, 0, sizeof(kdfhint));
1104 memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1105 memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1106
1107 /* XXX use dev_t instead of string. */
1108 strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
1109 bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
1110 bd.bd_size = sizeof(kdfhint);
1111 bd.bd_data = &kdfhint;
1112
1113 if (ioctl(devh, BIOCDISCIPLINE, &bd) == -1)
1114 err(1, "BIOCDISCIPLINE");
1115
1116 bio_status(&bd.bd_bio.bio_status);
1117
1118 /* Current passphrase. */
1119 bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
1120
1121 if (rflag == -1) {
1122 rflag = bcrypt_pbkdf_autorounds();
1123
1124 /* Use previous number of rounds for the same KDF if higher. */
1125 if (kdfhint.generic.type == SR_CRYPTOKDFT_BCRYPT_PBKDF &&
1126 rflag < kdfhint.rounds)
1127 rflag = kdfhint.rounds;
1128 }
1129
1130 /* New passphrase. */
1131 bio_kdf_generate(&kdfinfo2);
1132
1133 kdfpair.kdfinfo1 = &kdfinfo1;
1134 kdfpair.kdfsize1 = sizeof(kdfinfo1);
1135 kdfpair.kdfinfo2 = &kdfinfo2;
1136 kdfpair.kdfsize2 = sizeof(kdfinfo2);
1137
1138 bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
1139 bd.bd_size = sizeof(kdfpair);
1140 bd.bd_data = &kdfpair;
1141
1142 rv = ioctl(devh, BIOCDISCIPLINE, &bd);
1143
1144 memset(&kdfhint, 0, sizeof(kdfhint));
1145 explicit_bzero(&kdfinfo1, sizeof(kdfinfo1));
1146 explicit_bzero(&kdfinfo2, sizeof(kdfinfo2));
1147
1148 if (rv == -1)
1149 err(1, "BIOCDISCIPLINE");
1150
1151 bio_status(&bd.bd_bio.bio_status);
1152 }
1153
1154 #define BIOCTL_VIS_NBUF 4
1155 #define BIOCTL_VIS_BUFLEN 80
1156
1157 char *
bio_vis(char * s)1158 bio_vis(char *s)
1159 {
1160 static char rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
1161 static uint idx = 0;
1162 char *buf;
1163
1164 buf = rbuf[idx++];
1165 if (idx == BIOCTL_VIS_NBUF)
1166 idx = 0;
1167
1168 strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
1169 return (buf);
1170 }
1171
1172 void
bio_diskinq(char * sd_dev)1173 bio_diskinq(char *sd_dev)
1174 {
1175 struct dk_inquiry di;
1176
1177 if (ioctl(devh, DIOCINQ, &di) == -1)
1178 err(1, "DIOCINQ");
1179
1180 printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
1181 bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
1182 }
1183
1184 void
bio_patrol(char * arg)1185 bio_patrol(char *arg)
1186 {
1187 struct bioc_patrol bp;
1188 struct timing timing;
1189 const char *errstr;
1190
1191 memset(&bp, 0, sizeof(bp));
1192 bp.bp_bio.bio_cookie = bio_cookie;
1193
1194 switch (arg[0]) {
1195 case 'a':
1196 bp.bp_opcode = BIOC_SPAUTO;
1197 break;
1198
1199 case 'm':
1200 bp.bp_opcode = BIOC_SPMANUAL;
1201 break;
1202
1203 case 'd':
1204 bp.bp_opcode = BIOC_SPDISABLE;
1205 break;
1206
1207 case 'g': /* get patrol state */
1208 bp.bp_opcode = BIOC_GPSTATUS;
1209 break;
1210
1211 case 's': /* start/stop patrol */
1212 if (strncmp("sta", arg, 3) == 0)
1213 bp.bp_opcode = BIOC_SPSTART;
1214 else
1215 bp.bp_opcode = BIOC_SPSTOP;
1216 break;
1217
1218 default:
1219 errx(1, "invalid patrol function: %s", arg);
1220 }
1221
1222 switch (arg[0]) {
1223 case 'a':
1224 errstr = str2patrol(arg, &timing);
1225 if (errstr)
1226 errx(1, "Patrol %s: %s", arg, errstr);
1227 bp.bp_autoival = timing.interval;
1228 bp.bp_autonext = timing.start;
1229 break;
1230 }
1231
1232 if (ioctl(devh, BIOCPATROL, &bp) == -1)
1233 err(1, "BIOCPATROL");
1234
1235 bio_status(&bp.bp_bio.bio_status);
1236
1237 if (arg[0] == 'g') {
1238 const char *mode, *status;
1239 char interval[40];
1240
1241 interval[0] = '\0';
1242
1243 switch (bp.bp_mode) {
1244 case BIOC_SPMAUTO:
1245 mode = "auto";
1246 snprintf(interval, sizeof interval,
1247 " interval=%d next=%d", bp.bp_autoival,
1248 bp.bp_autonext - bp.bp_autonow);
1249 break;
1250 case BIOC_SPMMANUAL:
1251 mode = "manual";
1252 break;
1253 case BIOC_SPMDISABLED:
1254 mode = "disabled";
1255 break;
1256 default:
1257 mode = "unknown";
1258 break;
1259 }
1260 switch (bp.bp_status) {
1261 case BIOC_SPSSTOPPED:
1262 status = "stopped";
1263 break;
1264 case BIOC_SPSREADY:
1265 status = "ready";
1266 break;
1267 case BIOC_SPSACTIVE:
1268 status = "active";
1269 break;
1270 case BIOC_SPSABORTED:
1271 status = "aborted";
1272 break;
1273 default:
1274 status = "unknown";
1275 break;
1276 }
1277 printf("patrol mode: %s%s\n", mode, interval);
1278 printf("patrol status: %s\n", status);
1279 }
1280 }
1281
1282 /*
1283 * Measure this system's performance by measuring the time for 100 rounds.
1284 * We are aiming for something that takes around 1s.
1285 */
1286 int
bcrypt_pbkdf_autorounds(void)1287 bcrypt_pbkdf_autorounds(void)
1288 {
1289 struct timespec before, after;
1290 char buf[SR_CRYPTO_MAXKEYBYTES], salt[128];
1291 int r = 100;
1292 int duration;
1293
1294 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before);
1295 if (bcrypt_pbkdf("testpassword", strlen("testpassword"),
1296 salt, sizeof(salt), buf, sizeof(buf), r) != 0)
1297 errx(1, "bcrypt pbkdf failed");
1298 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after);
1299
1300 duration = after.tv_sec - before.tv_sec;
1301 duration *= 1000000;
1302 duration += (after.tv_nsec - before.tv_nsec) / 1000;
1303
1304 duration /= r;
1305 r = 1000000 / duration;
1306
1307 if (r < 16)
1308 r = 16;
1309
1310 return r;
1311 }
1312
1313 void
derive_key(u_int32_t type,int rounds,u_int8_t * key,size_t keysz,u_int8_t * salt,size_t saltsz,char * prompt,int verify)1314 derive_key(u_int32_t type, int rounds, u_int8_t *key, size_t keysz,
1315 u_int8_t *salt, size_t saltsz, char *prompt, int verify)
1316 {
1317 FILE *f;
1318 size_t pl;
1319 struct stat sb;
1320 char passphrase[1024], verifybuf[1024];
1321 int rpp_flag = RPP_ECHO_OFF;
1322
1323 if (!key)
1324 errx(1, "Invalid key");
1325 if (!salt)
1326 errx(1, "Invalid salt");
1327
1328 if (type != SR_CRYPTOKDFT_PKCS5_PBKDF2 &&
1329 type != SR_CRYPTOKDFT_BCRYPT_PBKDF)
1330 errx(1, "unknown KDF type %d", type);
1331
1332 if (rounds < (type == SR_CRYPTOKDFT_PKCS5_PBKDF2 ? 1000 : 16))
1333 errx(1, "number of KDF rounds is too small: %d", rounds);
1334
1335 /* get passphrase */
1336 if (passfile) {
1337 if ((f = fopen(passfile, "r")) == NULL)
1338 err(1, "invalid passphrase file");
1339
1340 if (fstat(fileno(f), &sb) == -1)
1341 err(1, "can't stat passphrase file");
1342 if (sb.st_uid != 0)
1343 errx(1, "passphrase file must be owned by root");
1344 if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR))
1345 errx(1, "passphrase file has the wrong permissions");
1346
1347 if (fgets(passphrase, sizeof(passphrase), f) == NULL)
1348 err(1, "can't read passphrase file");
1349 pl = strlen(passphrase);
1350 if (pl > 0 && passphrase[pl - 1] == '\n')
1351 passphrase[pl - 1] = '\0';
1352 else
1353 errx(1, "invalid passphrase length");
1354
1355 fclose(f);
1356 } else {
1357 rpp_flag |= interactive ? RPP_REQUIRE_TTY : RPP_STDIN;
1358
1359 retry:
1360 if (readpassphrase(prompt, passphrase, sizeof(passphrase),
1361 rpp_flag) == NULL)
1362 err(1, "unable to read passphrase");
1363 if (*passphrase == '\0') {
1364 warnx("invalid passphrase length");
1365 if (interactive)
1366 goto retry;
1367 exit(1);
1368 }
1369 }
1370
1371 if (verify && !passfile) {
1372 /* request user to re-type it */
1373 if (readpassphrase("Re-type passphrase: ", verifybuf,
1374 sizeof(verifybuf), rpp_flag) == NULL) {
1375 explicit_bzero(passphrase, sizeof(passphrase));
1376 err(1, "unable to read passphrase");
1377 }
1378 if ((strlen(passphrase) != strlen(verifybuf)) ||
1379 (strcmp(passphrase, verifybuf) != 0)) {
1380 explicit_bzero(passphrase, sizeof(passphrase));
1381 explicit_bzero(verifybuf, sizeof(verifybuf));
1382 if (interactive) {
1383 warnx("Passphrases did not match, try again");
1384 goto retry;
1385 }
1386 errx(1, "Passphrases did not match");
1387 }
1388 /* forget the re-typed one */
1389 explicit_bzero(verifybuf, sizeof(verifybuf));
1390 }
1391
1392 /* derive key from passphrase */
1393 if (type == SR_CRYPTOKDFT_PKCS5_PBKDF2) {
1394 if (verbose)
1395 printf("Deriving key using PKCS#5 PBKDF2 with %i rounds...\n",
1396 rounds);
1397 if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
1398 key, keysz, rounds) != 0)
1399 errx(1, "pkcs5_pbkdf2 failed");
1400 } else if (type == SR_CRYPTOKDFT_BCRYPT_PBKDF) {
1401 if (verbose)
1402 printf("Deriving key using bcrypt PBKDF with %i rounds...\n",
1403 rounds);
1404 if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, saltsz,
1405 key, keysz, rounds) != 0)
1406 errx(1, "bcrypt_pbkdf failed");
1407 } else {
1408 errx(1, "unknown KDF type %d", type);
1409 }
1410
1411 /* forget passphrase */
1412 explicit_bzero(passphrase, sizeof(passphrase));
1413 }
1414