GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/mount_vnd/mount_vnd.c Lines: 42 146 28.8 %
Date: 2017-11-07 Branches: 30 118 25.4 %

Line Branch Exec Source
1
/*	$OpenBSD: mount_vnd.c,v 1.20 2016/01/24 06:32:33 mmcc 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>	/* DEV_BSIZE */
41
#include <sys/ioctl.h>
42
#include <sys/mount.h>
43
#include <sys/stat.h>
44
#include <sys/disklabel.h>
45
46
#include <dev/vndioctl.h>
47
48
#include <blf.h>
49
#include <err.h>
50
#include <errno.h>
51
#include <fcntl.h>
52
#include <readpassphrase.h>
53
#include <stdio.h>
54
#include <stdlib.h>
55
#include <string.h>
56
#include <unistd.h>
57
#include <limits.h>
58
#include <util.h>
59
60
#define DEFAULT_VND	"vnd0"
61
62
#define VND_CONFIG	1
63
#define VND_UNCONFIG	2
64
#define VND_GET		3
65
66
int verbose = 0;
67
int run_mount_vnd = 0;
68
69
__dead void	 usage(void);
70
int		 config(char *, char *, int, struct disklabel *, char *,
71
		     size_t);
72
int		 getinfo(const char *);
73
char		*get_pkcs_key(char *, char *);
74
75
int
76
main(int argc, char **argv)
77
{
78
	int	 ch, rv, action, opt_c, opt_k, opt_K, opt_l, opt_u;
79
	char	*key, *mntopts, *rounds, *saltopt;
80
	size_t	 keylen = 0;
81
	extern char *__progname;
82
	struct disklabel *dp = NULL;
83
84
68
	if (strcasecmp(__progname, "mount_vnd") == 0)
85
		run_mount_vnd = 1;
86
87
	opt_c = opt_k = opt_K = opt_l = opt_u = 0;
88
	key = mntopts = rounds = saltopt = NULL;
89
	action = VND_CONFIG;
90
91
86
	while ((ch = getopt(argc, argv, "ckK:lo:S:t:uv")) != -1) {
92


18
		switch (ch) {
93
		case 'c':
94
			opt_c = 1;
95
			break;
96
		case 'k':
97
			opt_k = 1;
98
			break;
99
		case 'K':
100
			opt_K = 1;
101
			rounds = optarg;
102
			break;
103
		case 'l':
104
			opt_l = 1;
105
			break;
106
		case 'o':
107
			mntopts = optarg;
108
			break;
109
		case 'S':
110
			saltopt = optarg;
111
			break;
112
		case 't':
113
			dp = getdiskbyname(optarg);
114
			if (dp == NULL)
115
				errx(1, "unknown disk type: %s", optarg);
116
			break;
117
		case 'u':
118
			opt_u = 1;
119
18
			break;
120
		case 'v':
121
			verbose = 1;
122
			break;
123
		default:
124
			usage();
125
			/* NOTREACHED */
126
		}
127
	}
128
34
	argc -= optind;
129
34
	argv += optind;
130
131
34
	if (opt_c + opt_l + opt_u > 1)
132
		errx(1, "-c, -l and -u are mutually exclusive options");
133
134
34
	if (opt_l)
135
		action = VND_GET;
136
34
	else if (opt_u)
137
18
		action = VND_UNCONFIG;
138
	else
139
		action = VND_CONFIG;	/* default behavior */
140
141
34
	if (saltopt && (!opt_K))
142
		errx(1, "-S only makes sense when used with -K");
143
144
34
	if (action == VND_CONFIG && argc == 2) {
145
		int ind_raw, ind_reg;
146
147
16
		if (opt_k || opt_K) {
148
			fprintf(stderr,
149
			    "WARNING: Consider using softraid crypto.\n");
150
		}
151
16
		if (opt_k) {
152
			if (opt_K)
153
				errx(1, "-k and -K are mutually exclusive");
154
			key = getpass("Encryption key: ");
155
			if (key == NULL || (keylen = strlen(key)) == 0)
156
				errx(1, "Need an encryption key");
157
16
		} else if (opt_K) {
158
			key = get_pkcs_key(rounds, saltopt);
159
			keylen = BLF_MAXUTILIZED;
160
		}
161
162
		/* fix order of arguments. */
163
16
		if (run_mount_vnd) {
164
			ind_raw = 1;
165
			ind_reg = 0;
166
		} else {
167
			ind_raw = 0;
168
			ind_reg = 1;
169
		}
170
16
		rv = config(argv[ind_raw], argv[ind_reg], action, dp, key,
171
		    keylen);
172
34
	} else if (action == VND_UNCONFIG && argc == 1)
173
18
		rv = config(argv[0], NULL, action, NULL, NULL, 0);
174
	else if (action == VND_GET)
175
		rv = getinfo(argc ? argv[0] : NULL);
176
	else
177
		usage();
178
179
	exit(rv);
180
}
181
182
char *
183
get_pkcs_key(char *arg, char *saltopt)
184
{
185
	char		 passphrase[128] = {'\0'};
186
	char		 saltbuf[128] = {'\0'}, saltfilebuf[PATH_MAX];
187
	char		*key = NULL;
188
	char		*saltfile;
189
	const char	*errstr;
190
	int		 rounds;
191
192
	rounds = strtonum(arg, 1000, INT_MAX, &errstr);
193
	if (errstr)
194
		err(1, "rounds: %s", errstr);
195
	if (readpassphrase("Encryption key: ", passphrase, sizeof(passphrase),
196
	    RPP_REQUIRE_TTY) == NULL)
197
		errx(1, "Unable to read passphrase");
198
	if (saltopt)
199
		saltfile = saltopt;
200
	else {
201
		printf("Salt file: ");
202
		fflush(stdout);
203
		saltfile = fgets(saltfilebuf, sizeof(saltfilebuf), stdin);
204
		if (saltfile)
205
			saltfile[strcspn(saltfile, "\n")] = '\0';
206
	}
207
	if (!saltfile || saltfile[0] == '\0')
208
		warnx("Skipping salt file, insecure");
209
	else {
210
		int fd;
211
212
		fd = open(saltfile, O_RDONLY);
213
		if (fd == -1) {
214
			int *s;
215
216
			fprintf(stderr, "Salt file not found, attempting to "
217
			    "create one\n");
218
			fd = open(saltfile, O_RDWR|O_CREAT|O_EXCL, 0600);
219
			if (fd == -1)
220
				err(1, "Unable to create salt file: '%s'",
221
				    saltfile);
222
			for (s = (int *)saltbuf;
223
			    s < (int *)(saltbuf + sizeof(saltbuf)); s++)
224
				*s = arc4random();
225
			if (write(fd, saltbuf, sizeof(saltbuf))
226
			    != sizeof(saltbuf))
227
				err(1, "Unable to write salt file: '%s'",
228
				    saltfile);
229
			fprintf(stderr, "Salt file created as '%s'\n",
230
			    saltfile);
231
		} else {
232
			if (read(fd, saltbuf, sizeof(saltbuf))
233
			    != sizeof(saltbuf))
234
				err(1, "Unable to read salt file: '%s'",
235
				    saltfile);
236
		}
237
		close(fd);
238
	}
239
	if ((key = calloc(1, BLF_MAXUTILIZED)) == NULL)
240
		err(1, NULL);
241
	if (pkcs5_pbkdf2(passphrase, sizeof(passphrase), saltbuf,
242
	    sizeof (saltbuf), key, BLF_MAXUTILIZED, rounds))
243
		errx(1, "pkcs5_pbkdf2 failed");
244
	explicit_bzero(passphrase, sizeof(passphrase));
245
246
	return (key);
247
}
248
249
int
250
getinfo(const char *vname)
251
{
252
	int vd, print_all = 0;
253
	struct vnd_user vnu;
254
255
	if (vname == NULL) {
256
		vname = DEFAULT_VND;
257
		print_all = 1;
258
	}
259
260
	vd = opendev((char *)vname, O_RDONLY, OPENDEV_PART, NULL);
261
	if (vd < 0)
262
		err(1, "open: %s", vname);
263
264
	vnu.vnu_unit = -1;
265
266
query:
267
	if (ioctl(vd, VNDIOCGET, &vnu) == -1) {
268
		if (print_all && errno == ENXIO && vnu.vnu_unit > 0) {
269
			close(vd);
270
			return (0);
271
		} else {
272
			err(1, "ioctl: %s", vname);
273
		}
274
	}
275
276
	fprintf(stdout, "vnd%d: ", vnu.vnu_unit);
277
278
	if (!vnu.vnu_ino)
279
		fprintf(stdout, "not in use\n");
280
	else
281
		fprintf(stdout, "covering %s on %s, inode %llu\n",
282
		    vnu.vnu_file, devname(vnu.vnu_dev, S_IFBLK),
283
		    (unsigned long long)vnu.vnu_ino);
284
285
	if (print_all) {
286
		vnu.vnu_unit++;
287
		goto query;
288
	}
289
290
	close(vd);
291
292
	return (0);
293
}
294
295
int
296
config(char *dev, char *file, int action, struct disklabel *dp, char *key,
297
    size_t keylen)
298
{
299
68
	struct vnd_ioctl vndio;
300
34
	char *rdev;
301
	int fd, rv = -1;
302
303
34
	if ((fd = opendev(dev, O_RDONLY, OPENDEV_PART, &rdev)) < 0) {
304
		err(4, "%s", rdev);
305
		goto out;
306
	}
307
308
34
	vndio.vnd_file = file;
309

68
	vndio.vnd_secsize = (dp && dp->d_secsize) ? dp->d_secsize : DEV_BSIZE;
310

68
	vndio.vnd_nsectors = (dp && dp->d_nsectors) ? dp->d_nsectors : 100;
311

68
	vndio.vnd_ntracks = (dp && dp->d_ntracks) ? dp->d_ntracks : 1;
312
34
	vndio.vnd_key = (u_char *)key;
313
34
	vndio.vnd_keylen = keylen;
314
315
	/*
316
	 * Clear (un-configure) the device
317
	 */
318
34
	if (action == VND_UNCONFIG) {
319
18
		rv = ioctl(fd, VNDIOCCLR, &vndio);
320
18
		if (rv)
321
2
			warn("VNDIOCCLR");
322
16
		else if (verbose)
323
			printf("%s: cleared\n", dev);
324
	}
325
	/*
326
	 * Configure the device
327
	 */
328
34
	if (action == VND_CONFIG) {
329
16
		rv = ioctl(fd, VNDIOCSET, &vndio);
330
16
		if (rv)
331
			warn("VNDIOCSET");
332
16
		else if (verbose)
333
			printf("%s: %llu bytes on %s\n", dev, vndio.vnd_size,
334
			    file);
335
	}
336
337
34
	close(fd);
338
34
	fflush(stdout);
339
 out:
340
34
	if (key)
341
		explicit_bzero(key, keylen);
342
68
	return (rv < 0);
343
34
}
344
345
__dead void
346
usage(void)
347
{
348
	extern char *__progname;
349
350
	if (run_mount_vnd)
351
		(void)fprintf(stderr,
352
		    "usage: mount_vnd [-k] [-K rounds] [-o options] "
353
		    "[-S saltfile] [-t disktype]\n"
354
		    "\t\t image vnd_dev\n");
355
	else
356
		(void)fprintf(stderr,
357
		    "usage: %s [-ckluv] [-K rounds] [-S saltfile] "
358
		    "[-t disktype] vnd_dev image\n", __progname);
359
360
	exit(1);
361
}