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