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