1 /*	$OpenBSD: mount_vnd.c,v 1.4 2007/09/29 07:10:09 fkr Exp $	*/
2 /*
3  * Copyright (c) 1993 University of Utah.
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * the Systems Programming Group of the University of Utah Computer
9  * Science Department.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
36  *
37  *	@(#)vnconfig.c	8.1 (Berkeley) 12/15/93
38  */
39 
40 #include <sys/param.h>
41 #include <sys/ioctl.h>
42 #include <sys/mount.h>
43 #include <sys/stat.h>
44 
45 #include <dev/vndioctl.h>
46 
47 #include <blf.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <pwd.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <util.h>
57 
58 #include "pkcs5_pbkdf2.h"
59 
60 __RCSID("$MirOS: src/sbin/mount_vnd/mount_vnd.c,v 1.3 2010/09/21 21:24:18 tg Exp $");
61 __RCSID("$OpenBSD: mount_vnd.c,v 1.4 2007/09/29 07:10:09 fkr Exp $");
62 __RCSID("Utah $Hdr: vnconfig.c 1.1 93/12/15$");
63 __SCCSID("@(#)vnconfig.c	8.1 (Berkeley) 12/15/93");
64 
65 #define DEFAULT_VND	"svnd0"
66 
67 #define VND_CONFIG	1
68 #define VND_UNCONFIG	2
69 #define VND_GET		3
70 
71 int verbose = 0;
72 int run_mount_vnd = 0;
73 
74 __dead void	 usage(void);
75 int		 config(char *, char *, int, char *, size_t);
76 int		 getinfo(const char *);
77 char		*get_pkcs_key(char *, char *);
78 
79 int
main(int argc,char ** argv)80 main(int argc, char **argv)
81 {
82 	int	 ch, rv, action, opt_c, opt_k, opt_K, opt_l, opt_u;
83 	char	*key, *mntopts, *rounds, *saltopt;
84 	size_t	 keylen = 0;
85 	extern char *__progname;
86 
87 	if (strcasecmp(__progname, "mount_vnd") == 0)
88 		run_mount_vnd = 1;
89 
90 	opt_c = opt_k = opt_K = opt_l = opt_u = 0;
91 	key = mntopts = rounds = saltopt = NULL;
92 	action = VND_CONFIG;
93 
94 	while ((ch = getopt(argc, argv, "ckK:lo:S:uv")) != -1) {
95 		switch (ch) {
96 		case 'c':
97 			opt_c = 1;
98 			break;
99 		case 'k':
100 			opt_k = 1;
101 			break;
102 		case 'K':
103 			opt_K = 1;
104 			rounds = optarg;
105 			break;
106 		case 'l':
107 			opt_l = 1;
108 			break;
109 		case 'o':
110 			mntopts = optarg;
111 			break;
112 		case 'S':
113 			saltopt = optarg;
114 			break;
115 		case 'u':
116 			opt_u = 1;
117 			break;
118 		case 'v':
119 			verbose = 1;
120 			break;
121 		default:
122 			usage();
123 			/* NOTREACHED */
124 		}
125 	}
126 	argc -= optind;
127 	argv += optind;
128 
129 	if (opt_c + opt_l + opt_u > 1)
130 		errx(1, "-c, -l and -u are mutually exclusive options");
131 
132 	if (opt_l)
133 		action = VND_GET;
134 	else if (opt_u)
135 		action = VND_UNCONFIG;
136 	else
137 		action = VND_CONFIG;	/* default behavior */
138 
139 	if (saltopt && (!opt_K))
140 		errx(1, "-S only makes sense when used with -K");
141 
142 	if (action == VND_CONFIG && argc == 2) {
143 		int ind_raw, ind_reg;
144 
145 		if (opt_k) {
146 			if (opt_K)
147 				errx(1, "-k and -K are mutually exclusive");
148 			key = getpass("Encryption key: ");
149 			if (key == NULL || (keylen = strlen(key)) == 0)
150 				errx(1, "Need an encryption key");
151 		} else if (opt_K) {
152 			key = get_pkcs_key(rounds, saltopt);
153 			keylen = BLF_MAXUTILIZED;
154 		}
155 
156 		/* fix order of arguments. */
157 		if (run_mount_vnd) {
158 			ind_raw = 1;
159 			ind_reg = 0;
160 		} else {
161 			ind_raw = 0;
162 			ind_reg = 1;
163 		}
164 		rv = config(argv[ind_raw], argv[ind_reg], action, key, keylen);
165 	} else if (action == VND_UNCONFIG && argc == 1)
166 		rv = config(argv[0], NULL, action, NULL, 0);
167 	else if (action == VND_GET)
168 		rv = getinfo(argc ? argv[0] : NULL);
169 	else
170 		usage();
171 
172 	exit(rv);
173 }
174 
175 char *
get_pkcs_key(char * arg,char * saltopt)176 get_pkcs_key(char *arg, char *saltopt)
177 {
178 	char		 keybuf[128], saltbuf[128], saltfilebuf[PATH_MAX];
179 	char		*saltfile;
180 	char		*key = NULL;
181 	const char	*errstr;
182 	int		 rounds;
183 
184 	rounds = strtonum(arg, 1000, INT_MAX, &errstr);
185 	if (errstr)
186 		err(1, "rounds: %s", errstr);
187 	key = getpass("Encryption key: ");
188 	if (!key || strlen(key) == 0)
189 		errx(1, "Need an encryption key");
190 	strncpy(keybuf, key, sizeof(keybuf));
191 	if (saltopt)
192 		saltfile = saltopt;
193 	else {
194 		printf("Salt file: ");
195 		fflush(stdout);
196 		saltfile = fgets(saltfilebuf, sizeof(saltfilebuf), stdin);
197 		if (saltfile)
198 			saltfile[strcspn(saltfile, "\n")] = '\0';
199 	}
200 	if (!saltfile || saltfile[0] == '\0') {
201 		warnx("Skipping salt file, insecure");
202 		memset(saltbuf, 0, sizeof(saltbuf));
203 	} else {
204 		int fd;
205 
206 		fd = open(saltfile, O_RDONLY);
207 		if (fd == -1) {
208 			int *s;
209 
210 			fprintf(stderr, "Salt file not found, attempting to create one\n");
211 			fd = open(saltfile, O_RDWR|O_CREAT|O_EXCL, 0600);
212 			if (fd == -1)
213 				err(1, "Unable to create salt file: '%s'",
214 				    saltfile);
215 			arc4random_buf(saltbuf, sizeof(saltbuf));
216 			if (write(fd, saltbuf, sizeof(saltbuf))
217 			    != sizeof(saltbuf))
218 				err(1, "Unable to write salt file: '%s'", saltfile);
219 			fprintf(stderr, "Salt file created as '%s'\n", saltfile);
220 		} else {
221 			if (read(fd, saltbuf, sizeof(saltbuf))
222 			    != sizeof(saltbuf))
223 				err(1, "Unable to read salt file: '%s'", saltfile);
224 		}
225 		close(fd);
226 	}
227 	if (pkcs5_pbkdf2((u_int8_t**)&key, BLF_MAXUTILIZED, keybuf,
228 	    sizeof(keybuf), saltbuf, sizeof(saltbuf), rounds, 0))
229 		errx(1, "pkcs5_pbkdf2 failed");
230 
231 	return (key);
232 }
233 
234 int
getinfo(const char * vname)235 getinfo(const char *vname)
236 {
237 	int vd, print_all = 0;
238 	struct vnd_user vnu;
239 
240 	if (vname == NULL) {
241 		vname = DEFAULT_VND;
242 		print_all = 1;
243 	}
244 
245 	vd = opendev((char *)vname, O_RDONLY, OPENDEV_PART, NULL);
246 	if (vd < 0)
247 		err(1, "open: %s", vname);
248 
249 	vnu.vnu_unit = -1;
250 
251 query:
252 	if (ioctl(vd, VNDIOCGET, &vnu) == -1) {
253 		if (print_all && errno == ENXIO && vnu.vnu_unit > 0) {
254 			close(vd);
255 			return (0);
256 		} else {
257 			err(1, "ioctl: %s", vname);
258 		}
259 	}
260 
261 	fprintf(stdout, "vnd%d: ", vnu.vnu_unit);
262 
263 	if (!vnu.vnu_ino)
264 		fprintf(stdout, "not in use\n");
265 	else
266 		fprintf(stdout, "covering %s on %s, inode %d\n", vnu.vnu_file,
267 		    devname(vnu.vnu_dev, S_IFBLK), vnu.vnu_ino);
268 
269 	if (print_all) {
270 		vnu.vnu_unit++;
271 		goto query;
272 	}
273 
274 	close(vd);
275 
276 	return (0);
277 }
278 
279 int
config(char * dev,char * file,int action,char * key,size_t keylen)280 config(char *dev, char *file, int action, char *key, size_t keylen)
281 {
282 	struct vnd_ioctl vndio;
283 	FILE *f;
284 	char *rdev;
285 	int rv;
286 
287 	if (opendev(dev, O_RDONLY, OPENDEV_PART, &rdev) < 0)
288 		err(4, "%s", rdev);
289 	f = fopen(rdev, "r");
290 	if (f == NULL) {
291 		warn("%s", rdev);
292 		rv = -1;
293 		goto out;
294 	}
295 	vndio.vnd_file = file;
296 	vndio.vnd_key = (u_char *)key;
297 	vndio.vnd_keylen = keylen;
298 
299 	/*
300 	 * Clear (un-configure) the device
301 	 */
302 	if (action == VND_UNCONFIG) {
303 		rv = ioctl(fileno(f), VNDIOCCLR, &vndio);
304 		if (rv)
305 			warn("VNDIOCCLR");
306 		else if (verbose)
307 			printf("%s: cleared\n", dev);
308 	}
309 	/*
310 	 * Configure the device
311 	 */
312 	if (action == VND_CONFIG) {
313 		rv = ioctl(fileno(f), VNDIOCSET, &vndio);
314 		if (rv)
315 			warn("VNDIOCSET");
316 		else if (verbose)
317 			printf("%s: %llu bytes on %s\n", dev, vndio.vnd_size,
318 			    file);
319 	}
320 
321 	fclose(f);
322 	fflush(stdout);
323  out:
324 	if (key)
325 		memset(key, 0, keylen);
326 	return (rv < 0);
327 }
328 
329 __dead void
usage(void)330 usage(void)
331 {
332 	extern char *__progname;
333 
334 	if (run_mount_vnd)
335 		(void)fprintf(stderr,
336 		    "usage: %s [-k] [-K rounds] [-o options] "
337 		    "[-S saltfile] image vnd_dev\n", __progname);
338 	else
339 		(void)fprintf(stderr,
340 		    "usage: %s [-ckluv] [-K rounds] [-S saltfile] vnd_dev "
341 		    "image\n", __progname);
342 
343 	exit(1);
344 }
345