1 /**	$MirOS: src/usr.sbin/vnconfig/vnconfig.c,v 1.15 2010/09/21 21:24:49 tg Exp $ */
2 /*	$OpenBSD: vnconfig.c,v 1.16 2004/09/14 22:35:51 deraadt Exp $	*/
3 /*
4  * Copyright (c) 2006, 2010 Thorsten Glaser
5  * Copyright (c) 1993 University of Utah.
6  * Copyright (c) 1990, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * the Systems Programming Group of the University of Utah Computer
11  * Science Department.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
38  *
39  *	@(#)vnconfig.c	8.1 (Berkeley) 12/15/93
40  */
41 
42 #include <sys/param.h>
43 #include <sys/ioctl.h>
44 #include <sys/mount.h>
45 #include <sys/stat.h>
46 
47 #include <dev/vndioctl.h>
48 
49 #include <err.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <pwd.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <util.h>
58 
59 #ifndef SMALL
60 #include <openssl/asn1.h>
61 #include <openssl/err.h>
62 #include <openssl/evp.h>
63 #include <openssl/pem.h>
64 #endif
65 
66 __RCSID("$MirOS: src/usr.sbin/vnconfig/vnconfig.c,v 1.15 2010/09/21 21:24:49 tg Exp $");
67 
68 #define DEFAULT_VND	"vnd0"
69 
70 #define VND_CONFIG	1
71 #define VND_UNCONFIG	2
72 #define VND_GET		3
73 #define VND_MAKEKEY	4
74 
75 #define BLF_MAX_BYTES	72
76 
77 int verbose = 0;
78 
79 __dead void usage(void);
80 int config(char *, char *, int, char *, size_t, u_int32_t);
81 int getinfo(const char *);
82 #ifndef SMALL
83 static void extract_key(FILE *, char **, int *);
84 static int make_key(const char *, FILE *, const char *);
85 #endif
86 
87 int
main(int argc,char ** argv)88 main(int argc, char **argv)
89 {
90 	int ch, rv, action = VND_CONFIG, flags = 0, keylen = 0;
91 	char *key = NULL;
92 #ifndef SMALL
93 	char *key2 = NULL, *keyfile = NULL, *algo = NULL;
94 	FILE *keyfp = NULL;
95 #endif
96 
97 	while ((ch = getopt(argc, argv, "cf:K:klruv")) != -1) {
98 		switch (ch) {
99 		case 'c':
100 			action = VND_CONFIG;
101 			break;
102 #ifndef SMALL
103 		case 'f':
104 			keyfile = optarg;
105 			break;
106 		case 'K':
107 			action = VND_MAKEKEY;
108 			algo = optarg;
109 			break;
110 #endif
111 		case 'l':
112 			action = VND_GET;
113 			break;
114 		case 'u':
115 			action = VND_UNCONFIG;
116 			break;
117 		case 'v':
118 			verbose = 1;
119 			break;
120 		case 'k':
121 			key = getpass("Encryption key: ");
122 			if (key == NULL)
123 				errx(1, "getpass");
124 			keylen = strlen(key);
125 			break;
126 		case 'r':
127 			flags |= VNDIOC_OPT_RDONLY;
128 			break;
129 		default:
130 			usage();
131 			/* NOTREACHED */
132 		}
133 	}
134 
135 	argc -= optind;
136 	argv += optind;
137 
138 #ifndef SMALL
139 	if (keyfile) {
140 		keyfp = fopen(keyfile, (action == VND_MAKEKEY) ? "wb" : "rb");
141 		if (keyfp == NULL)
142 			err(1, "fopen");
143 		if (action != VND_MAKEKEY)
144 			extract_key(keyfp, &key, &keylen);
145 	}
146 
147 	if (key && action == VND_MAKEKEY) {
148 		key2 = getpass("repeat the key: ");
149 		if (memcmp(key, key2, 1+keylen))
150 			errx(1, "keys not identical");
151 	}
152 #endif
153 
154 	if (action == VND_CONFIG && argc == 2)
155 		rv = config(argv[0], argv[1], action, key, keylen,
156 		    flags);
157 	else if (action == VND_UNCONFIG && argc == 1)
158 		rv = config(argv[0], NULL, action, key, keylen,
159 		    flags | VNDIOC_OPT_RDONLY);
160 	else if (action == VND_GET)
161 		rv = getinfo(argc ? argv[0] : NULL);
162 #ifndef SMALL
163 	else if (action == VND_MAKEKEY)
164 		rv = make_key(algo, keyfp, key2);
165 #endif
166 	else
167 		usage();
168 
169 #ifndef SMALL
170 	if (keyfp)
171 		fclose(keyfp);
172 #endif
173 	return (rv);
174 }
175 
176 int
getinfo(const char * vname)177 getinfo(const char *vname)
178 {
179 	int vd, print_all = 0;
180 	struct vnd_user vnu;
181 	char *vnamedup;
182 
183 	if (vname == NULL) {
184 		vname = DEFAULT_VND;
185 		print_all = 1;
186 	}
187 
188 	if ((vnamedup = strdup(vname)) == NULL)
189 		err(1, "strdup");
190 	vd = opendev(vnamedup, O_RDONLY, OPENDEV_PART, NULL);
191 	free(vnamedup);
192 	if (vd < 0)
193 		err(1, "open: %s", vname);
194 
195 	vnu.vnu_unit = -1;
196 
197 query:
198 	if (ioctl(vd, VNDIOCGET, &vnu) == -1) {
199 		close(vd);
200 		return (!(errno == ENXIO && print_all));
201 	}
202 
203 	fprintf(stdout, "vnd%d: ", vnu.vnu_unit);
204 
205 	if (!vnu.vnu_ino)
206 		fprintf(stdout, "not in use\n");
207 	else
208 		fprintf(stdout, "covering %s on %s, inode %d\n", vnu.vnu_file,
209 		    devname(vnu.vnu_dev, S_IFBLK), vnu.vnu_ino);
210 
211 	if (print_all) {
212 		vnu.vnu_unit++;
213 		goto query;
214 	}
215 
216 	close(vd);
217 
218 	return (0);
219 }
220 
221 int
config(char * dev,char * file,int action,char * key,size_t klen,u_int32_t flags)222 config(char *dev, char *file, int action, char *key, size_t klen,
223     u_int32_t flags)
224 {
225 	struct vnd_ioctl vndio;
226 	FILE *f;
227 	char *rdev;
228 	int rv = 0;
229 
230 	if (opendev(dev, (flags & VNDIOC_OPT_RDONLY) ? O_RDONLY : O_RDWR,
231 	    OPENDEV_PART, &rdev) < 0)
232 		err(4, "%s", rdev);
233 	f = fopen(rdev, "rw");
234 	if (f == NULL) {
235 		warn("%s", rdev);
236 		rv = -1;
237 		goto out;
238 	}
239 	vndio.vnd_file = file;
240 	vndio.vnd_key = (u_char *)key;
241 	vndio.vnd_keylen = klen;
242 	vndio.vnd_options = flags;
243 
244 	/*
245 	 * Clear (un-configure) the device
246 	 */
247 	if (action == VND_UNCONFIG) {
248 		rv = ioctl(fileno(f), VNDIOCCLR, &vndio);
249 		if (rv)
250 			warn("VNDIOCCLR");
251 		else if (verbose)
252 			printf("%s: cleared\n", dev);
253 	}
254 	/*
255 	 * Configure the device
256 	 */
257 	if (action == VND_CONFIG) {
258 		rv = ioctl(fileno(f), VNDIOCSET, &vndio);
259 		if (rv)
260 			warn("VNDIOCSET");
261 		else if (verbose)
262 			printf("%s: %llu bytes on %s\n", dev, vndio.vnd_size,
263 			    file);
264 	}
265 
266 	fclose(f);
267 	fflush(stdout);
268  out:
269 	if (key)
270 		memset(key, 0, klen);
271 	return (rv < 0);
272 }
273 
274 __dead void
usage(void)275 usage(void)
276 {
277 	extern const char *__progname;
278 
279 	(void)fprintf(stderr,
280 	    "usage: %s [-c] [-krv] [-f keyfile] rawdev regular-file\n"
281 	    "       %s -u [-v] rawdev\n"
282 	    "       %s -K algorithm -f keyfile\n"
283 	    "       %s -l [rawdev]\n",
284 	    __progname, __progname, __progname, __progname);
285 	exit(1);
286 }
287 
288 #ifndef SMALL
289 static int
make_key(const char * algo,FILE * fp,const char * key2)290 make_key(const char *algo, FILE *fp, const char *key2)
291 {
292 	ASN1_OCTET_STRING *aos;
293 	const EVP_CIPHER *enc = NULL;
294 #define KBUF_ELEM	(BLF_MAX_BYTES / 4)
295 	uint32_t kbuf[KBUF_ELEM];
296 	int i;
297 	size_t kbuflen = sizeof (kbuf);
298 
299 	if (algo == NULL || fp == NULL)
300 		usage();
301 
302 	ERR_load_crypto_strings();
303 	OpenSSL_add_all_ciphers();
304 	if ((aos = ASN1_OCTET_STRING_new()) == NULL)
305 		errx(2, "cannot create ASN.1 octet string: %s",
306 		    ERR_error_string(ERR_get_error(), NULL));
307 	if ((enc = EVP_get_cipherbyname(algo)) == NULL)
308 		errx(2, "unknown cipher '%s': %s", algo,
309 		    ERR_error_string(ERR_get_error(), NULL));
310 
311 	if (key2) {
312 		if (strlen(key2) < kbuflen)
313 			kbuflen = strlen(key2);
314 		else
315 			fprintf(stderr, "WARNING: truncating from %zu to"
316 			    " %zu characters!\n", strlen(key2), kbuflen);
317 		memcpy(kbuf, key2, kbuflen);
318 		fprintf(stderr, "WARNING: not using random bits as key!\n");
319 	} else
320 		arc4random_buf(kbuf, sizeof(kbuf));
321 
322 	i = ASN1_STRING_set(aos, kbuf, kbuflen);
323 	bzero(kbuf, sizeof (kbuf));
324 	if (!i)
325 		errx(2, "cannot set ASN.1 octet string: %s",
326 		    ERR_error_string(ERR_get_error(), NULL));
327 
328 	i = PEM_write_ASN1_OCTET_STRING(fp, aos, enc, NULL, 0, NULL, NULL);
329 	ASN1_STRING_free(aos);
330 	if (!i)
331 		errx(2, "cannot encode svnd keyfile: %s",
332 		    ERR_error_string(ERR_get_error(), NULL));
333 	return (0);
334 }
335 
336 static void
extract_key(FILE * fp,char ** key,int * klen)337 extract_key(FILE *fp, char **key, int *klen)
338 {
339 	ASN1_OCTET_STRING *aos;
340 	unsigned char *p;
341 
342 	if (fp == NULL || key == NULL || klen == NULL)
343 		usage();
344 
345 	ERR_load_crypto_strings();
346 	OpenSSL_add_all_ciphers();
347 	if ((aos = PEM_read_ASN1_OCTET_STRING(fp, NULL, NULL, NULL)) == NULL) {
348 		ERR_print_errors_fp(stderr);
349 		errx(2, "cannot decode svnd keyfile");
350 	}
351 
352 	*klen = ASN1_STRING_length(aos);
353 	if (*klen < 1) {
354 		ASN1_STRING_free(aos);
355 		ERR_print_errors_fp(stderr);
356 		errx(2, "svnd keyfile too small: %d", *klen);
357 	} else if (*klen > BLF_MAX_BYTES)
358 		*klen = BLF_MAX_BYTES;
359 
360 	*key = malloc(*klen);
361 	if (*key == NULL)
362 		err(1, "malloc of %d bytes", *klen);
363 
364 	p = ASN1_STRING_data(aos);
365 	if (p == NULL) {
366 		ASN1_STRING_free(aos);
367 		ERR_print_errors_fp(stderr);
368 		errx(2, "cannot get ASN.1 string");
369 	}
370 
371 	memcpy(*key, p, *klen);
372 	ASN1_STRING_free(aos);
373 	EVP_cleanup();
374 	ERR_free_strings();
375 }
376 #endif
377