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