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