vnd.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. /* $OpenBSD: vnd.c,v 1.155 2014/12/13 21:05:32 doug Exp $ */
  2. /* $NetBSD: vnd.c,v 1.26 1996/03/30 23:06:11 christos Exp $ */
  3. /*
  4. * Copyright (c) 1988 University of Utah.
  5. * Copyright (c) 1990, 1993
  6. * The Regents of the University of California. All rights reserved.
  7. *
  8. * This code is derived from software contributed to Berkeley by
  9. * the Systems Programming Group of the University of Utah Computer
  10. * Science Department.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. * 1. Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in the
  19. * documentation and/or other materials provided with the distribution.
  20. * 3. Neither the name of the University nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE.
  35. */
  36. /*
  37. * There is a security issue involved with this driver.
  38. *
  39. * Once mounted all access to the contents of the "mapped" file via
  40. * the special file is controlled by the permissions on the special
  41. * file, the protection of the mapped file is ignored (effectively,
  42. * by using root credentials in all transactions).
  43. *
  44. */
  45. #include <sys/param.h>
  46. #include <sys/systm.h>
  47. #include <sys/namei.h>
  48. #include <sys/proc.h>
  49. #include <sys/errno.h>
  50. #include <sys/limits.h>
  51. #include <sys/buf.h>
  52. #include <sys/malloc.h>
  53. #include <sys/ioctl.h>
  54. #include <sys/disklabel.h>
  55. #include <sys/device.h>
  56. #include <sys/disk.h>
  57. #include <sys/stat.h>
  58. #include <sys/vnode.h>
  59. #include <sys/file.h>
  60. #include <sys/uio.h>
  61. #include <sys/conf.h>
  62. #include <sys/dkio.h>
  63. #include <sys/specdev.h>
  64. #include <crypto/blf.h>
  65. #include <dev/vndioctl.h>
  66. #ifdef VNDDEBUG
  67. int vnddebug = 0x00;
  68. #define VDB_FOLLOW 0x01
  69. #define VDB_INIT 0x02
  70. #define VDB_IO 0x04
  71. #define DNPRINTF(f, p...) do { if ((f) & vnddebug) printf(p); } while (0)
  72. #else
  73. #define DNPRINTF(f, p...) /* nothing */
  74. #endif /* VNDDEBUG */
  75. struct vnd_softc {
  76. struct device sc_dev;
  77. struct disk sc_dk;
  78. char sc_file[VNDNLEN]; /* file we're covering */
  79. int sc_flags; /* flags */
  80. size_t sc_size; /* size of vnd in sectors */
  81. size_t sc_secsize; /* sector size in bytes */
  82. size_t sc_nsectors; /* # of sectors per track */
  83. size_t sc_ntracks; /* # of tracks per cylinder */
  84. struct vnode *sc_vp; /* vnode */
  85. struct ucred *sc_cred; /* credentials */
  86. blf_ctx *sc_keyctx; /* key context */
  87. };
  88. /* sc_flags */
  89. #define VNF_INITED 0x0001
  90. #define VNF_HAVELABEL 0x0002
  91. #define VNF_READONLY 0x0004
  92. #define VNDRW(v) ((v)->sc_flags & VNF_READONLY ? FREAD : FREAD|FWRITE)
  93. struct vnd_softc *vnd_softc;
  94. int numvnd = 0;
  95. /* called by main() at boot time */
  96. void vndattach(int);
  97. void vndclear(struct vnd_softc *);
  98. int vndsetcred(struct vnd_softc *, struct ucred *);
  99. int vndgetdisklabel(dev_t, struct vnd_softc *, struct disklabel *, int);
  100. void vndencrypt(struct vnd_softc *, caddr_t, size_t, daddr_t, int);
  101. void vndencryptbuf(struct vnd_softc *, struct buf *, int);
  102. size_t vndbdevsize(struct vnode *, struct proc *);
  103. void
  104. vndencrypt(struct vnd_softc *sc, caddr_t addr, size_t size, daddr_t off,
  105. int encrypt)
  106. {
  107. int i, bsize;
  108. u_char iv[8];
  109. bsize = dbtob(1);
  110. for (i = 0; i < size/bsize; i++) {
  111. memset(iv, 0, sizeof(iv));
  112. memcpy(iv, &off, sizeof(off));
  113. blf_ecb_encrypt(sc->sc_keyctx, iv, sizeof(iv));
  114. if (encrypt)
  115. blf_cbc_encrypt(sc->sc_keyctx, iv, addr, bsize);
  116. else
  117. blf_cbc_decrypt(sc->sc_keyctx, iv, addr, bsize);
  118. addr += bsize;
  119. off++;
  120. }
  121. }
  122. void
  123. vndencryptbuf(struct vnd_softc *sc, struct buf *bp, int encrypt)
  124. {
  125. vndencrypt(sc, bp->b_data, bp->b_bcount, bp->b_blkno, encrypt);
  126. }
  127. void
  128. vndattach(int num)
  129. {
  130. char *mem;
  131. int i;
  132. if (num <= 0)
  133. return;
  134. mem = mallocarray(num, sizeof(struct vnd_softc), M_DEVBUF,
  135. M_NOWAIT | M_ZERO);
  136. if (mem == NULL) {
  137. printf("WARNING: no memory for vnode disks\n");
  138. return;
  139. }
  140. vnd_softc = (struct vnd_softc *)mem;
  141. for (i = 0; i < num; i++) {
  142. struct vnd_softc *sc = &vnd_softc[i];
  143. sc->sc_dev.dv_unit = i;
  144. snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname),
  145. "vnd%d", i);
  146. disk_construct(&sc->sc_dk);
  147. device_ref(&sc->sc_dev);
  148. }
  149. numvnd = num;
  150. }
  151. int
  152. vndopen(dev_t dev, int flags, int mode, struct proc *p)
  153. {
  154. int unit = DISKUNIT(dev);
  155. struct vnd_softc *sc;
  156. int error = 0, part;
  157. DNPRINTF(VDB_FOLLOW, "vndopen(%x, %x, %x, %p)\n", dev, flags, mode, p);
  158. if (unit >= numvnd)
  159. return (ENXIO);
  160. sc = &vnd_softc[unit];
  161. if ((error = disk_lock(&sc->sc_dk)) != 0)
  162. return (error);
  163. if ((flags & FWRITE) && (sc->sc_flags & VNF_READONLY)) {
  164. error = EROFS;
  165. goto bad;
  166. }
  167. if ((sc->sc_flags & VNF_INITED) &&
  168. (sc->sc_flags & VNF_HAVELABEL) == 0 &&
  169. sc->sc_dk.dk_openmask == 0) {
  170. sc->sc_flags |= VNF_HAVELABEL;
  171. vndgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0);
  172. }
  173. part = DISKPART(dev);
  174. error = disk_openpart(&sc->sc_dk, part, mode,
  175. (sc->sc_flags & VNF_HAVELABEL) != 0);
  176. bad:
  177. disk_unlock(&sc->sc_dk);
  178. return (error);
  179. }
  180. /*
  181. * Load the label information on the named device
  182. */
  183. int
  184. vndgetdisklabel(dev_t dev, struct vnd_softc *sc, struct disklabel *lp,
  185. int spoofonly)
  186. {
  187. memset(lp, 0, sizeof(struct disklabel));
  188. lp->d_secsize = sc->sc_secsize;
  189. lp->d_nsectors = sc->sc_nsectors;
  190. lp->d_ntracks = sc->sc_ntracks;
  191. lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
  192. lp->d_ncylinders = sc->sc_size / lp->d_secpercyl;
  193. strncpy(lp->d_typename, "vnd device", sizeof(lp->d_typename));
  194. lp->d_type = DTYPE_VND;
  195. strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
  196. DL_SETDSIZE(lp, sc->sc_size);
  197. lp->d_flags = 0;
  198. lp->d_version = 1;
  199. lp->d_magic = DISKMAGIC;
  200. lp->d_magic2 = DISKMAGIC;
  201. lp->d_checksum = dkcksum(lp);
  202. /* Call the generic disklabel extraction routine */
  203. return readdisklabel(DISKLABELDEV(dev), vndstrategy, lp, spoofonly);
  204. }
  205. int
  206. vndclose(dev_t dev, int flags, int mode, struct proc *p)
  207. {
  208. int unit = DISKUNIT(dev);
  209. struct vnd_softc *sc;
  210. int part;
  211. DNPRINTF(VDB_FOLLOW, "vndclose(%x, %x, %x, %p)\n", dev, flags, mode, p);
  212. if (unit >= numvnd)
  213. return (ENXIO);
  214. sc = &vnd_softc[unit];
  215. disk_lock_nointr(&sc->sc_dk);
  216. part = DISKPART(dev);
  217. disk_closepart(&sc->sc_dk, part, mode);
  218. #if 0
  219. if (sc->sc_dk.dk_openmask == 0)
  220. sc->sc_flags &= ~VNF_HAVELABEL;
  221. #endif
  222. disk_unlock(&sc->sc_dk);
  223. return (0);
  224. }
  225. void
  226. vndstrategy(struct buf *bp)
  227. {
  228. int unit = DISKUNIT(bp->b_dev);
  229. struct vnd_softc *sc;
  230. struct partition *p;
  231. off_t off;
  232. long origbcount;
  233. int s;
  234. DNPRINTF(VDB_FOLLOW, "vndstrategy(%p): unit %d\n", bp, unit);
  235. if (unit >= numvnd) {
  236. bp->b_error = ENXIO;
  237. goto bad;
  238. }
  239. sc = &vnd_softc[unit];
  240. if ((sc->sc_flags & VNF_HAVELABEL) == 0) {
  241. bp->b_error = ENXIO;
  242. goto bad;
  243. }
  244. /*
  245. * Many of the distrib scripts assume they can issue arbitrary
  246. * sized requests to raw vnd devices irrespective of the
  247. * emulated disk geometry.
  248. *
  249. * To continue supporting this, round the block count up to a
  250. * multiple of d_secsize for bounds_check_with_label(), and
  251. * then restore afterwards.
  252. *
  253. * We only do this for non-encrypted vnd, because encryption
  254. * requires operating on blocks at a time.
  255. */
  256. origbcount = bp->b_bcount;
  257. if (sc->sc_keyctx == NULL) {
  258. u_int32_t secsize = sc->sc_dk.dk_label->d_secsize;
  259. bp->b_bcount = ((origbcount + secsize - 1) & ~(secsize - 1));
  260. #ifdef DIAGNOSTIC
  261. if (bp->b_bcount != origbcount) {
  262. struct proc *pr = curproc;
  263. printf("%s: sloppy %s from proc %d (%s): "
  264. "blkno %lld bcount %ld\n", sc->sc_dev.dv_xname,
  265. (bp->b_flags & B_READ) ? "read" : "write",
  266. pr->p_pid, pr->p_comm, (long long)bp->b_blkno,
  267. origbcount);
  268. }
  269. #endif
  270. }
  271. if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) {
  272. bp->b_resid = bp->b_bcount = origbcount;
  273. goto done;
  274. }
  275. if (origbcount < bp->b_bcount)
  276. bp->b_bcount = origbcount;
  277. p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
  278. off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize +
  279. (u_int64_t)bp->b_blkno * DEV_BSIZE;
  280. if (sc->sc_keyctx && !(bp->b_flags & B_READ))
  281. vndencryptbuf(sc, bp, 1);
  282. /*
  283. * Use IO_NOLIMIT because upper layer has already checked I/O
  284. * for limits, so there is no need to do it again.
  285. */
  286. bp->b_error = vn_rdwr((bp->b_flags & B_READ) ? UIO_READ : UIO_WRITE,
  287. sc->sc_vp, bp->b_data, bp->b_bcount, off, UIO_SYSSPACE, IO_NOLIMIT,
  288. sc->sc_cred, &bp->b_resid, curproc);
  289. if (bp->b_error)
  290. bp->b_flags |= B_ERROR;
  291. /* Data in buffer cache needs to be in clear */
  292. if (sc->sc_keyctx)
  293. vndencryptbuf(sc, bp, 0);
  294. goto done;
  295. bad:
  296. bp->b_flags |= B_ERROR;
  297. bp->b_resid = bp->b_bcount;
  298. done:
  299. s = splbio();
  300. biodone(bp);
  301. splx(s);
  302. }
  303. /* ARGSUSED */
  304. int
  305. vndread(dev_t dev, struct uio *uio, int flags)
  306. {
  307. return (physio(vndstrategy, dev, B_READ, minphys, uio));
  308. }
  309. /* ARGSUSED */
  310. int
  311. vndwrite(dev_t dev, struct uio *uio, int flags)
  312. {
  313. return (physio(vndstrategy, dev, B_WRITE, minphys, uio));
  314. }
  315. size_t
  316. vndbdevsize(struct vnode *vp, struct proc *p)
  317. {
  318. struct partinfo pi;
  319. struct bdevsw *bsw;
  320. dev_t dev;
  321. dev = vp->v_rdev;
  322. bsw = bdevsw_lookup(dev);
  323. if (bsw->d_ioctl == NULL)
  324. return (0);
  325. if (bsw->d_ioctl(dev, DIOCGPART, (caddr_t)&pi, FREAD, p))
  326. return (0);
  327. DNPRINTF(VDB_INIT, "vndbdevsize: size %llu secsize %u\n",
  328. DL_GETPSIZE(pi.part), pi.disklab->d_secsize);
  329. return (DL_GETPSIZE(pi.part));
  330. }
  331. /* ARGSUSED */
  332. int
  333. vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
  334. {
  335. int unit = DISKUNIT(dev);
  336. struct disklabel *lp;
  337. struct vnd_softc *sc;
  338. struct vnd_ioctl *vio;
  339. struct vnd_user *vnu;
  340. struct vattr vattr;
  341. struct nameidata nd;
  342. int error, part, pmask;
  343. DNPRINTF(VDB_FOLLOW, "vndioctl(%x, %lx, %p, %x, %p): unit %d\n",
  344. dev, cmd, addr, flag, p, unit);
  345. error = suser(p, 0);
  346. if (error)
  347. return (error);
  348. if (unit >= numvnd)
  349. return (ENXIO);
  350. sc = &vnd_softc[unit];
  351. vio = (struct vnd_ioctl *)addr;
  352. switch (cmd) {
  353. case VNDIOCSET:
  354. if (sc->sc_flags & VNF_INITED)
  355. return (EBUSY);
  356. /* Geometry eventually has to fit into label fields */
  357. if (vio->vnd_secsize > UINT_MAX ||
  358. vio->vnd_ntracks > UINT_MAX ||
  359. vio->vnd_nsectors > UINT_MAX)
  360. return (EINVAL);
  361. if ((error = disk_lock(&sc->sc_dk)) != 0)
  362. return (error);
  363. if ((error = copyinstr(vio->vnd_file, sc->sc_file,
  364. sizeof(sc->sc_file), NULL))) {
  365. disk_unlock(&sc->sc_dk);
  366. return (error);
  367. }
  368. /* Set geometry for device. */
  369. sc->sc_secsize = vio->vnd_secsize;
  370. sc->sc_ntracks = vio->vnd_ntracks;
  371. sc->sc_nsectors = vio->vnd_nsectors;
  372. /*
  373. * Open for read and write first. This lets vn_open() weed out
  374. * directories, sockets, etc. so we don't have to worry about
  375. * them.
  376. */
  377. NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
  378. sc->sc_flags &= ~VNF_READONLY;
  379. error = vn_open(&nd, FREAD|FWRITE, 0);
  380. if (error == EROFS) {
  381. sc->sc_flags |= VNF_READONLY;
  382. error = vn_open(&nd, FREAD, 0);
  383. }
  384. if (error) {
  385. disk_unlock(&sc->sc_dk);
  386. return (error);
  387. }
  388. if (nd.ni_vp->v_type == VBLK)
  389. sc->sc_size = vndbdevsize(nd.ni_vp, p);
  390. else {
  391. error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
  392. if (error) {
  393. VOP_UNLOCK(nd.ni_vp, 0, p);
  394. vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p);
  395. disk_unlock(&sc->sc_dk);
  396. return (error);
  397. }
  398. sc->sc_size = vattr.va_size / sc->sc_secsize;
  399. }
  400. VOP_UNLOCK(nd.ni_vp, 0, p);
  401. sc->sc_vp = nd.ni_vp;
  402. if ((error = vndsetcred(sc, p->p_ucred)) != 0) {
  403. (void) vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p);
  404. disk_unlock(&sc->sc_dk);
  405. return (error);
  406. }
  407. if (vio->vnd_keylen > 0) {
  408. char key[BLF_MAXUTILIZED];
  409. if (vio->vnd_keylen > sizeof(key))
  410. vio->vnd_keylen = sizeof(key);
  411. if ((error = copyin(vio->vnd_key, key,
  412. vio->vnd_keylen)) != 0) {
  413. (void) vn_close(nd.ni_vp, VNDRW(sc),
  414. p->p_ucred, p);
  415. disk_unlock(&sc->sc_dk);
  416. return (error);
  417. }
  418. sc->sc_keyctx = malloc(sizeof(*sc->sc_keyctx), M_DEVBUF,
  419. M_WAITOK);
  420. blf_key(sc->sc_keyctx, key, vio->vnd_keylen);
  421. explicit_bzero(key, vio->vnd_keylen);
  422. } else
  423. sc->sc_keyctx = NULL;
  424. vio->vnd_size = sc->sc_size * sc->sc_secsize;
  425. sc->sc_flags |= VNF_INITED;
  426. DNPRINTF(VDB_INIT, "vndioctl: SET vp %p size %llx\n",
  427. sc->sc_vp, (unsigned long long)sc->sc_size);
  428. /* Attach the disk. */
  429. sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
  430. disk_attach(&sc->sc_dev, &sc->sc_dk);
  431. disk_unlock(&sc->sc_dk);
  432. break;
  433. case VNDIOCCLR:
  434. if ((sc->sc_flags & VNF_INITED) == 0)
  435. return (ENXIO);
  436. if ((error = disk_lock(&sc->sc_dk)) != 0)
  437. return (error);
  438. /*
  439. * Don't unconfigure if any other partitions are open
  440. * or if both the character and block flavors of this
  441. * partition are open.
  442. */
  443. part = DISKPART(dev);
  444. pmask = (1 << part);
  445. if ((sc->sc_dk.dk_openmask & ~pmask) ||
  446. ((sc->sc_dk.dk_bopenmask & pmask) &&
  447. (sc->sc_dk.dk_copenmask & pmask))) {
  448. disk_unlock(&sc->sc_dk);
  449. return (EBUSY);
  450. }
  451. vndclear(sc);
  452. DNPRINTF(VDB_INIT, "vndioctl: CLRed\n");
  453. /* Free crypto key */
  454. if (sc->sc_keyctx) {
  455. explicit_bzero(sc->sc_keyctx, sizeof(*sc->sc_keyctx));
  456. free(sc->sc_keyctx, M_DEVBUF, 0);
  457. }
  458. /* Detach the disk. */
  459. disk_detach(&sc->sc_dk);
  460. disk_unlock(&sc->sc_dk);
  461. break;
  462. case VNDIOCGET:
  463. vnu = (struct vnd_user *)addr;
  464. if (vnu->vnu_unit == -1)
  465. vnu->vnu_unit = unit;
  466. if (vnu->vnu_unit >= numvnd)
  467. return (ENXIO);
  468. if (vnu->vnu_unit < 0)
  469. return (EINVAL);
  470. sc = &vnd_softc[vnu->vnu_unit];
  471. if (sc->sc_flags & VNF_INITED) {
  472. error = VOP_GETATTR(sc->sc_vp, &vattr, p->p_ucred, p);
  473. if (error)
  474. return (error);
  475. strlcpy(vnu->vnu_file, sc->sc_file,
  476. sizeof(vnu->vnu_file));
  477. vnu->vnu_dev = vattr.va_fsid;
  478. vnu->vnu_ino = vattr.va_fileid;
  479. } else {
  480. vnu->vnu_dev = 0;
  481. vnu->vnu_ino = 0;
  482. }
  483. break;
  484. case DIOCRLDINFO:
  485. if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  486. return (ENOTTY);
  487. lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
  488. vndgetdisklabel(dev, sc, lp, 0);
  489. *(sc->sc_dk.dk_label) = *lp;
  490. free(lp, M_TEMP, 0);
  491. return (0);
  492. case DIOCGPDINFO:
  493. if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  494. return (ENOTTY);
  495. vndgetdisklabel(dev, sc, (struct disklabel *)addr, 1);
  496. return (0);
  497. case DIOCGDINFO:
  498. if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  499. return (ENOTTY);
  500. *(struct disklabel *)addr = *(sc->sc_dk.dk_label);
  501. return (0);
  502. case DIOCGPART:
  503. if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  504. return (ENOTTY);
  505. ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
  506. ((struct partinfo *)addr)->part =
  507. &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)];
  508. return (0);
  509. case DIOCWDINFO:
  510. case DIOCSDINFO:
  511. if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  512. return (ENOTTY);
  513. if ((flag & FWRITE) == 0)
  514. return (EBADF);
  515. if ((error = disk_lock(&sc->sc_dk)) != 0)
  516. return (error);
  517. error = setdisklabel(sc->sc_dk.dk_label,
  518. (struct disklabel *)addr, /* sc->sc_dk.dk_openmask */ 0);
  519. if (error == 0) {
  520. if (cmd == DIOCWDINFO)
  521. error = writedisklabel(DISKLABELDEV(dev),
  522. vndstrategy, sc->sc_dk.dk_label);
  523. }
  524. disk_unlock(&sc->sc_dk);
  525. return (error);
  526. default:
  527. return (ENOTTY);
  528. }
  529. return (0);
  530. }
  531. /*
  532. * Duplicate the current processes' credentials. Since we are called only
  533. * as the result of a SET ioctl and only root can do that, any future access
  534. * to this "disk" is essentially as root. Note that credentials may change
  535. * if some other uid can write directly to the mapped file (NFS).
  536. */
  537. int
  538. vndsetcred(struct vnd_softc *sc, struct ucred *cred)
  539. {
  540. void *buf;
  541. size_t size;
  542. int error;
  543. sc->sc_cred = crdup(cred);
  544. buf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
  545. size = MIN(DEV_BSIZE, sc->sc_size * sc->sc_secsize);
  546. /* XXX: Horrible kludge to establish credentials for NFS */
  547. error = vn_rdwr(UIO_READ, sc->sc_vp, buf, size, 0, UIO_SYSSPACE, 0,
  548. sc->sc_cred, NULL, curproc);
  549. free(buf, M_TEMP, 0);
  550. return (error);
  551. }
  552. void
  553. vndclear(struct vnd_softc *sc)
  554. {
  555. struct vnode *vp = sc->sc_vp;
  556. struct proc *p = curproc; /* XXX */
  557. DNPRINTF(VDB_FOLLOW, "vndclear(%p): vp %p\n", sc, vp);
  558. if (vp == NULL)
  559. panic("vndioctl: null vp");
  560. (void) vn_close(vp, VNDRW(sc), sc->sc_cred, p);
  561. crfree(sc->sc_cred);
  562. sc->sc_flags = 0;
  563. sc->sc_vp = NULL;
  564. sc->sc_cred = NULL;
  565. sc->sc_size = 0;
  566. memset(sc->sc_file, 0, sizeof(sc->sc_file));
  567. }
  568. daddr_t
  569. vndsize(dev_t dev)
  570. {
  571. /* We don't support swapping to vnd anymore. */
  572. return (-1);
  573. }
  574. int
  575. vnddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
  576. {
  577. /* Not implemented. */
  578. return (ENXIO);
  579. }