xref: /openbsd-src/sbin/bioctl/bioctl.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /* $OpenBSD: bioctl.c,v 1.103 2011/08/01 08:23:52 matthieu 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/dkio.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <dev/biovar.h>
36 #include <dev/softraidvar.h>
37 
38 #include <errno.h>
39 #include <err.h>
40 #include <fcntl.h>
41 #include <util.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <ctype.h>
47 #include <vis.h>
48 #include <readpassphrase.h>
49 
50 #include "pbkdf2.h"
51 
52 struct locator {
53 	int		channel;
54 	int		target;
55 	int		lun;
56 };
57 
58 void			usage(void);
59 const char 		*str2locator(const char *, struct locator *);
60 void			cleanup(void);
61 int			bio_parse_devlist(char *, dev_t *);
62 void			bio_kdf_derive(struct sr_crypto_kdfinfo *,
63 			    struct sr_crypto_kdf_pbkdf2 *, char *, int);
64 void			bio_kdf_generate(struct sr_crypto_kdfinfo *);
65 void			derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *,
66 			    size_t, char *, int);
67 
68 void			bio_inq(char *);
69 void			bio_alarm(char *);
70 int			bio_getvolbyname(char *);
71 void			bio_setstate(char *, int, char *);
72 void			bio_setblink(char *, char *, int);
73 void			bio_blink(char *, int, int);
74 struct sr_aoe_config 	*create_aoe(u_int16_t, char *);
75 void			bio_createraid(u_int16_t, char *, char *);
76 void			bio_deleteraid(char *);
77 void			bio_changepass(char *);
78 u_int32_t		bio_createflags(char *);
79 char			*bio_vis(char *);
80 void			bio_diskinq(char *);
81 
82 int			devh = -1;
83 int			human;
84 int			verbose;
85 u_int32_t		cflags = 0;
86 int			rflag = 8192;
87 char			*password;
88 
89 struct bio_locate	bl;
90 int rpp_flag = RPP_REQUIRE_TTY;
91 
92 int
93 main(int argc, char *argv[])
94 {
95 	extern char		*optarg;
96 	u_int64_t		func = 0;
97 	/* u_int64_t subfunc = 0; */
98 	char			*devicename = NULL;
99 	char			*realname = NULL, *al_arg = NULL;
100 	char			*bl_arg = NULL, *dev_list = NULL;
101 	char			*key_disk = NULL;
102 	const char		*errstr;
103 	int			ch, rv, blink = 0, changepass = 0, diskinq = 0;
104 	int			ss_func = 0;
105 	u_int16_t		cr_level = 0;
106 	int			biodev = 0;
107 
108 	if (argc < 2)
109 		usage();
110 
111 	while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:Pp:qr:R:svu:")) !=
112 	    -1) {
113 		switch (ch) {
114 		case 'a': /* alarm */
115 			func |= BIOC_ALARM;
116 			al_arg = optarg;
117 			break;
118 		case 'b': /* blink */
119 			func |= BIOC_BLINK;
120 			blink = BIOC_SBBLINK;
121 			bl_arg = optarg;
122 			break;
123 		case 'C': /* creation flags */
124 			cflags = bio_createflags(optarg);
125 			break;
126 		case 'c': /* create */
127 			func |= BIOC_CREATERAID;
128 			if (isdigit(*optarg)) {
129 				cr_level = strtonum(optarg, 0, 10, &errstr);
130 				if (errstr != NULL)
131 					errx(1, "Invalid RAID level");
132 			} else
133 				cr_level = *optarg;
134 			break;
135 		case 'd':
136 			/* delete volume */
137 			func |= BIOC_DELETERAID;
138 			break;
139 		case 'u': /* unblink */
140 			func |= BIOC_BLINK;
141 			blink = BIOC_SBUNBLINK;
142 			bl_arg = optarg;
143 			break;
144 		case 'H': /* set hotspare */
145 			func |= BIOC_SETSTATE;
146 			ss_func = BIOC_SSHOTSPARE;
147 			al_arg = optarg;
148 			break;
149 		case 'h':
150 			human = 1;
151 			break;
152 		case 'i': /* inquiry */
153 			func |= BIOC_INQ;
154 			break;
155 		case 'k': /* Key disk. */
156 			key_disk = optarg;
157 			break;
158 		case 'l': /* device list */
159 			func |= BIOC_DEVLIST;
160 			dev_list = optarg;
161 			break;
162 		case 'P':
163 			/* Change passphrase. */
164 			changepass = 1;
165 			break;
166 		case 'p':
167 			password = optarg;
168 			break;
169 		case 'r':
170 			rflag = strtonum(optarg, 1000, 1<<30, &errstr);
171 			if (errstr != NULL)
172 				errx(1, "Number of rounds is %s: %s",
173 				    errstr, optarg);
174 			break;
175 		case 'R':
176 			/* rebuild to provided chunk/CTL */
177 			func |= BIOC_SETSTATE;
178 			ss_func = BIOC_SSREBUILD;
179 			al_arg = optarg;
180 			break;
181 		case 's':
182 			rpp_flag = RPP_STDIN;
183 			break;
184 		case 'v':
185 			verbose = 1;
186 			break;
187 		case 'q':
188 			diskinq = 1;
189 			break;
190 		default:
191 			usage();
192 			/* NOTREACHED */
193 		}
194 	}
195 	argc -= optind;
196 	argv += optind;
197 
198 	if (argc != 1 || (changepass && func != 0))
199 		usage();
200 
201 	if (func == 0)
202 		func |= BIOC_INQ;
203 
204 	devicename = argv[0];
205 	if (devicename == NULL)
206 		errx(1, "need device");
207 
208 	devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname);
209 	if (devh == -1) {
210 		devh = open("/dev/bio", O_RDWR);
211 		if (devh == -1)
212 			err(1, "Can't open %s", "/dev/bio");
213 
214 		bl.bl_name = devicename;
215 		rv = ioctl(devh, BIOCLOCATE, &bl);
216 		if (rv == -1)
217 			errx(1, "Can't locate %s device via %s",
218 			    bl.bl_name, "/dev/bio");
219 		biodev = 1;
220 		devicename = NULL;
221 	}
222 
223 	if (diskinq) {
224 		bio_diskinq(devicename);
225 	} else if (changepass && !biodev) {
226 		bio_changepass(devicename);
227 	} else if (func & BIOC_INQ) {
228 		bio_inq(devicename);
229 	} else if (func == BIOC_ALARM) {
230 		bio_alarm(al_arg);
231 	} else if (func == BIOC_BLINK) {
232 		bio_setblink(devicename, bl_arg, blink);
233 	} else if (func == BIOC_SETSTATE) {
234 		bio_setstate(al_arg, ss_func, argv[0]);
235 	} else if (func == BIOC_DELETERAID && !biodev) {
236 		bio_deleteraid(devicename);
237 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
238 		if (!(func & BIOC_CREATERAID))
239 			errx(1, "need -c parameter");
240 		if (!(func & BIOC_DEVLIST))
241 			errx(1, "need -l parameter");
242 		if (!biodev)
243 			errx(1, "must use bio device");
244 		bio_createraid(cr_level, dev_list, key_disk);
245 	}
246 
247 	return (0);
248 }
249 
250 void
251 usage(void)
252 {
253 	extern char		*__progname;
254 
255 	fprintf(stderr,
256 		"usage: %s [-hiqv] [-a alarm-function] "
257 		"[-b channel:target[.lun]]\n"
258 		"\t[-H channel:target[.lun]] "
259 		"[-R device | channel:target[.lun]]\n"
260 		"\t[-u channel:target[.lun]] "
261 		"device\n"
262 		"       %s [-dhiPqsv] "
263 		"[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n"
264 		"\t[-l special[,special,...]] [-p passfile]\n"
265 		"\t[-R device | channel:target[.lun]] [-r rounds] "
266 		"device\n", __progname, __progname);
267 
268 	exit(1);
269 }
270 
271 const char *
272 str2locator(const char *string, struct locator *location)
273 {
274 	const char		*errstr;
275 	char			parse[80], *targ, *lun;
276 
277 	strlcpy(parse, string, sizeof parse);
278 	targ = strchr(parse, ':');
279 	if (targ == NULL)
280 		return ("target not specified");
281 	*targ++ = '\0';
282 
283 	lun = strchr(targ, '.');
284 	if (lun != NULL) {
285 		*lun++ = '\0';
286 		location->lun = strtonum(lun, 0, 256, &errstr);
287 		if (errstr)
288 			return (errstr);
289 	} else
290 		location->lun = 0;
291 
292 	location->target = strtonum(targ, 0, 256, &errstr);
293 	if (errstr)
294 		return (errstr);
295 	location->channel = strtonum(parse, 0, 256, &errstr);
296 	if (errstr)
297 		return (errstr);
298 	return (NULL);
299 }
300 
301 void
302 bio_inq(char *name)
303 {
304 	char 			*status, size[64], scsiname[16], volname[32];
305 	char			percent[10], seconds[20];
306 	int			rv, i, d, volheader, hotspare, unused;
307 	char			encname[16], serial[32];
308 	struct bioc_disk	bd;
309 	struct bioc_inq		bi;
310 	struct bioc_vol		bv;
311 
312 	memset(&bi, 0, sizeof(bi));
313 
314 	bi.bi_cookie = bl.bl_cookie;
315 
316 	rv = ioctl(devh, BIOCINQ, &bi);
317 	if (rv == -1) {
318 		if (errno == ENOTTY)
319 			bio_diskinq(name);
320 		else
321 			err(1, "BIOCINQ");
322 		return;
323 	}
324 
325 	volheader = 0;
326 	for (i = 0; i < bi.bi_novol; i++) {
327 		memset(&bv, 0, sizeof(bv));
328 		bv.bv_cookie = bl.bl_cookie;
329 		bv.bv_volid = i;
330 		bv.bv_percent = -1;
331 		bv.bv_seconds = 0;
332 
333 		rv = ioctl(devh, BIOCVOL, &bv);
334 		if (rv == -1)
335 			err(1, "BIOCVOL");
336 
337 		if (name && strcmp(name, bv.bv_dev) != 0)
338 			continue;
339 
340 		if (!volheader) {
341 			volheader = 1;
342 			printf("%-11s %-10s %14s %-8s\n",
343 			    "Volume", "Status", "Size", "Device");
344 		}
345 
346 		percent[0] = '\0';
347 		seconds[0] = '\0';
348 		if (bv.bv_percent != -1)
349 			snprintf(percent, sizeof percent,
350 			    " %d%% done", bv.bv_percent);
351 		if (bv.bv_seconds)
352 			snprintf(seconds, sizeof seconds,
353 			    " %u seconds", bv.bv_seconds);
354 		switch (bv.bv_status) {
355 		case BIOC_SVONLINE:
356 			status = BIOC_SVONLINE_S;
357 			break;
358 		case BIOC_SVOFFLINE:
359 			status = BIOC_SVOFFLINE_S;
360 			break;
361 		case BIOC_SVDEGRADED:
362 			status = BIOC_SVDEGRADED_S;
363 			break;
364 		case BIOC_SVBUILDING:
365 			status = BIOC_SVBUILDING_S;
366 			break;
367 		case BIOC_SVREBUILD:
368 			status = BIOC_SVREBUILD_S;
369 			break;
370 		case BIOC_SVSCRUB:
371 			status = BIOC_SVSCRUB_S;
372 			break;
373 		case BIOC_SVINVALID:
374 		default:
375 			status = BIOC_SVINVALID_S;
376 		}
377 
378 		snprintf(volname, sizeof volname, "%s %u",
379 		    bi.bi_dev, bv.bv_volid);
380 
381 		unused = 0;
382 		hotspare = 0;
383 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
384 			hotspare = 1;
385 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
386 			unused = 1;
387 		else {
388 			if (human)
389 				fmt_scaled(bv.bv_size, size);
390 			else
391 				snprintf(size, sizeof size, "%14llu",
392 				    bv.bv_size);
393 			switch (bv.bv_level) {
394 			case 'C':
395 				printf("%11s %-10s %14s %-7s CRYPTO%s%s\n",
396 				    volname, status, size, bv.bv_dev,
397 				    percent, seconds);
398 				break;
399 			default:
400 				printf("%11s %-10s %14s %-7s RAID%u%s%s\n",
401 				    volname, status, size, bv.bv_dev,
402 				    bv.bv_level, percent, seconds);
403 				break;
404 			}
405 
406 		}
407 
408 		for (d = 0; d < bv.bv_nodisk; d++) {
409 			memset(&bd, 0, sizeof(bd));
410 			bd.bd_cookie = bl.bl_cookie;
411 			bd.bd_diskid = d;
412 			bd.bd_volid = i;
413 
414 			rv = ioctl(devh, BIOCDISK, &bd);
415 			if (rv == -1)
416 				err(1, "BIOCDISK");
417 
418 			switch (bd.bd_status) {
419 			case BIOC_SDONLINE:
420 				status = BIOC_SDONLINE_S;
421 				break;
422 			case BIOC_SDOFFLINE:
423 				status = BIOC_SDOFFLINE_S;
424 				break;
425 			case BIOC_SDFAILED:
426 				status = BIOC_SDFAILED_S;
427 				break;
428 			case BIOC_SDREBUILD:
429 				status = BIOC_SDREBUILD_S;
430 				break;
431 			case BIOC_SDHOTSPARE:
432 				status = BIOC_SDHOTSPARE_S;
433 				break;
434 			case BIOC_SDUNUSED:
435 				status = BIOC_SDUNUSED_S;
436 				break;
437 			case BIOC_SDSCRUB:
438 				status = BIOC_SDSCRUB_S;
439 				break;
440 			case BIOC_SDINVALID:
441 			default:
442 				status = BIOC_SDINVALID_S;
443 			}
444 
445 			if (hotspare || unused)
446 				;	/* use volname from parent volume */
447 			else
448 				snprintf(volname, sizeof volname, "    %3u",
449 				    bd.bd_diskid);
450 
451 			if (bv.bv_level == 'C' && bd.bd_size == 0)
452 				snprintf(size, sizeof size, "%14s", "key disk");
453 			else if (human)
454 				fmt_scaled(bd.bd_size, size);
455 			else
456 				snprintf(size, sizeof size, "%14llu",
457 				    bd.bd_size);
458 			snprintf(scsiname, sizeof scsiname,
459 			    "%u:%u.%u",
460 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
461 			if (bd.bd_procdev[0])
462 				strlcpy(encname, bd.bd_procdev, sizeof encname);
463 			else
464 				strlcpy(encname, "noencl", sizeof encname);
465 			if (bd.bd_serial[0])
466 				strlcpy(serial, bd.bd_serial, sizeof serial);
467 			else
468 				strlcpy(serial, "unknown serial", sizeof serial);
469 
470 			printf("%11s %-10s %14s %-7s %-6s <%s>\n",
471 			    volname, status, size, scsiname, encname,
472 			    bd.bd_vendor);
473 			if (verbose)
474 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
475 				    "", "", "", "", "", serial);
476 		}
477 	}
478 }
479 
480 void
481 bio_alarm(char *arg)
482 {
483 	int			rv;
484 	struct bioc_alarm	ba;
485 
486 	ba.ba_cookie = bl.bl_cookie;
487 
488 	switch (arg[0]) {
489 	case 'q': /* silence alarm */
490 		/* FALLTHROUGH */
491 	case 's':
492 		ba.ba_opcode = BIOC_SASILENCE;
493 		break;
494 
495 	case 'e': /* enable alarm */
496 		ba.ba_opcode = BIOC_SAENABLE;
497 		break;
498 
499 	case 'd': /* disable alarm */
500 		ba.ba_opcode = BIOC_SADISABLE;
501 		break;
502 
503 	case 't': /* test alarm */
504 		ba.ba_opcode = BIOC_SATEST;
505 		break;
506 
507 	case 'g': /* get alarm state */
508 		ba.ba_opcode = BIOC_GASTATUS;
509 		break;
510 
511 	default:
512 		errx(1, "invalid alarm function: %s", arg);
513 	}
514 
515 	rv = ioctl(devh, BIOCALARM, &ba);
516 	if (rv == -1)
517 		err(1, "BIOCALARM");
518 
519 	if (arg[0] == 'g') {
520 		printf("alarm is currently %s\n",
521 		    ba.ba_status ? "enabled" : "disabled");
522 
523 	}
524 }
525 
526 int
527 bio_getvolbyname(char *name)
528 {
529 	int			id = -1, i, rv;
530 	struct bioc_inq		bi;
531 	struct bioc_vol		bv;
532 
533 	memset(&bi, 0, sizeof(bi));
534 	bi.bi_cookie = bl.bl_cookie;
535 	rv = ioctl(devh, BIOCINQ, &bi);
536 	if (rv == -1)
537 		err(1, "BIOCINQ");
538 
539 	for (i = 0; i < bi.bi_novol; i++) {
540 		memset(&bv, 0, sizeof(bv));
541 		bv.bv_cookie = bl.bl_cookie;
542 		bv.bv_volid = i;
543 		rv = ioctl(devh, BIOCVOL, &bv);
544 		if (rv == -1)
545 			err(1, "BIOCVOL");
546 
547 		if (name && strcmp(name, bv.bv_dev) != 0)
548 			continue;
549 		id = i;
550 		break;
551 	}
552 
553 	return (id);
554 }
555 
556 void
557 bio_setstate(char *arg, int status, char *devicename)
558 {
559 	struct bioc_setstate	bs;
560 	struct locator		location;
561 	struct stat		sb;
562 	const char		*errstr;
563 	int			rv;
564 
565 	memset(&bs, 0, sizeof(bs));
566 	if (stat(arg, &sb) == -1) {
567 		/* use CTL */
568 		errstr = str2locator(arg, &location);
569 		if (errstr)
570 			errx(1, "Target %s: %s", arg, errstr);
571 		bs.bs_channel = location.channel;
572 		bs.bs_target = location.target;
573 		bs.bs_lun = location.lun;
574 	} else {
575 		/* use other id */
576 		bs.bs_other_id = sb.st_rdev;
577 		bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
578 	}
579 
580 	bs.bs_cookie = bl.bl_cookie;
581 	bs.bs_status = status;
582 
583 	if (status != BIOC_SSHOTSPARE) {
584 		/* make sure user supplied a sd device */
585 		bs.bs_volid = bio_getvolbyname(devicename);
586 		if (bs.bs_volid == -1)
587 			errx(1, "invalid device %s", devicename);
588 	}
589 
590 	rv = ioctl(devh, BIOCSETSTATE, &bs);
591 	if (rv == -1)
592 		err(1, "BIOCSETSTATE");
593 }
594 
595 void
596 bio_setblink(char *name, char *arg, int blink)
597 {
598 	struct locator		location;
599 	struct bioc_inq		bi;
600 	struct bioc_vol		bv;
601 	struct bioc_disk	bd;
602 	struct bioc_blink	bb;
603 	const char		*errstr;
604 	int			v, d, rv;
605 
606 	errstr = str2locator(arg, &location);
607 	if (errstr)
608 		errx(1, "Target %s: %s", arg, errstr);
609 
610 	/* try setting blink on the device directly */
611 	memset(&bb, 0, sizeof(bb));
612 	bb.bb_cookie = bl.bl_cookie;
613 	bb.bb_status = blink;
614 	bb.bb_target = location.target;
615 	bb.bb_channel = location.channel;
616 	rv = ioctl(devh, BIOCBLINK, &bb);
617 	if (rv == 0)
618 		return;
619 
620 	/* if the blink didn't work, try to find something that will */
621 
622 	memset(&bi, 0, sizeof(bi));
623 	bi.bi_cookie = bl.bl_cookie;
624 	rv = ioctl(devh, BIOCINQ, &bi);
625 	if (rv == -1)
626 		err(1, "BIOCINQ");
627 
628 	for (v = 0; v < bi.bi_novol; v++) {
629 		memset(&bv, 0, sizeof(bv));
630 		bv.bv_cookie = bl.bl_cookie;
631 		bv.bv_volid = v;
632 		rv = ioctl(devh, BIOCVOL, &bv);
633 		if (rv == -1)
634 			err(1, "BIOCVOL");
635 
636 		if (name && strcmp(name, bv.bv_dev) != 0)
637 			continue;
638 
639 		for (d = 0; d < bv.bv_nodisk; d++) {
640 			memset(&bd, 0, sizeof(bd));
641 			bd.bd_cookie = bl.bl_cookie;
642 			bd.bd_volid = v;
643 			bd.bd_diskid = d;
644 
645 			rv = ioctl(devh, BIOCDISK, &bd);
646 			if (rv == -1)
647 				err(1, "BIOCDISK");
648 
649 			if (bd.bd_channel == location.channel &&
650 			    bd.bd_target == location.target &&
651 			    bd.bd_lun == location.lun) {
652 				if (bd.bd_procdev[0] != '\0') {
653 					bio_blink(bd.bd_procdev,
654 					    location.target, blink);
655 				} else
656 					warnx("Disk %s is not in an enclosure", arg);
657 				return;
658 			}
659 		}
660 	}
661 
662 	warnx("Disk %s does not exist", arg);
663 	return;
664 }
665 
666 void
667 bio_blink(char *enclosure, int target, int blinktype)
668 {
669 	int			bioh;
670 	struct bio_locate	bio;
671 	struct bioc_blink	blink;
672 	int			rv;
673 
674 	bioh = open("/dev/bio", O_RDWR);
675 	if (bioh == -1)
676 		err(1, "Can't open %s", "/dev/bio");
677 
678 	bio.bl_name = enclosure;
679 	rv = ioctl(bioh, BIOCLOCATE, &bio);
680 	if (rv == -1)
681 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
682 
683 	memset(&blink, 0, sizeof(blink));
684 	blink.bb_cookie = bio.bl_cookie;
685 	blink.bb_status = blinktype;
686 	blink.bb_target = target;
687 
688 	rv = ioctl(bioh, BIOCBLINK, &blink);
689 	if (rv == -1)
690 		err(1, "BIOCBLINK");
691 
692 	close(bioh);
693 }
694 
695 struct sr_aoe_config *
696 create_aoe(u_int16_t level, char *dev_list)
697 {
698 	static struct sr_aoe_config sac;
699 	char *nic;
700 	char *dsteaddr;
701 	char *shelf;
702 	char *slot;
703 	struct ether_addr *eaddr;
704 	const char *errstr;
705 
706 	nic = dsteaddr = slot = shelf = 0;
707 
708 	memset(&sac, 0, sizeof(sac));
709 	nic = dev_list;
710 	dsteaddr = strchr(nic, ',');
711 	if (!dsteaddr)
712 		goto invalid;
713 	*dsteaddr++ = '\0';
714 	shelf = strchr(dsteaddr, ',');
715 	if (!shelf)
716 		goto invalid;
717 	*shelf++ = '\0';
718 	slot = strchr(shelf, ',');
719 	if (!slot)
720 		goto invalid;
721 	*slot++ = '\0';
722 	strlcpy(sac.nic, nic, sizeof(sac.nic));
723 	eaddr = ether_aton(dsteaddr);
724 	if (!eaddr)
725 		goto invalid;
726 	sac.dsteaddr = *eaddr;
727 	sac.shelf = htons(strtonum(shelf, 0, 0xfffe, &errstr));
728 	if (errstr)
729 		goto invalid;
730 	sac.slot = strtonum(slot, 0, 0xfe, &errstr);
731 	if (errstr)
732 		goto invalid;
733 
734 	return &sac;
735 invalid:
736 	errx(1, "invalid AOE dev list: use nic,dsteaddr,shelf,slot");
737 }
738 
739 void
740 bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
741 {
742 	struct bioc_createraid	create;
743 	struct sr_crypto_kdfinfo kdfinfo;
744 	struct sr_crypto_kdf_pbkdf2 kdfhint;
745 	struct sr_aoe_config	*sac;
746 	struct stat		sb;
747 	int			rv, no_dev, fd;
748 	dev_t			*dt;
749 	u_int16_t		min_disks = 0;
750 
751 	if (!dev_list)
752 		errx(1, "no devices specified");
753 
754 	if (level == 'a') {
755 		sac = create_aoe(level, dev_list);
756 		no_dev = 0;
757 		dt = NULL;
758 	} else  {
759 		dt = (dev_t *)malloc(BIOC_CRMAXLEN);
760 		if (!dt)
761 			err(1, "not enough memory for dev_t list");
762 		memset(dt, 0, BIOC_CRMAXLEN);
763 
764 		no_dev = bio_parse_devlist(dev_list, dt);
765 	}
766 
767 	switch (level) {
768 	case 0:
769 		min_disks = 2;
770 		break;
771 	case 1:
772 		min_disks = 2;
773 		break;
774 	case 4:
775 	case 5:
776 		min_disks = 3;
777 		break;
778 	case 'C':
779 		min_disks = 1;
780 		break;
781 	case 'c':
782 		min_disks = 1;
783 		break;
784 	case 'a':
785 		break;
786 	default:
787 		errx(1, "unsupported raid level");
788 	}
789 
790 	if (no_dev < min_disks)
791 		errx(1, "not enough disks");
792 
793 	/* for crypto raid we only allow one single chunk */
794 	if (level == 'C' && no_dev != min_disks)
795 		errx(1, "not exactly one partition");
796 
797 	memset(&create, 0, sizeof(create));
798 	create.bc_cookie = bl.bl_cookie;
799 	create.bc_level = level;
800 	create.bc_dev_list_len = no_dev * sizeof(dev_t);
801 	create.bc_dev_list = dt;
802 	create.bc_flags = BIOC_SCDEVT | cflags;
803 	create.bc_key_disk = NODEV;
804 
805 	if (level == 'a') {
806 		create.bc_opaque = sac;
807 		create.bc_opaque_size = sizeof(*sac);
808 		create.bc_opaque_flags = BIOC_SOIN;
809 	} else if (level == 'C' && key_disk == NULL) {
810 
811 		memset(&kdfinfo, 0, sizeof(kdfinfo));
812 		memset(&kdfhint, 0, sizeof(kdfhint));
813 
814 		create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
815 
816 		create.bc_opaque = &kdfhint;
817 		create.bc_opaque_size = sizeof(kdfhint);
818 		create.bc_opaque_flags = BIOC_SOOUT;
819 
820 		/* try to get KDF hint */
821 		if (ioctl(devh, BIOCCREATERAID, &create) == -1)
822 			err(1, "ioctl");
823 
824 		if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
825 			bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
826 			memset(&kdfhint, 0, sizeof(kdfhint));
827 		} else  {
828 			bio_kdf_generate(&kdfinfo);
829 		}
830 
831 		create.bc_opaque = &kdfinfo;
832 		create.bc_opaque_size = sizeof(kdfinfo);
833 		create.bc_opaque_flags = BIOC_SOIN;
834 
835 	} else if (level == 'C' && key_disk != NULL) {
836 
837 		/* Get device number for key disk. */
838 		fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL);
839 		if (fd == -1)
840 			err(1, "could not open %s", key_disk);
841 		if (fstat(fd, &sb) == -1) {
842 			close(fd);
843 			err(1, "could not stat %s", key_disk);
844 		}
845 		close(fd);
846 		create.bc_key_disk = sb.st_rdev;
847 
848 		memset(&kdfinfo, 0, sizeof(kdfinfo));
849 
850 		kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf);
851 		kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK;
852 		kdfinfo.len = sizeof(kdfinfo);
853 		kdfinfo.flags = SR_CRYPTOKDF_HINT;
854 
855 		create.bc_opaque = &kdfinfo;
856 		create.bc_opaque_size = sizeof(kdfinfo);
857 		create.bc_opaque_flags = BIOC_SOIN;
858 
859 	}
860 
861 	rv = ioctl(devh, BIOCCREATERAID, &create);
862 	memset(&kdfinfo, 0, sizeof(kdfinfo));
863 	memset(&create, 0, sizeof(create));
864 	if (rv == -1) {
865 		if (errno == EPERM)
866 			errx(1, "Incorrect passphrase");
867 		err(1, "BIOCCREATERAID");
868 	}
869 
870 	free(dt);
871 }
872 
873 void
874 bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
875     *kdfhint, char* prompt, int verify)
876 {
877 	if (!kdfinfo)
878 		errx(1, "invalid KDF info");
879 	if (!kdfhint)
880 		errx(1, "invalid KDF hint");
881 
882 	if (kdfhint->len != sizeof(*kdfhint))
883 		errx(1, "KDF hint has invalid size");
884 	if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2)
885 		errx(1, "unknown KDF type %d", kdfhint->type);
886 	if (kdfhint->rounds < 1000)
887 		errx(1, "number of KDF rounds too low: %d", kdfhint->rounds);
888 
889 	kdfinfo->flags = SR_CRYPTOKDF_KEY;
890 	kdfinfo->len = sizeof(*kdfinfo);
891 
892 	derive_key_pkcs(kdfhint->rounds,
893 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
894 	    kdfhint->salt, sizeof(kdfhint->salt), prompt, verify);
895 }
896 
897 void
898 bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
899 {
900 	if (!kdfinfo)
901 		errx(1, "invalid KDF info");
902 
903 	kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2);
904 	kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2;
905 	kdfinfo->pbkdf2.rounds = rflag;
906 	kdfinfo->len = sizeof(*kdfinfo);
907 	kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT;
908 
909 	/* generate salt */
910 	arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt));
911 
912 	derive_key_pkcs(kdfinfo->pbkdf2.rounds,
913 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
914 	    kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt),
915 	    "New passphrase: ", 1);
916 }
917 
918 int
919 bio_parse_devlist(char *lst, dev_t *dt)
920 {
921 	char			*s, *e;
922 	u_int32_t		sz = 0;
923 	int			no_dev = 0, i, x;
924 	struct stat		sb;
925 	char			dev[MAXPATHLEN];
926 	int			fd;
927 
928 	if (!lst)
929 		errx(1, "invalid device list");
930 
931 	s = e = lst;
932 	/* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
933 	while (*e != '\0') {
934 		if (*e == ',')
935 			s = e + 1;
936 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
937 			/* got one */
938 			sz = e - s + 1;
939 			strlcpy(dev, s, sz + 1);
940 			fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL);
941 			if (fd == -1)
942 				err(1, "could not open %s", dev);
943 			if (fstat(fd, &sb) == -1) {
944 				close(fd);
945 				err(1, "could not stat %s", dev);
946 			}
947 			close(fd);
948 			dt[no_dev] = sb.st_rdev;
949 			no_dev++;
950 			if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
951 				errx(1, "too many devices on device list");
952 		}
953 		e++;
954 	}
955 
956 	for (i = 0; i < no_dev; i++)
957 		for (x = 0; x < no_dev; x++)
958 			if (dt[i] == dt[x] && x != i)
959 				errx(1, "duplicate device in list");
960 
961 	return (no_dev);
962 }
963 
964 u_int32_t
965 bio_createflags(char *lst)
966 {
967 	char			*s, *e, fs[32];
968 	u_int32_t		sz = 0;
969 	u_int32_t		flags = 0;
970 
971 	if (!lst)
972 		errx(1, "invalid flags list");
973 
974 	s = e = lst;
975 	/* make sure we have a valid flags list like force,noassemeble */
976 	while (*e != '\0') {
977 		if (*e == ',')
978 			s = e + 1;
979 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
980 			/* got one */
981 			sz = e - s + 1;
982 			switch (s[0]) {
983 			case 'f':
984 				flags |= BIOC_SCFORCE;
985 				break;
986 			case 'n':
987 				flags |= BIOC_SCNOAUTOASSEMBLE;
988 				break;
989 			default:
990 				strlcpy(fs, s, sz + 1);
991 				errx(1, "invalid flag %s", fs);
992 			}
993 		}
994 		e++;
995 	}
996 
997 	return (flags);
998 }
999 
1000 void
1001 bio_deleteraid(char *dev)
1002 {
1003 	struct bioc_deleteraid	bd;
1004 	memset(&bd, 0, sizeof(bd));
1005 
1006 	bd.bd_cookie = bd.bd_cookie;
1007 	/* XXX make this a dev_t instead of a string */
1008 	strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
1009 	if (ioctl(devh, BIOCDELETERAID, &bd))
1010 		errx(1, "delete volume %s failed", dev);
1011 }
1012 
1013 void
1014 bio_changepass(char *dev)
1015 {
1016 	struct bioc_discipline bd;
1017 	struct sr_crypto_kdfpair kdfpair;
1018 	struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
1019 	struct sr_crypto_kdf_pbkdf2 kdfhint;
1020 	int rv;
1021 
1022 	memset(&bd, 0, sizeof(bd));
1023 	memset(&kdfhint, 0, sizeof(kdfhint));
1024 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1025 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1026 
1027 	/* XXX use dev_t instead of string. */
1028 	strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
1029 	bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
1030 	bd.bd_size = sizeof(kdfhint);
1031 	bd.bd_data = &kdfhint;
1032 
1033 	if (ioctl(devh, BIOCDISCIPLINE, &bd))
1034 		errx(1, "%s: failed to get KDF hint", dev);
1035 
1036 	/* Current passphrase. */
1037 	bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
1038 
1039 	/* New passphrase. */
1040 	bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1);
1041 
1042 	kdfpair.kdfinfo1 = &kdfinfo1;
1043 	kdfpair.kdfsize1 = sizeof(kdfinfo1);
1044 	kdfpair.kdfinfo2 = &kdfinfo2;
1045 	kdfpair.kdfsize2 = sizeof(kdfinfo2);
1046 
1047 	bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
1048 	bd.bd_size = sizeof(kdfpair);
1049 	bd.bd_data = &kdfpair;
1050 
1051 	rv = ioctl(devh, BIOCDISCIPLINE, &bd);
1052 
1053 	memset(&kdfhint, 0, sizeof(kdfhint));
1054 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1055 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1056 
1057 	if (rv) {
1058 		if (errno == EPERM)
1059 			errx(1, "%s: incorrect passphrase", dev);
1060 		else
1061 			errx(1, "%s: failed to change passphrase", dev);
1062 	}
1063 }
1064 
1065 #define BIOCTL_VIS_NBUF		4
1066 #define BIOCTL_VIS_BUFLEN	80
1067 
1068 char *
1069 bio_vis(char *s)
1070 {
1071 	static char	 rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
1072 	static uint	 idx = 0;
1073 	char		*buf;
1074 
1075 	buf = rbuf[idx++];
1076 	if (idx == BIOCTL_VIS_NBUF)
1077 		idx = 0;
1078 
1079 	strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
1080 	return (buf);
1081 }
1082 
1083 void
1084 bio_diskinq(char *sd_dev)
1085 {
1086 	struct dk_inquiry	di;
1087 
1088 	if (ioctl(devh, DIOCINQ, &di) == -1)
1089 		err(1, "DIOCINQ");
1090 
1091 	printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
1092 	    bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
1093 }
1094 
1095 void
1096 derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
1097     size_t saltsz, char *prompt, int verify)
1098 {
1099 	FILE		*f;
1100 	size_t		pl;
1101 	struct stat	sb;
1102 	char		passphrase[1024], verifybuf[1024];
1103 
1104 	if (!key)
1105 		errx(1, "Invalid key");
1106 	if (!salt)
1107 		errx(1, "Invalid salt");
1108 	if (rounds < 1000)
1109 		errx(1, "Too few rounds: %d", rounds);
1110 
1111 	/* get passphrase */
1112 	if (password && verify)
1113 		errx(1, "can't specify passphrase file during initial "
1114 		    "creation of crypto volume");
1115 	if (password) {
1116 		if ((f = fopen(password, "r")) == NULL)
1117 			err(1, "invalid passphrase file");
1118 
1119 		if (fstat(fileno(f), &sb) == -1)
1120 			err(1, "can't stat passphrase file");
1121 		if (sb.st_uid != 0)
1122 			errx(1, "passphrase file must be owned by root");
1123 		if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR))
1124 			errx(1, "passphrase file has the wrong permissions");
1125 
1126 		if (fgets(passphrase, sizeof(passphrase), f) == NULL)
1127 			err(1, "can't read passphrase file");
1128 		pl = strlen(passphrase);
1129 		if (pl > 0 && passphrase[pl - 1] == '\n')
1130 			passphrase[pl - 1] = '\0';
1131 		else
1132 			errx(1, "invalid passphrase length");
1133 
1134 		fclose(f);
1135 	} else {
1136 		if (readpassphrase(prompt, passphrase, sizeof(passphrase),
1137 		    rpp_flag) == NULL)
1138 			errx(1, "unable to read passphrase");
1139 	}
1140 
1141 	if (verify) {
1142 		/* request user to re-type it */
1143 		if (readpassphrase("Re-type passphrase: ", verifybuf,
1144 		    sizeof(verifybuf), rpp_flag) == NULL) {
1145 			memset(passphrase, 0, sizeof(passphrase));
1146 			errx(1, "unable to read passphrase");
1147 		}
1148 		if ((strlen(passphrase) != strlen(verifybuf)) ||
1149 		    (strcmp(passphrase, verifybuf) != 0)) {
1150 			memset(passphrase, 0, sizeof(passphrase));
1151 			memset(verifybuf, 0, sizeof(verifybuf));
1152 			errx(1, "Passphrases did not match");
1153 		}
1154 		/* forget the re-typed one */
1155 		memset(verifybuf, 0, strlen(verifybuf));
1156 	}
1157 
1158 	/* derive key from passphrase */
1159 	if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
1160 	    key, keysz, rounds) != 0)
1161 		errx(1, "pbkdf2 failed");
1162 
1163 	/* forget passphrase */
1164 	memset(passphrase, 0, sizeof(passphrase));
1165 
1166 	return;
1167 }
1168