1 /* $OpenBSD: mount_vnd.c,v 1.8 2008/09/03 23:24:25 krw 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 #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 <pwd.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <util.h> 58 59 #include "pkcs5_pbkdf2.h" 60 61 #define DEFAULT_VND "svnd0" 62 63 #define VND_CONFIG 1 64 #define VND_UNCONFIG 2 65 #define VND_GET 3 66 67 int verbose = 0; 68 int run_mount_vnd = 0; 69 70 __dead void usage(void); 71 int config(char *, char *, int, struct disklabel *, char *, 72 size_t); 73 int getinfo(const char *); 74 char *get_pkcs_key(char *, char *); 75 76 int 77 main(int argc, char **argv) 78 { 79 int ch, rv, action, opt_c, opt_k, opt_K, opt_l, opt_u; 80 char *key, *mntopts, *rounds, *saltopt; 81 size_t keylen = 0; 82 const char *errstr; 83 extern char *__progname; 84 struct disklabel *dp = NULL; 85 86 if (strcasecmp(__progname, "mount_vnd") == 0) 87 run_mount_vnd = 1; 88 89 opt_c = opt_k = opt_K = opt_l = opt_u = 0; 90 key = mntopts = rounds = saltopt = NULL; 91 action = VND_CONFIG; 92 93 while ((ch = getopt(argc, argv, "ckK:lo:S:t:uv")) != -1) { 94 switch (ch) { 95 case 'c': 96 opt_c = 1; 97 break; 98 case 'k': 99 opt_k = 1; 100 break; 101 case 'K': 102 opt_K = 1; 103 rounds = optarg; 104 break; 105 case 'l': 106 opt_l = 1; 107 break; 108 case 'o': 109 mntopts = optarg; 110 break; 111 case 'S': 112 saltopt = optarg; 113 break; 114 case 't': 115 dp = getdiskbyname(optarg); 116 if (dp == NULL) 117 errx(1, "unknown disk type: %s", optarg); 118 break; 119 case 'u': 120 opt_u = 1; 121 break; 122 case 'v': 123 verbose = 1; 124 break; 125 default: 126 usage(); 127 /* NOTREACHED */ 128 } 129 } 130 argc -= optind; 131 argv += optind; 132 133 if (opt_c + opt_l + opt_u > 1) 134 errx(1, "-c, -l and -u are mutually exclusive options"); 135 136 if (opt_l) 137 action = VND_GET; 138 else if (opt_u) 139 action = VND_UNCONFIG; 140 else 141 action = VND_CONFIG; /* default behavior */ 142 143 if (saltopt && (!opt_K)) 144 errx(1, "-S only makes sense when used with -K"); 145 146 if (action == VND_CONFIG && argc == 2) { 147 int ind_raw, ind_reg; 148 149 if (opt_k) { 150 if (opt_K) 151 errx(1, "-k and -K are mutually exclusive"); 152 key = getpass("Encryption key: "); 153 if (key == NULL || (keylen = strlen(key)) == 0) 154 errx(1, "Need an encryption key"); 155 } else if (opt_K) { 156 key = get_pkcs_key(rounds, saltopt); 157 keylen = BLF_MAXUTILIZED; 158 } 159 160 /* fix order of arguments. */ 161 if (run_mount_vnd) { 162 ind_raw = 1; 163 ind_reg = 0; 164 } else { 165 ind_raw = 0; 166 ind_reg = 1; 167 } 168 rv = config(argv[ind_raw], argv[ind_reg], action, dp, key, 169 keylen); 170 } else if (action == VND_UNCONFIG && argc == 1) 171 rv = config(argv[0], NULL, action, NULL, NULL, 0); 172 else if (action == VND_GET) 173 rv = getinfo(argc ? argv[0] : NULL); 174 else 175 usage(); 176 177 exit(rv); 178 } 179 180 char * 181 get_pkcs_key(char *arg, char *saltopt) 182 { 183 char keybuf[128], saltbuf[128], saltfilebuf[PATH_MAX]; 184 char *saltfile; 185 char *key = NULL; 186 const char *errstr; 187 int rounds; 188 189 rounds = strtonum(arg, 1000, INT_MAX, &errstr); 190 if (errstr) 191 err(1, "rounds: %s", errstr); 192 key = getpass("Encryption key: "); 193 if (!key || strlen(key) == 0) 194 errx(1, "Need an encryption key"); 195 strncpy(keybuf, key, sizeof(keybuf)); 196 if (saltopt) 197 saltfile = saltopt; 198 else { 199 printf("Salt file: "); 200 fflush(stdout); 201 saltfile = fgets(saltfilebuf, sizeof(saltfilebuf), stdin); 202 if (saltfile) 203 saltfile[strcspn(saltfile, "\n")] = '\0'; 204 } 205 if (!saltfile || saltfile[0] == '\0') { 206 warnx("Skipping salt file, insecure"); 207 memset(saltbuf, 0, sizeof(saltbuf)); 208 } else { 209 int fd; 210 211 fd = open(saltfile, O_RDONLY); 212 if (fd == -1) { 213 int *s; 214 215 fprintf(stderr, "Salt file not found, attempting to create one\n"); 216 fd = open(saltfile, O_RDWR|O_CREAT|O_EXCL, 0600); 217 if (fd == -1) 218 err(1, "Unable to create salt file: '%s'", 219 saltfile); 220 for (s = (int *)saltbuf; 221 s < (int *)(saltbuf + sizeof(saltbuf)); s++) 222 *s = arc4random(); 223 if (write(fd, saltbuf, sizeof(saltbuf)) 224 != sizeof(saltbuf)) 225 err(1, "Unable to write salt file: '%s'", saltfile); 226 fprintf(stderr, "Salt file created as '%s'\n", saltfile); 227 } else { 228 if (read(fd, saltbuf, sizeof(saltbuf)) 229 != sizeof(saltbuf)) 230 err(1, "Unable to read salt file: '%s'", saltfile); 231 } 232 close(fd); 233 } 234 if (pkcs5_pbkdf2((u_int8_t**)&key, BLF_MAXUTILIZED, keybuf, 235 sizeof(keybuf), saltbuf, sizeof(saltbuf), rounds, 0)) 236 errx(1, "pkcs5_pbkdf2 failed"); 237 238 return (key); 239 } 240 241 int 242 getinfo(const char *vname) 243 { 244 int vd, print_all = 0; 245 struct vnd_user vnu; 246 247 if (vname == NULL) { 248 vname = DEFAULT_VND; 249 print_all = 1; 250 } 251 252 vd = opendev((char *)vname, O_RDONLY, OPENDEV_PART, NULL); 253 if (vd < 0) 254 err(1, "open: %s", vname); 255 256 vnu.vnu_unit = -1; 257 258 query: 259 if (ioctl(vd, VNDIOCGET, &vnu) == -1) { 260 if (print_all && errno == ENXIO && vnu.vnu_unit > 0) { 261 close(vd); 262 return (0); 263 } else { 264 err(1, "ioctl: %s", vname); 265 } 266 } 267 268 fprintf(stdout, "vnd%d: ", vnu.vnu_unit); 269 270 if (!vnu.vnu_ino) 271 fprintf(stdout, "not in use\n"); 272 else 273 fprintf(stdout, "covering %s on %s, inode %d\n", vnu.vnu_file, 274 devname(vnu.vnu_dev, S_IFBLK), vnu.vnu_ino); 275 276 if (print_all) { 277 vnu.vnu_unit++; 278 goto query; 279 } 280 281 close(vd); 282 283 return (0); 284 } 285 286 int 287 config(char *dev, char *file, int action, struct disklabel *dp, char *key, 288 size_t keylen) 289 { 290 struct vnd_ioctl vndio; 291 FILE *f; 292 char *rdev; 293 int rv = -1; 294 295 if (opendev(dev, O_RDONLY, OPENDEV_PART, &rdev) < 0) 296 err(4, "%s", rdev); 297 f = fopen(rdev, "r"); 298 if (f == NULL) { 299 warn("%s", rdev); 300 goto out; 301 } 302 vndio.vnd_file = file; 303 vndio.vnd_secsize = (dp && dp->d_secsize) ? dp->d_secsize : DEV_BSIZE; 304 vndio.vnd_nsectors = (dp && dp->d_nsectors) ? dp->d_nsectors : 100; 305 vndio.vnd_ntracks = (dp && dp->d_ntracks) ? dp->d_ntracks : 1; 306 vndio.vnd_key = (u_char *)key; 307 vndio.vnd_keylen = keylen; 308 309 /* 310 * Clear (un-configure) the device 311 */ 312 if (action == VND_UNCONFIG) { 313 rv = ioctl(fileno(f), VNDIOCCLR, &vndio); 314 if (rv) 315 warn("VNDIOCCLR"); 316 else if (verbose) 317 printf("%s: cleared\n", dev); 318 } 319 /* 320 * Configure the device 321 */ 322 if (action == VND_CONFIG) { 323 rv = ioctl(fileno(f), VNDIOCSET, &vndio); 324 if (rv) 325 warn("VNDIOCSET"); 326 else if (verbose) 327 printf("%s: %llu bytes on %s\n", dev, vndio.vnd_size, 328 file); 329 } 330 331 fclose(f); 332 fflush(stdout); 333 out: 334 if (key) 335 memset(key, 0, keylen); 336 return (rv < 0); 337 } 338 339 __dead void 340 usage(void) 341 { 342 extern char *__progname; 343 344 if (run_mount_vnd) 345 (void)fprintf(stderr, 346 "usage: mount_vnd [-k] [-K rounds] [-o options] " 347 "[-S saltfile] [-t disktype]\n" 348 "\t\t image vnd_dev\n"); 349 else 350 (void)fprintf(stderr, 351 "usage: %s [-ckluv] [-K rounds] [-S saltfile] " 352 "[-t disktype] vnd_dev image\n", __progname); 353 354 exit(1); 355 } 356