1 /* $OpenBSD: mount_vnd.c,v 1.11 2011/04/18 16:52:11 thib 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 <readpassphrase.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <util.h> 58 59 #include "pbkdf2.h" 60 61 #define DEFAULT_VND "vnd0" 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 passphrase[128]; 184 char saltbuf[128], saltfilebuf[PATH_MAX]; 185 char *key = NULL; 186 char *saltfile; 187 const char *errstr; 188 int rounds; 189 190 rounds = strtonum(arg, 1000, INT_MAX, &errstr); 191 if (errstr) 192 err(1, "rounds: %s", errstr); 193 bzero(passphrase, sizeof(passphrase)); 194 if (readpassphrase("Encryption key: ", passphrase, sizeof(passphrase), 195 RPP_REQUIRE_TTY) == NULL) 196 errx(1, "Unable to read passphrase"); 197 if (saltopt) 198 saltfile = saltopt; 199 else { 200 printf("Salt file: "); 201 fflush(stdout); 202 saltfile = fgets(saltfilebuf, sizeof(saltfilebuf), stdin); 203 if (saltfile) 204 saltfile[strcspn(saltfile, "\n")] = '\0'; 205 } 206 if (!saltfile || saltfile[0] == '\0') { 207 warnx("Skipping salt file, insecure"); 208 memset(saltbuf, 0, sizeof(saltbuf)); 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 memset(passphrase, 0, 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 %d\n", vnu.vnu_file, 282 devname(vnu.vnu_dev, S_IFBLK), vnu.vnu_ino); 283 284 if (print_all) { 285 vnu.vnu_unit++; 286 goto query; 287 } 288 289 close(vd); 290 291 return (0); 292 } 293 294 int 295 config(char *dev, char *file, int action, struct disklabel *dp, char *key, 296 size_t keylen) 297 { 298 struct vnd_ioctl vndio; 299 char *rdev; 300 int fd, rv = -1; 301 302 if ((fd = opendev(dev, O_RDONLY, OPENDEV_PART, &rdev)) < 0) { 303 err(4, "%s", rdev); 304 goto out; 305 } 306 307 vndio.vnd_file = file; 308 vndio.vnd_secsize = (dp && dp->d_secsize) ? dp->d_secsize : DEV_BSIZE; 309 vndio.vnd_nsectors = (dp && dp->d_nsectors) ? dp->d_nsectors : 100; 310 vndio.vnd_ntracks = (dp && dp->d_ntracks) ? dp->d_ntracks : 1; 311 vndio.vnd_key = (u_char *)key; 312 vndio.vnd_keylen = keylen; 313 314 /* 315 * Clear (un-configure) the device 316 */ 317 if (action == VND_UNCONFIG) { 318 rv = ioctl(fd, VNDIOCCLR, &vndio); 319 if (rv) 320 warn("VNDIOCCLR"); 321 else if (verbose) 322 printf("%s: cleared\n", dev); 323 } 324 /* 325 * Configure the device 326 */ 327 if (action == VND_CONFIG) { 328 rv = ioctl(fd, VNDIOCSET, &vndio); 329 if (rv) 330 warn("VNDIOCSET"); 331 else if (verbose) 332 printf("%s: %llu bytes on %s\n", dev, vndio.vnd_size, 333 file); 334 } 335 336 close(fd); 337 fflush(stdout); 338 out: 339 if (key) 340 memset(key, 0, keylen); 341 return (rv < 0); 342 } 343 344 __dead void 345 usage(void) 346 { 347 extern char *__progname; 348 349 if (run_mount_vnd) 350 (void)fprintf(stderr, 351 "usage: mount_vnd [-k] [-K rounds] [-o options] " 352 "[-S saltfile] [-t disktype]\n" 353 "\t\t image vnd_dev\n"); 354 else 355 (void)fprintf(stderr, 356 "usage: %s [-ckluv] [-K rounds] [-S saltfile] " 357 "[-t disktype] vnd_dev image\n", __progname); 358 359 exit(1); 360 } 361