1 /* $OpenBSD: nfs_serv.c,v 1.109 2016/07/04 18:34:03 natano Exp $ */ 2 /* $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 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 * Rick Macklem at The University of Guelph. 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 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95 36 */ 37 38 /* 39 * nfs version 2 and 3 server calls to vnode ops 40 * - these routines generally have 3 phases 41 * 1 - break down and validate rpc request in mbuf list 42 * 2 - do the vnode ops for the request 43 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 44 * 3 - build the rpc reply in an mbuf list 45 * nb: 46 * - do not mix the phases, since the nfsm_?? macros can return failures 47 * on a bad rpc or similar and do not do any vrele() or vput()'s 48 * 49 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 50 * error number iff error != 0 whereas 51 * returning an error from the server function implies a fatal error 52 * such as a badly constructed rpc request that should be dropped without 53 * a reply. 54 * For Version 3, nfsm_reply() does not return for the error case, since 55 * most version 3 rpcs return more than the status for error cases. 56 */ 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/proc.h> 61 #include <sys/file.h> 62 #include <sys/namei.h> 63 #include <sys/vnode.h> 64 #include <sys/lock.h> 65 #include <sys/mount.h> 66 #include <sys/socket.h> 67 #include <sys/socketvar.h> 68 #include <sys/mbuf.h> 69 #include <sys/dirent.h> 70 #include <sys/stat.h> 71 #include <sys/kernel.h> 72 #include <sys/pool.h> 73 #include <sys/queue.h> 74 #include <sys/unistd.h> 75 76 #include <ufs/ufs/dir.h> 77 78 #include <nfs/nfsproto.h> 79 #include <nfs/nfs.h> 80 #include <nfs/xdr_subs.h> 81 #include <nfs/nfsm_subs.h> 82 #include <nfs/nfs_var.h> 83 84 /* Global vars */ 85 extern u_int32_t nfs_xdrneg1; 86 extern u_int32_t nfs_false, nfs_true; 87 extern enum vtype nv3tov_type[8]; 88 extern struct nfsstats nfsstats; 89 extern nfstype nfsv2_type[9]; 90 extern nfstype nfsv3_type[9]; 91 92 /* 93 * nfs v3 access service 94 */ 95 int 96 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 97 struct proc *procp, struct mbuf **mrq) 98 { 99 struct mbuf *nam = nfsd->nd_nam; 100 struct nfsm_info info; 101 struct ucred *cred = &nfsd->nd_cr; 102 struct vnode *vp; 103 nfsfh_t nfh; 104 fhandle_t *fhp; 105 u_int32_t *tl; 106 int32_t t1; 107 int error = 0, rdonly, getret; 108 char *cp2; 109 struct vattr va; 110 u_long testmode, nfsmode; 111 112 info.nmi_mreq = NULL; 113 info.nmi_mrep = nfsd->nd_mrep; 114 info.nmi_md = nfsd->nd_md; 115 info.nmi_dpos = nfsd->nd_dpos; 116 117 fhp = &nfh.fh_generic; 118 nfsm_srvmtofh(fhp); 119 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 120 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 121 if (error) { 122 nfsm_reply(NFSX_UNSIGNED); 123 nfsm_srvpostop_attr(nfsd, 1, NULL, &info); 124 error = 0; 125 goto nfsmout; 126 } 127 nfsmode = fxdr_unsigned(u_int32_t, *tl); 128 if ((nfsmode & NFSV3ACCESS_READ) && 129 nfsrv_access(vp, VREAD, cred, rdonly, procp, 0)) 130 nfsmode &= ~NFSV3ACCESS_READ; 131 if (vp->v_type == VDIR) 132 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | 133 NFSV3ACCESS_DELETE); 134 else 135 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); 136 if ((nfsmode & testmode) && 137 nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0)) 138 nfsmode &= ~testmode; 139 if (vp->v_type == VDIR) 140 testmode = NFSV3ACCESS_LOOKUP; 141 else 142 testmode = NFSV3ACCESS_EXECUTE; 143 if ((nfsmode & testmode) && 144 nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0)) 145 nfsmode &= ~testmode; 146 getret = VOP_GETATTR(vp, &va, cred, procp); 147 vput(vp); 148 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); 149 nfsm_srvpostop_attr(nfsd, getret, &va, &info); 150 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 151 *tl = txdr_unsigned(nfsmode); 152 nfsmout: 153 return(error); 154 } 155 156 /* 157 * nfs getattr service 158 */ 159 int 160 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 161 struct proc *procp, struct mbuf **mrq) 162 { 163 struct mbuf *nam = nfsd->nd_nam; 164 struct nfsm_info info; 165 struct ucred *cred = &nfsd->nd_cr; 166 struct nfs_fattr *fp; 167 struct vattr va; 168 struct vnode *vp; 169 nfsfh_t nfh; 170 fhandle_t *fhp; 171 u_int32_t *tl; 172 int32_t t1; 173 int error = 0, rdonly; 174 char *cp2; 175 176 info.nmi_mreq = NULL; 177 info.nmi_mrep = nfsd->nd_mrep; 178 info.nmi_md = nfsd->nd_md; 179 info.nmi_dpos = nfsd->nd_dpos; 180 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 181 182 fhp = &nfh.fh_generic; 183 nfsm_srvmtofh(fhp); 184 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 185 if (error) { 186 nfsm_reply(0); 187 error = 0; 188 goto nfsmout; 189 } 190 error = VOP_GETATTR(vp, &va, cred, procp); 191 vput(vp); 192 nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 193 if (error) { 194 error = 0; 195 goto nfsmout; 196 } 197 fp = nfsm_build(&info.nmi_mb, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 198 nfsm_srvfattr(nfsd, &va, fp); 199 nfsmout: 200 return(error); 201 } 202 203 /* 204 * nfs setattr service 205 */ 206 int 207 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 208 struct proc *procp, struct mbuf **mrq) 209 { 210 struct mbuf *nam = nfsd->nd_nam; 211 struct nfsm_info info; 212 struct ucred *cred = &nfsd->nd_cr; 213 struct vattr va, preat; 214 struct nfsv2_sattr *sp; 215 struct nfs_fattr *fp; 216 struct vnode *vp; 217 nfsfh_t nfh; 218 fhandle_t *fhp; 219 u_int32_t *tl; 220 int32_t t1; 221 int error = 0, rdonly, preat_ret = 1, postat_ret = 1; 222 int gcheck = 0; 223 char *cp2; 224 struct timespec guard; 225 226 info.nmi_mreq = NULL; 227 info.nmi_mrep = nfsd->nd_mrep; 228 info.nmi_md = nfsd->nd_md; 229 info.nmi_dpos = nfsd->nd_dpos; 230 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 231 232 fhp = &nfh.fh_generic; 233 nfsm_srvmtofh(fhp); 234 VATTR_NULL(&va); 235 if (info.nmi_v3) { 236 va.va_vaflags |= VA_UTIMES_NULL; 237 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos); 238 if (error) 239 goto nfsmout; 240 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 241 gcheck = fxdr_unsigned(int, *tl); 242 if (gcheck) { 243 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 244 fxdr_nfsv3time(tl, &guard); 245 } 246 } else { 247 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 248 /* 249 * Nah nah nah nah na nah 250 * There is a bug in the Sun client that puts 0xffff in the mode 251 * field of sattr when it should put in 0xffffffff. The u_short 252 * doesn't sign extend. 253 * --> check the low order 2 bytes for 0xffff 254 */ 255 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 256 va.va_mode = nfstov_mode(sp->sa_mode); 257 if (sp->sa_uid != nfs_xdrneg1) 258 va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 259 if (sp->sa_gid != nfs_xdrneg1) 260 va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 261 if (sp->sa_size != nfs_xdrneg1) 262 va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size); 263 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { 264 #ifdef notyet 265 fxdr_nfsv2time(&sp->sa_atime, &va.va_atime); 266 #else 267 va.va_atime.tv_sec = 268 fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec); 269 va.va_atime.tv_nsec = 0; 270 #endif 271 } 272 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) 273 fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime); 274 275 } 276 277 /* 278 * Now that we have all the fields, lets do it. 279 */ 280 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 281 if (error) { 282 nfsm_reply(2 * NFSX_UNSIGNED); 283 nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, &info); 284 error = 0; 285 goto nfsmout; 286 } 287 if (info.nmi_v3) { 288 error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp); 289 if (!error && gcheck && 290 (preat.va_ctime.tv_sec != guard.tv_sec || 291 preat.va_ctime.tv_nsec != guard.tv_nsec)) 292 error = NFSERR_NOT_SYNC; 293 if (error) { 294 vput(vp); 295 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 296 nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, 297 &info); 298 error = 0; 299 goto nfsmout; 300 } 301 } 302 303 /* 304 * If the size is being changed write acces is required, otherwise 305 * just check for a read only file system. 306 */ 307 if (va.va_size == ((u_quad_t)((quad_t) -1))) { 308 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 309 error = EROFS; 310 goto out; 311 } 312 } else { 313 if (vp->v_type == VDIR) { 314 error = EISDIR; 315 goto out; 316 } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly, 317 procp, 1)) != 0) 318 goto out; 319 } 320 error = VOP_SETATTR(vp, &va, cred, procp); 321 postat_ret = VOP_GETATTR(vp, &va, cred, procp); 322 if (!error) 323 error = postat_ret; 324 out: 325 vput(vp); 326 nfsm_reply(NFSX_WCCORFATTR(info.nmi_v3)); 327 if (info.nmi_v3) { 328 nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, 329 &info); 330 error = 0; 331 goto nfsmout; 332 } else { 333 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 334 nfsm_srvfattr(nfsd, &va, fp); 335 } 336 nfsmout: 337 return(error); 338 } 339 340 /* 341 * nfs lookup rpc 342 */ 343 int 344 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 345 struct proc *procp, struct mbuf **mrq) 346 { 347 struct mbuf *nam = nfsd->nd_nam; 348 struct ucred *cred = &nfsd->nd_cr; 349 struct nfs_fattr *fp; 350 struct nameidata nd; 351 struct vnode *vp, *dirp; 352 struct nfsm_info info; 353 nfsfh_t nfh; 354 fhandle_t *fhp; 355 u_int32_t *tl; 356 int32_t t1; 357 int error = 0, len, dirattr_ret = 1; 358 int v3 = (nfsd->nd_flag & ND_NFSV3); 359 char *cp2; 360 struct vattr va, dirattr; 361 362 info.nmi_mrep = nfsd->nd_mrep; 363 info.nmi_mreq = NULL; 364 info.nmi_md = nfsd->nd_md; 365 info.nmi_dpos = nfsd->nd_dpos; 366 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 367 368 fhp = &nfh.fh_generic; 369 nfsm_srvmtofh(fhp); 370 nfsm_srvnamesiz(len); 371 372 NDINIT(&nd, LOOKUP, LOCKLEAF | SAVESTART, UIO_SYSSPACE, NULL, procp); 373 nd.ni_cnd.cn_cred = cred; 374 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp); 375 if (dirp) { 376 if (info.nmi_v3) 377 dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, 378 procp); 379 vrele(dirp); 380 } 381 if (error) { 382 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3)); 383 nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info); 384 return (0); 385 } 386 vrele(nd.ni_startdir); 387 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 388 vp = nd.ni_vp; 389 memset(fhp, 0, sizeof(nfh)); 390 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 391 error = VFS_VPTOFH(vp, &fhp->fh_fid); 392 if (!error) 393 error = VOP_GETATTR(vp, &va, cred, procp); 394 vput(vp); 395 nfsm_reply(NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) 396 + NFSX_POSTOPATTR(info.nmi_v3)); 397 if (error) { 398 nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info); 399 error = 0; 400 goto nfsmout; 401 } 402 nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3); 403 if (v3) { 404 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 405 nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info); 406 } else { 407 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 408 nfsm_srvfattr(nfsd, &va, fp); 409 } 410 nfsmout: 411 return(error); 412 } 413 414 /* 415 * nfs readlink service 416 */ 417 int 418 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 419 struct proc *procp, struct mbuf **mrq) 420 { 421 struct mbuf *nam = nfsd->nd_nam; 422 struct ucred *cred = &nfsd->nd_cr; 423 struct iovec iov; 424 struct mbuf *mp = NULL; 425 struct nfsm_info info; 426 u_int32_t *tl; 427 int32_t t1; 428 int error = 0, rdonly, tlen, len = 0, getret; 429 char *cp2; 430 struct vnode *vp; 431 struct vattr attr; 432 nfsfh_t nfh; 433 fhandle_t *fhp; 434 struct uio uio; 435 436 info.nmi_mreq = NULL; 437 info.nmi_mrep = nfsd->nd_mrep; 438 info.nmi_md = nfsd->nd_md; 439 info.nmi_dpos = nfsd->nd_dpos; 440 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 441 442 memset(&uio, 0, sizeof(uio)); 443 444 fhp = &nfh.fh_generic; 445 nfsm_srvmtofh(fhp); 446 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 447 if (error) { 448 nfsm_reply(2 * NFSX_UNSIGNED); 449 nfsm_srvpostop_attr(nfsd, 1, NULL, &info); 450 error = 0; 451 goto nfsmout; 452 } 453 if (vp->v_type != VLNK) { 454 if (info.nmi_v3) 455 error = EINVAL; 456 else 457 error = ENXIO; 458 goto out; 459 } 460 461 MGET(mp, M_WAIT, MT_DATA); 462 MCLGET(mp, M_WAIT); /* MLEN < NFS_MAXPATHLEN < MCLBYTES */ 463 mp->m_len = NFS_MAXPATHLEN; 464 len = NFS_MAXPATHLEN; 465 iov.iov_base = mtod(mp, caddr_t); 466 iov.iov_len = mp->m_len; 467 468 uio.uio_iov = &iov; 469 uio.uio_iovcnt = 1; 470 uio.uio_offset = 0; 471 uio.uio_resid = NFS_MAXPATHLEN; 472 uio.uio_rw = UIO_READ; 473 uio.uio_segflg = UIO_SYSSPACE; 474 uio.uio_procp = NULL; 475 476 error = VOP_READLINK(vp, &uio, cred); 477 out: 478 getret = VOP_GETATTR(vp, &attr, cred, procp); 479 vput(vp); 480 if (error) 481 m_freem(mp); 482 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_UNSIGNED); 483 if (info.nmi_v3) { 484 nfsm_srvpostop_attr(nfsd, getret, &attr, &info); 485 if (error) { 486 error = 0; 487 goto nfsmout; 488 } 489 } 490 if (uio.uio_resid > 0) { 491 len -= uio.uio_resid; 492 tlen = nfsm_rndup(len); 493 nfsm_adj(mp, NFS_MAXPATHLEN-tlen, tlen-len); 494 } 495 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 496 *tl = txdr_unsigned(len); 497 info.nmi_mb->m_next = mp; 498 499 nfsmout: 500 return (error); 501 } 502 503 /* 504 * nfs read service 505 */ 506 int 507 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 508 struct proc *procp, struct mbuf **mrq) 509 { 510 struct mbuf *nam = nfsd->nd_nam; 511 struct ucred *cred = &nfsd->nd_cr; 512 struct mbuf *m; 513 struct nfs_fattr *fp; 514 struct nfsm_info info; 515 u_int32_t *tl; 516 int32_t t1; 517 int i, reqlen; 518 int error = 0, rdonly, cnt, len, left, siz, tlen, getret = 1; 519 char *cp2; 520 struct mbuf *m2; 521 struct vnode *vp; 522 nfsfh_t nfh; 523 fhandle_t *fhp; 524 struct uio io, *uiop = &io; 525 struct vattr va; 526 off_t off; 527 528 info.nmi_mreq = NULL; 529 info.nmi_mrep = nfsd->nd_mrep; 530 info.nmi_md = nfsd->nd_md; 531 info.nmi_dpos = nfsd->nd_dpos; 532 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 533 534 fhp = &nfh.fh_generic; 535 nfsm_srvmtofh(fhp); 536 if (info.nmi_v3) { 537 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 538 off = fxdr_hyper(tl); 539 } else { 540 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 541 off = (off_t)fxdr_unsigned(u_int32_t, *tl); 542 } 543 544 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 545 reqlen = fxdr_unsigned(int32_t, *tl); 546 if (reqlen > (NFS_SRVMAXDATA(nfsd)) || reqlen <= 0) { 547 error = EBADRPC; 548 nfsm_reply(0); 549 } 550 551 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 552 if (error) 553 goto bad; 554 555 if (vp->v_type != VREG) { 556 if (info.nmi_v3) 557 error = EINVAL; 558 else 559 error = (vp->v_type == VDIR) ? EISDIR : EACCES; 560 } 561 if (!error) { 562 if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0) 563 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 1); 564 } 565 getret = VOP_GETATTR(vp, &va, cred, procp); 566 if (!error) 567 error = getret; 568 if (error) 569 goto vbad; 570 571 if (off >= va.va_size) 572 cnt = 0; 573 else if ((off + reqlen) > va.va_size) 574 cnt = va.va_size - off; 575 else 576 cnt = reqlen; 577 nfsm_reply(NFSX_POSTOPORFATTR(info.nmi_v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)); 578 if (info.nmi_v3) { 579 tl = nfsm_build(&info.nmi_mb, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); 580 *tl++ = nfs_true; 581 fp = (struct nfs_fattr *)tl; 582 tl += (NFSX_V3FATTR / sizeof (u_int32_t)); 583 } else { 584 tl = nfsm_build(&info.nmi_mb, NFSX_V2FATTR + NFSX_UNSIGNED); 585 fp = (struct nfs_fattr *)tl; 586 tl += (NFSX_V2FATTR / sizeof (u_int32_t)); 587 } 588 len = left = nfsm_rndup (cnt); 589 if (cnt > 0) { 590 struct iovec *iv, *iv2; 591 size_t ivlen; 592 /* 593 * Generate the mbuf list with the uio_iov ref. to it. 594 */ 595 i = 0; 596 m = m2 = info.nmi_mb; 597 while (left > 0) { 598 siz = min(M_TRAILINGSPACE(m), left); 599 if (siz > 0) { 600 left -= siz; 601 i++; 602 } 603 if (left > 0) { 604 MGET(m, M_WAIT, MT_DATA); 605 if (left >= MINCLSIZE) 606 MCLGET(m, M_WAIT); 607 m->m_len = 0; 608 m2->m_next = m; 609 m2 = m; 610 } 611 } 612 iv = mallocarray(i, sizeof(*iv), M_TEMP, M_WAITOK); 613 ivlen = i * sizeof(*iv); 614 uiop->uio_iov = iv2 = iv; 615 m = info.nmi_mb; 616 left = len; 617 i = 0; 618 while (left > 0) { 619 if (m == NULL) 620 panic("nfsrv_read iov"); 621 siz = min(M_TRAILINGSPACE(m), left); 622 if (siz > 0) { 623 iv->iov_base = mtod(m, caddr_t) + m->m_len; 624 iv->iov_len = siz; 625 m->m_len += siz; 626 left -= siz; 627 iv++; 628 i++; 629 } 630 m = m->m_next; 631 } 632 uiop->uio_iovcnt = i; 633 uiop->uio_offset = off; 634 uiop->uio_resid = len; 635 uiop->uio_rw = UIO_READ; 636 uiop->uio_segflg = UIO_SYSSPACE; 637 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 638 off = uiop->uio_offset; 639 free(iv2, M_TEMP, ivlen); 640 if (error || (getret = VOP_GETATTR(vp, &va, cred, procp)) != 0){ 641 if (!error) 642 error = getret; 643 m_freem(info.nmi_mreq); 644 goto vbad; 645 } 646 } else 647 uiop->uio_resid = 0; 648 vput(vp); 649 nfsm_srvfattr(nfsd, &va, fp); 650 tlen = len - uiop->uio_resid; 651 cnt = cnt < tlen ? cnt : tlen; 652 tlen = nfsm_rndup (cnt); 653 if (len != tlen || tlen != cnt) 654 nfsm_adj(info.nmi_mb, len - tlen, tlen - cnt); 655 if (info.nmi_v3) { 656 *tl++ = txdr_unsigned(cnt); 657 if (len < reqlen) 658 *tl++ = nfs_true; 659 else 660 *tl++ = nfs_false; 661 } 662 *tl = txdr_unsigned(cnt); 663 nfsmout: 664 return(error); 665 666 vbad: 667 vput(vp); 668 bad: 669 nfsm_reply(0); 670 nfsm_srvpostop_attr(nfsd, getret, &va, &info); 671 return (0); 672 } 673 674 /* 675 * nfs write service 676 */ 677 int 678 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 679 struct proc *procp, struct mbuf **mrq) 680 { 681 struct mbuf *nam = nfsd->nd_nam; 682 struct ucred *cred = &nfsd->nd_cr; 683 struct nfsm_info info; 684 int i, cnt; 685 struct mbuf *mp; 686 struct nfs_fattr *fp; 687 struct vattr va, forat; 688 u_int32_t *tl; 689 int32_t t1; 690 int error = 0, rdonly, len, forat_ret = 1; 691 int ioflags, aftat_ret = 1, retlen, zeroing, adjust; 692 int stable = NFSV3WRITE_FILESYNC; 693 char *cp2; 694 struct vnode *vp; 695 nfsfh_t nfh; 696 fhandle_t *fhp; 697 struct uio io, *uiop = &io; 698 off_t off; 699 700 info.nmi_mreq = NULL; 701 info.nmi_mrep = nfsd->nd_mrep; 702 info.nmi_md = nfsd->nd_md; 703 info.nmi_dpos = nfsd->nd_dpos; 704 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 705 706 if (info.nmi_mrep == NULL) { 707 *mrq = NULL; 708 return (0); 709 } 710 fhp = &nfh.fh_generic; 711 nfsm_srvmtofh(fhp); 712 if (info.nmi_v3) { 713 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 714 off = fxdr_hyper(tl); 715 tl += 3; 716 stable = fxdr_unsigned(int, *tl++); 717 } else { 718 nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 719 off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 720 tl += 2; 721 } 722 retlen = len = fxdr_unsigned(int32_t, *tl); 723 cnt = i = 0; 724 725 /* 726 * For NFS Version 2, it is not obvious what a write of zero length 727 * should do, but I might as well be consistent with Version 3, 728 * which is to return ok so long as there are no permission problems. 729 */ 730 if (len > 0) { 731 zeroing = 1; 732 mp = info.nmi_mrep; 733 while (mp) { 734 if (mp == info.nmi_md) { 735 zeroing = 0; 736 adjust = info.nmi_dpos - mtod(mp, caddr_t); 737 mp->m_len -= adjust; 738 if (mp->m_len > 0 && adjust > 0) 739 mp->m_data += adjust; 740 } 741 if (zeroing) 742 mp->m_len = 0; 743 else if (mp->m_len > 0) { 744 i += mp->m_len; 745 if (i > len) { 746 mp->m_len -= (i - len); 747 zeroing = 1; 748 } 749 if (mp->m_len > 0) 750 cnt++; 751 } 752 mp = mp->m_next; 753 } 754 } 755 if (len > NFS_MAXDATA || len < 0 || i < len) { 756 error = EIO; 757 goto bad; 758 } 759 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 760 if (error) 761 goto bad; 762 if (info.nmi_v3) 763 forat_ret = VOP_GETATTR(vp, &forat, cred, procp); 764 if (vp->v_type != VREG) { 765 if (info.nmi_v3) 766 error = EINVAL; 767 else 768 error = (vp->v_type == VDIR) ? EISDIR : EACCES; 769 goto vbad; 770 } 771 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1); 772 if (error) 773 goto vbad; 774 775 if (len > 0) { 776 struct iovec *iv, *ivp; 777 size_t ivlen; 778 779 ivp = mallocarray(cnt, sizeof(*ivp), M_TEMP, M_WAITOK); 780 ivlen = cnt * sizeof(*ivp); 781 uiop->uio_iov = iv = ivp; 782 uiop->uio_iovcnt = cnt; 783 mp = info.nmi_mrep; 784 while (mp) { 785 if (mp->m_len > 0) { 786 ivp->iov_base = mtod(mp, caddr_t); 787 ivp->iov_len = mp->m_len; 788 ivp++; 789 } 790 mp = mp->m_next; 791 } 792 793 if (stable == NFSV3WRITE_UNSTABLE) 794 ioflags = IO_NODELOCKED; 795 else if (stable == NFSV3WRITE_DATASYNC) 796 ioflags = (IO_SYNC | IO_NODELOCKED); 797 else 798 ioflags = (IO_SYNC | IO_NODELOCKED); 799 uiop->uio_resid = len; 800 uiop->uio_rw = UIO_WRITE; 801 uiop->uio_segflg = UIO_SYSSPACE; 802 uiop->uio_procp = NULL; 803 uiop->uio_offset = off; 804 error = VOP_WRITE(vp, uiop, ioflags, cred); 805 nfsstats.srvvop_writes++; 806 free(iv, M_TEMP, ivlen); 807 } 808 aftat_ret = VOP_GETATTR(vp, &va, cred, procp); 809 vput(vp); 810 if (!error) 811 error = aftat_ret; 812 nfsm_reply(NFSX_PREOPATTR(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) + 813 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(info.nmi_v3)); 814 if (info.nmi_v3) { 815 nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info); 816 if (error) { 817 error = 0; 818 goto nfsmout; 819 } 820 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 821 *tl++ = txdr_unsigned(retlen); 822 if (stable == NFSV3WRITE_UNSTABLE) 823 *tl++ = txdr_unsigned(stable); 824 else 825 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); 826 /* 827 * Actually, there is no need to txdr these fields, 828 * but it may make the values more human readable, 829 * for debugging purposes. 830 */ 831 *tl++ = txdr_unsigned(boottime.tv_sec); 832 *tl = txdr_unsigned(boottime.tv_nsec/1000); 833 } else { 834 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 835 nfsm_srvfattr(nfsd, &va, fp); 836 } 837 nfsmout: 838 return(error); 839 840 vbad: 841 vput(vp); 842 bad: 843 nfsm_reply(0); 844 nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info); 845 return (0); 846 } 847 848 /* 849 * nfs create service 850 * now does a truncate to 0 length via. setattr if it already exists 851 */ 852 int 853 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 854 struct proc *procp, struct mbuf **mrq) 855 { 856 struct mbuf *nam = nfsd->nd_nam; 857 struct ucred *cred = &nfsd->nd_cr; 858 struct nfs_fattr *fp; 859 struct vattr va, dirfor, diraft; 860 struct nfsv2_sattr *sp; 861 struct nfsm_info info; 862 u_int32_t *tl; 863 struct nameidata nd; 864 caddr_t cp; 865 int32_t t1; 866 int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1; 867 dev_t rdev = 0; 868 int how, exclusive_flag = 0; 869 char *cp2; 870 struct vnode *vp = NULL, *dirp = NULL; 871 nfsfh_t nfh; 872 fhandle_t *fhp; 873 u_quad_t tempsize; 874 u_char cverf[NFSX_V3CREATEVERF]; 875 876 info.nmi_mreq = NULL; 877 info.nmi_mrep = nfsd->nd_mrep; 878 info.nmi_md = nfsd->nd_md; 879 info.nmi_dpos = nfsd->nd_dpos; 880 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 881 882 fhp = &nfh.fh_generic; 883 nfsm_srvmtofh(fhp); 884 nfsm_srvnamesiz(len); 885 886 NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE, 887 NULL, procp); 888 nd.ni_cnd.cn_cred = cred; 889 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 890 &info.nmi_dpos, &dirp, procp); 891 if (dirp) { 892 if (info.nmi_v3) 893 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 894 else { 895 vrele(dirp); 896 dirp = NULL; 897 } 898 } 899 if (error) { 900 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 901 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 902 &info); 903 if (dirp) 904 vrele(dirp); 905 return (0); 906 } 907 908 VATTR_NULL(&va); 909 if (info.nmi_v3) { 910 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 911 how = fxdr_unsigned(int, *tl); 912 switch (how) { 913 case NFSV3CREATE_GUARDED: 914 if (nd.ni_vp) { 915 error = EEXIST; 916 break; 917 } 918 case NFSV3CREATE_UNCHECKED: 919 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 920 &info.nmi_dpos); 921 if (error) 922 goto nfsmout; 923 break; 924 case NFSV3CREATE_EXCLUSIVE: 925 nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF); 926 bcopy(cp, cverf, NFSX_V3CREATEVERF); 927 exclusive_flag = 1; 928 if (nd.ni_vp == NULL) 929 va.va_mode = 0; 930 break; 931 }; 932 va.va_type = VREG; 933 } else { 934 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 935 va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 936 if (va.va_type == VNON) 937 va.va_type = VREG; 938 va.va_mode = nfstov_mode(sp->sa_mode); 939 switch (va.va_type) { 940 case VREG: 941 tsize = fxdr_unsigned(int32_t, sp->sa_size); 942 if (tsize != -1) 943 va.va_size = (u_quad_t)tsize; 944 break; 945 case VCHR: 946 case VBLK: 947 case VFIFO: 948 rdev = (dev_t)fxdr_unsigned(int32_t, sp->sa_size); 949 break; 950 default: 951 break; 952 }; 953 } 954 955 /* 956 * Iff doesn't exist, create it 957 * otherwise just truncate to 0 length 958 * should I set the mode too ?? 959 */ 960 if (nd.ni_vp == NULL) { 961 if (va.va_type == VREG || va.va_type == VSOCK) { 962 vrele(nd.ni_startdir); 963 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 964 if (!error) { 965 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 966 if (exclusive_flag) { 967 exclusive_flag = 0; 968 VATTR_NULL(&va); 969 bcopy(cverf, (caddr_t)&va.va_atime, 970 NFSX_V3CREATEVERF); 971 error = VOP_SETATTR(nd.ni_vp, &va, cred, 972 procp); 973 } 974 } 975 } else if (va.va_type == VCHR || va.va_type == VBLK || 976 va.va_type == VFIFO) { 977 if (va.va_type == VCHR && rdev == 0xffffffff) 978 va.va_type = VFIFO; 979 if (va.va_type != VFIFO && 980 (error = suser_ucred(cred))) { 981 vrele(nd.ni_startdir); 982 if (nd.ni_cnd.cn_flags & HASBUF) { 983 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 984 nd.ni_cnd.cn_flags &= ~HASBUF; 985 } 986 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 987 vput(nd.ni_dvp); 988 nfsm_reply(0); 989 error = 0; 990 goto nfsmout; 991 } else 992 va.va_rdev = (dev_t)rdev; 993 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, 994 &va); 995 if (error) { 996 vrele(nd.ni_startdir); 997 if (nd.ni_cnd.cn_flags & HASBUF) { 998 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 999 nd.ni_cnd.cn_flags &= ~HASBUF; 1000 } 1001 nfsm_reply(0); 1002 error = 0; 1003 goto nfsmout; 1004 } 1005 nd.ni_cnd.cn_nameiop = LOOKUP; 1006 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 1007 nd.ni_cnd.cn_proc = procp; 1008 nd.ni_cnd.cn_cred = cred; 1009 if ((error = vfs_lookup(&nd)) != 0) { 1010 if (nd.ni_cnd.cn_flags & HASBUF) { 1011 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1012 nd.ni_cnd.cn_flags &= ~HASBUF; 1013 } 1014 nfsm_reply(0); 1015 error = 0; 1016 goto nfsmout; 1017 } 1018 1019 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1020 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1021 vrele(nd.ni_dvp); 1022 vput(nd.ni_vp); 1023 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1024 error = EINVAL; 1025 nfsm_reply(0); 1026 error = 0; 1027 goto nfsmout; 1028 } 1029 } else { 1030 vrele(nd.ni_startdir); 1031 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1032 nd.ni_cnd.cn_flags &= ~HASBUF; 1033 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1034 vput(nd.ni_dvp); 1035 error = ENXIO; 1036 } 1037 vp = nd.ni_vp; 1038 } else { 1039 vrele(nd.ni_startdir); 1040 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1041 nd.ni_cnd.cn_flags &= ~HASBUF; 1042 vp = nd.ni_vp; 1043 if (nd.ni_dvp == vp) 1044 vrele(nd.ni_dvp); 1045 else 1046 vput(nd.ni_dvp); 1047 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1048 if (va.va_size != -1) { 1049 error = nfsrv_access(vp, VWRITE, cred, 1050 (nd.ni_cnd.cn_flags & RDONLY), procp, 0); 1051 if (!error) { 1052 tempsize = va.va_size; 1053 VATTR_NULL(&va); 1054 va.va_size = tempsize; 1055 error = VOP_SETATTR(vp, &va, cred, 1056 procp); 1057 } 1058 if (error) 1059 vput(vp); 1060 } 1061 } 1062 if (!error) { 1063 memset(fhp, 0, sizeof(nfh)); 1064 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1065 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1066 if (!error) 1067 error = VOP_GETATTR(vp, &va, cred, procp); 1068 vput(vp); 1069 } 1070 if (info.nmi_v3) { 1071 if (exclusive_flag && !error && 1072 bcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF)) 1073 error = EEXIST; 1074 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1075 vrele(dirp); 1076 } 1077 nfsm_reply(NFSX_SRVFH(info.nmi_v3) + NFSX_FATTR(info.nmi_v3) 1078 + NFSX_WCCDATA(info.nmi_v3)); 1079 if (info.nmi_v3) { 1080 if (!error) { 1081 nfsm_srvpostop_fh(fhp); 1082 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1083 } 1084 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1085 &info); 1086 } else { 1087 nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3); 1088 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 1089 nfsm_srvfattr(nfsd, &va, fp); 1090 } 1091 return (0); 1092 nfsmout: 1093 if (dirp) 1094 vrele(dirp); 1095 if (nd.ni_cnd.cn_nameiop != LOOKUP) { 1096 vrele(nd.ni_startdir); 1097 if (nd.ni_cnd.cn_flags & HASBUF) { 1098 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1099 nd.ni_cnd.cn_flags &= ~HASBUF; 1100 } 1101 } 1102 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1103 if (nd.ni_dvp == nd.ni_vp) 1104 vrele(nd.ni_dvp); 1105 else 1106 vput(nd.ni_dvp); 1107 if (nd.ni_vp) 1108 vput(nd.ni_vp); 1109 return (error); 1110 } 1111 1112 /* 1113 * nfs v3 mknod service 1114 */ 1115 int 1116 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1117 struct proc *procp, struct mbuf **mrq) 1118 { 1119 struct mbuf *nam = nfsd->nd_nam; 1120 struct ucred *cred = &nfsd->nd_cr; 1121 struct vattr va, dirfor, diraft; 1122 struct nfsm_info info; 1123 u_int32_t *tl; 1124 struct nameidata nd; 1125 int32_t t1; 1126 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1127 u_int32_t major, minor; 1128 enum vtype vtyp; 1129 char *cp2; 1130 struct vnode *vp, *dirp = NULL; 1131 nfsfh_t nfh; 1132 fhandle_t *fhp; 1133 1134 info.nmi_mreq = NULL; 1135 info.nmi_mrep = nfsd->nd_mrep; 1136 info.nmi_md = nfsd->nd_md; 1137 info.nmi_dpos = nfsd->nd_dpos; 1138 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1139 1140 fhp = &nfh.fh_generic; 1141 nfsm_srvmtofh(fhp); 1142 nfsm_srvnamesiz(len); 1143 1144 NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE, 1145 NULL, procp); 1146 nd.ni_cnd.cn_cred = cred; 1147 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp); 1148 if (dirp) 1149 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1150 if (error) { 1151 nfsm_reply(NFSX_WCCDATA(1)); 1152 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1153 &info); 1154 if (dirp) 1155 vrele(dirp); 1156 return (0); 1157 } 1158 1159 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1160 vtyp = nfsv3tov_type(*tl); 1161 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1162 vrele(nd.ni_startdir); 1163 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1164 error = NFSERR_BADTYPE; 1165 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1166 if (nd.ni_dvp == nd.ni_vp) 1167 vrele(nd.ni_dvp); 1168 else 1169 vput(nd.ni_dvp); 1170 if (nd.ni_vp) 1171 vput(nd.ni_vp); 1172 goto out; 1173 } 1174 VATTR_NULL(&va); 1175 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos); 1176 if (error) 1177 goto nfsmout; 1178 if (vtyp == VCHR || vtyp == VBLK) { 1179 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1180 major = fxdr_unsigned(u_int32_t, *tl++); 1181 minor = fxdr_unsigned(u_int32_t, *tl); 1182 va.va_rdev = makedev(major, minor); 1183 } 1184 1185 /* 1186 * Iff doesn't exist, create it. 1187 */ 1188 if (nd.ni_vp) { 1189 vrele(nd.ni_startdir); 1190 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1191 error = EEXIST; 1192 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1193 if (nd.ni_dvp == nd.ni_vp) 1194 vrele(nd.ni_dvp); 1195 else 1196 vput(nd.ni_dvp); 1197 vput(nd.ni_vp); 1198 goto out; 1199 } 1200 va.va_type = vtyp; 1201 if (vtyp == VSOCK) { 1202 vrele(nd.ni_startdir); 1203 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1204 if (!error) 1205 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1206 } else { 1207 if (va.va_type != VFIFO && 1208 (error = suser_ucred(cred))) { 1209 vrele(nd.ni_startdir); 1210 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1211 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1212 vput(nd.ni_dvp); 1213 goto out; 1214 } 1215 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1216 if (error) { 1217 vrele(nd.ni_startdir); 1218 goto out; 1219 } 1220 nd.ni_cnd.cn_nameiop = LOOKUP; 1221 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 1222 nd.ni_cnd.cn_proc = procp; 1223 nd.ni_cnd.cn_cred = procp->p_ucred; 1224 error = vfs_lookup(&nd); 1225 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1226 if (error) 1227 goto out; 1228 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1229 vrele(nd.ni_dvp); 1230 vput(nd.ni_vp); 1231 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1232 error = EINVAL; 1233 } 1234 } 1235 out: 1236 vp = nd.ni_vp; 1237 if (!error) { 1238 memset(fhp, 0, sizeof(nfh)); 1239 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1240 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1241 if (!error) 1242 error = VOP_GETATTR(vp, &va, cred, procp); 1243 vput(vp); 1244 } 1245 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1246 vrele(dirp); 1247 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); 1248 if (!error) { 1249 nfsm_srvpostop_fh(fhp); 1250 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1251 } 1252 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, &info); 1253 return (0); 1254 nfsmout: 1255 if (dirp) 1256 vrele(dirp); 1257 if (nd.ni_cnd.cn_nameiop) { 1258 vrele(nd.ni_startdir); 1259 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1260 } 1261 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1262 if (nd.ni_dvp == nd.ni_vp) 1263 vrele(nd.ni_dvp); 1264 else 1265 vput(nd.ni_dvp); 1266 if (nd.ni_vp) 1267 vput(nd.ni_vp); 1268 return (error); 1269 } 1270 1271 /* 1272 * nfs remove service 1273 */ 1274 int 1275 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1276 struct proc *procp, struct mbuf **mrq) 1277 { 1278 struct mbuf *nam = nfsd->nd_nam; 1279 struct ucred *cred = &nfsd->nd_cr; 1280 struct nameidata nd; 1281 struct nfsm_info info; 1282 u_int32_t *tl; 1283 int32_t t1; 1284 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1285 char *cp2; 1286 struct vnode *vp, *dirp; 1287 struct vattr dirfor, diraft; 1288 nfsfh_t nfh; 1289 fhandle_t *fhp; 1290 1291 info.nmi_mreq = NULL; 1292 info.nmi_mrep = nfsd->nd_mrep; 1293 info.nmi_md = nfsd->nd_md; 1294 info.nmi_dpos = nfsd->nd_dpos; 1295 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1296 1297 vp = NULL; 1298 1299 fhp = &nfh.fh_generic; 1300 nfsm_srvmtofh(fhp); 1301 nfsm_srvnamesiz(len); 1302 1303 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp); 1304 nd.ni_cnd.cn_cred = cred; 1305 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp); 1306 if (dirp) { 1307 if (info.nmi_v3) 1308 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1309 else { 1310 vrele(dirp); 1311 dirp = NULL; 1312 } 1313 } 1314 1315 if (!error) { 1316 vp = nd.ni_vp; 1317 if (vp->v_type == VDIR && 1318 (error = suser_ucred(cred)) != 0) 1319 goto out; 1320 /* 1321 * The root of a mounted filesystem cannot be deleted. 1322 */ 1323 if (vp->v_flag & VROOT) { 1324 error = EBUSY; 1325 goto out; 1326 } 1327 if (vp->v_flag & VTEXT) 1328 uvm_vnp_uncache(vp); 1329 out: 1330 if (!error) { 1331 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1332 } else { 1333 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1334 if (nd.ni_dvp == vp) 1335 vrele(nd.ni_dvp); 1336 else 1337 vput(nd.ni_dvp); 1338 vput(vp); 1339 } 1340 } 1341 if (dirp && info.nmi_v3) { 1342 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1343 vrele(dirp); 1344 } 1345 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1346 if (info.nmi_v3) { 1347 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1348 &info); 1349 return (0); 1350 } 1351 1352 nfsmout: 1353 return(error); 1354 } 1355 1356 /* 1357 * nfs rename service 1358 */ 1359 int 1360 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1361 struct proc *procp, struct mbuf **mrq) 1362 { 1363 struct mbuf *nam = nfsd->nd_nam; 1364 struct ucred *cred = &nfsd->nd_cr; 1365 struct nfsm_info info; 1366 u_int32_t *tl; 1367 int32_t t1; 1368 int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; 1369 int tdirfor_ret = 1, tdiraft_ret = 1; 1370 char *cp2; 1371 struct nameidata fromnd, tond; 1372 struct vnode *fvp = NULL, *tvp, *tdvp, *fdirp = NULL; 1373 struct vnode *tdirp = NULL; 1374 struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 1375 nfsfh_t fnfh, tnfh; 1376 fhandle_t *ffhp, *tfhp; 1377 uid_t saved_uid; 1378 1379 info.nmi_mreq = NULL; 1380 info.nmi_mrep = nfsd->nd_mrep; 1381 info.nmi_md = nfsd->nd_md; 1382 info.nmi_dpos = nfsd->nd_dpos; 1383 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1384 1385 ffhp = &fnfh.fh_generic; 1386 tfhp = &tnfh.fh_generic; 1387 nfsm_srvmtofh(ffhp); 1388 nfsm_srvnamesiz(len); 1389 1390 /* 1391 * Remember our original uid so that we can reset cr_uid before 1392 * the second nfs_namei() call, in case it is remapped. 1393 */ 1394 saved_uid = cred->cr_uid; 1395 1396 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_SYSSPACE, NULL, 1397 procp); 1398 fromnd.ni_cnd.cn_cred = cred; 1399 error = nfs_namei(&fromnd, ffhp, len, slp, nam, &info.nmi_md, 1400 &info.nmi_dpos, &fdirp, procp); 1401 if (fdirp) { 1402 if (info.nmi_v3) 1403 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, 1404 procp); 1405 else { 1406 vrele(fdirp); 1407 fdirp = NULL; 1408 } 1409 } 1410 if (error) { 1411 nfsm_reply(2 * NFSX_WCCDATA(info.nmi_v3)); 1412 nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, 1413 &info); 1414 nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, 1415 &info); 1416 if (fdirp) 1417 vrele(fdirp); 1418 return (0); 1419 } 1420 1421 fvp = fromnd.ni_vp; 1422 nfsm_srvmtofh(tfhp); 1423 nfsm_strsiz(len2, NFS_MAXNAMLEN); 1424 cred->cr_uid = saved_uid; 1425 1426 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF| NOCACHE | SAVESTART, 1427 UIO_SYSSPACE, NULL, procp); 1428 tond.ni_cnd.cn_cred = cred; 1429 error = nfs_namei(&tond, tfhp, len2, slp, nam, &info.nmi_md, 1430 &info.nmi_dpos, &tdirp, procp); 1431 if (tdirp) { 1432 if (info.nmi_v3) 1433 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, 1434 procp); 1435 else { 1436 vrele(tdirp); 1437 tdirp = NULL; 1438 } 1439 } 1440 if (error) { 1441 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1442 vrele(fromnd.ni_dvp); 1443 vrele(fvp); 1444 goto out1; 1445 } 1446 tdvp = tond.ni_dvp; 1447 tvp = tond.ni_vp; 1448 if (tvp != NULL) { 1449 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1450 error = info.nmi_v3 ? EEXIST : EISDIR; 1451 goto out; 1452 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1453 error = info.nmi_v3 ? EEXIST : ENOTDIR; 1454 goto out; 1455 } 1456 if (tvp->v_type == VDIR && tvp->v_mountedhere) { 1457 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1458 goto out; 1459 } 1460 } 1461 if (fvp->v_type == VDIR && fvp->v_mountedhere) { 1462 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1463 goto out; 1464 } 1465 if (fvp->v_mount != tdvp->v_mount) { 1466 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1467 goto out; 1468 } 1469 if (fvp == tdvp) 1470 error = info.nmi_v3 ? EINVAL : ENOTEMPTY; 1471 /* 1472 * If source is the same as the destination (that is the 1473 * same vnode with the same name in the same directory), 1474 * then there is nothing to do. 1475 */ 1476 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1477 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1478 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1479 fromnd.ni_cnd.cn_namelen)) 1480 error = -1; 1481 out: 1482 if (!error) { 1483 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1484 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1485 } else { 1486 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1487 if (tdvp == tvp) 1488 vrele(tdvp); 1489 else 1490 vput(tdvp); 1491 if (tvp) 1492 vput(tvp); 1493 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1494 vrele(fromnd.ni_dvp); 1495 vrele(fvp); 1496 if (error == -1) 1497 error = 0; 1498 } 1499 vrele(tond.ni_startdir); 1500 pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf); 1501 out1: 1502 if (fdirp) { 1503 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); 1504 vrele(fdirp); 1505 } 1506 if (tdirp) { 1507 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); 1508 vrele(tdirp); 1509 } 1510 vrele(fromnd.ni_startdir); 1511 pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf); 1512 nfsm_reply(2 * NFSX_WCCDATA(info.nmi_v3)); 1513 if (info.nmi_v3) { 1514 nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, 1515 &info); 1516 nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, 1517 &info); 1518 } 1519 return (0); 1520 1521 nfsmout: 1522 if (fdirp) 1523 vrele(fdirp); 1524 if (tdirp) 1525 vrele(tdirp); 1526 if (tond.ni_cnd.cn_nameiop) { 1527 vrele(tond.ni_startdir); 1528 pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf); 1529 } 1530 if (fromnd.ni_cnd.cn_nameiop) { 1531 if (fromnd.ni_startdir) 1532 vrele(fromnd.ni_startdir); 1533 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1534 1535 /* 1536 * XXX: Workaround the fact that fromnd.ni_dvp can point 1537 * to the same vnode as fdirp. 1538 */ 1539 if (fromnd.ni_dvp != NULL && fromnd.ni_dvp != fdirp) 1540 vrele(fromnd.ni_dvp); 1541 if (fvp) 1542 vrele(fvp); 1543 } 1544 return (error); 1545 } 1546 1547 /* 1548 * nfs link service 1549 */ 1550 int 1551 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1552 struct proc *procp, struct mbuf **mrq) 1553 { 1554 struct mbuf *nam = nfsd->nd_nam; 1555 struct nfsm_info info; 1556 struct ucred *cred = &nfsd->nd_cr; 1557 struct nameidata nd; 1558 u_int32_t *tl; 1559 int32_t t1; 1560 int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1; 1561 int getret = 1; 1562 char *cp2; 1563 struct vnode *vp, *xp, *dirp = NULL; 1564 struct vattr dirfor, diraft, at; 1565 nfsfh_t nfh, dnfh; 1566 fhandle_t *fhp, *dfhp; 1567 1568 info.nmi_mreq = NULL; 1569 info.nmi_mrep = nfsd->nd_mrep; 1570 info.nmi_md = nfsd->nd_md; 1571 info.nmi_dpos = nfsd->nd_dpos; 1572 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1573 1574 fhp = &nfh.fh_generic; 1575 dfhp = &dnfh.fh_generic; 1576 nfsm_srvmtofh(fhp); 1577 nfsm_srvmtofh(dfhp); 1578 nfsm_srvnamesiz(len); 1579 1580 error = nfsrv_fhtovp(fhp, 0, &vp, cred, slp, nam, &rdonly); 1581 if (error) { 1582 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + 1583 NFSX_WCCDATA(info.nmi_v3)); 1584 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 1585 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1586 &info); 1587 error = 0; 1588 goto nfsmout; 1589 } 1590 if (vp->v_type == VDIR && (error = suser_ucred(cred)) != 0) 1591 goto out1; 1592 1593 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp); 1594 nd.ni_cnd.cn_cred = cred; 1595 error = nfs_namei(&nd, dfhp, len, slp, nam, &info.nmi_md, 1596 &info.nmi_dpos, &dirp, procp); 1597 if (dirp) { 1598 if (info.nmi_v3) 1599 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1600 procp); 1601 else { 1602 vrele(dirp); 1603 dirp = NULL; 1604 } 1605 } 1606 if (error) 1607 goto out1; 1608 xp = nd.ni_vp; 1609 if (xp != NULL) { 1610 error = EEXIST; 1611 goto out; 1612 } 1613 xp = nd.ni_dvp; 1614 if (vp->v_mount != xp->v_mount) 1615 error = EXDEV; 1616 out: 1617 if (!error) { 1618 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1619 } else { 1620 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1621 if (nd.ni_dvp == nd.ni_vp) 1622 vrele(nd.ni_dvp); 1623 else 1624 vput(nd.ni_dvp); 1625 if (nd.ni_vp) 1626 vrele(nd.ni_vp); 1627 } 1628 out1: 1629 if (info.nmi_v3) 1630 getret = VOP_GETATTR(vp, &at, cred, procp); 1631 if (dirp) { 1632 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1633 vrele(dirp); 1634 } 1635 vrele(vp); 1636 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)); 1637 if (info.nmi_v3) { 1638 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 1639 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1640 &info); 1641 error = 0; 1642 } 1643 nfsmout: 1644 return(error); 1645 } 1646 1647 /* 1648 * nfs symbolic link service 1649 */ 1650 int 1651 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1652 struct proc *procp, struct mbuf **mrq) 1653 { 1654 struct mbuf *nam = nfsd->nd_nam; 1655 struct ucred *cred = &nfsd->nd_cr; 1656 struct vattr va, dirfor, diraft; 1657 struct nameidata nd; 1658 struct nfsm_info info; 1659 u_int32_t *tl; 1660 int32_t t1; 1661 struct nfsv2_sattr *sp; 1662 char *pathcp = NULL, *cp2; 1663 struct uio io; 1664 struct iovec iv; 1665 int error = 0, len, pathlen, len2, dirfor_ret = 1, diraft_ret = 1; 1666 struct vnode *dirp = NULL; 1667 nfsfh_t nfh; 1668 fhandle_t *fhp; 1669 1670 info.nmi_mreq = NULL; 1671 info.nmi_mrep = nfsd->nd_mrep; 1672 info.nmi_md = nfsd->nd_md; 1673 info.nmi_dpos = nfsd->nd_dpos; 1674 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1675 1676 fhp = &nfh.fh_generic; 1677 nfsm_srvmtofh(fhp); 1678 nfsm_srvnamesiz(len); 1679 1680 NDINIT(&nd, CREATE, LOCKPARENT | SAVESTART, UIO_SYSSPACE, NULL, procp); 1681 nd.ni_cnd.cn_cred = cred; 1682 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1683 &info.nmi_dpos, &dirp, procp); 1684 if (dirp) { 1685 if (info.nmi_v3) 1686 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1687 procp); 1688 else { 1689 vrele(dirp); 1690 dirp = NULL; 1691 } 1692 } 1693 if (error) 1694 goto out; 1695 VATTR_NULL(&va); 1696 if (info.nmi_v3) { 1697 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 1698 &info.nmi_dpos); 1699 if (error) 1700 goto nfsmout; 1701 } 1702 nfsm_strsiz(len2, NFS_MAXPATHLEN); 1703 pathlen = len2 + 1; 1704 pathcp = malloc(pathlen, M_TEMP, M_WAITOK); 1705 iv.iov_base = pathcp; 1706 iv.iov_len = len2; 1707 io.uio_resid = len2; 1708 io.uio_offset = 0; 1709 io.uio_iov = &iv; 1710 io.uio_iovcnt = 1; 1711 io.uio_segflg = UIO_SYSSPACE; 1712 io.uio_rw = UIO_READ; 1713 io.uio_procp = NULL; 1714 nfsm_mtouio(&io, len2); 1715 if (!info.nmi_v3) { 1716 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1717 va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode); 1718 } 1719 *(pathcp + len2) = '\0'; 1720 if (nd.ni_vp) { 1721 vrele(nd.ni_startdir); 1722 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1723 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1724 if (nd.ni_dvp == nd.ni_vp) 1725 vrele(nd.ni_dvp); 1726 else 1727 vput(nd.ni_dvp); 1728 vrele(nd.ni_vp); 1729 error = EEXIST; 1730 goto out; 1731 } 1732 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp); 1733 if (error) 1734 vrele(nd.ni_startdir); 1735 else { 1736 if (info.nmi_v3) { 1737 nd.ni_cnd.cn_nameiop = LOOKUP; 1738 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW); 1739 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF); 1740 nd.ni_cnd.cn_proc = procp; 1741 nd.ni_cnd.cn_cred = cred; 1742 error = vfs_lookup(&nd); 1743 if (!error) { 1744 memset(fhp, 0, sizeof(nfh)); 1745 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; 1746 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); 1747 if (!error) 1748 error = VOP_GETATTR(nd.ni_vp, &va, cred, 1749 procp); 1750 vput(nd.ni_vp); 1751 } 1752 } else 1753 vrele(nd.ni_startdir); 1754 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1755 } 1756 out: 1757 if (pathcp) 1758 free(pathcp, M_TEMP, pathlen); 1759 if (dirp) { 1760 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1761 vrele(dirp); 1762 } 1763 nfsm_reply(NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPATTR(info.nmi_v3) 1764 + NFSX_WCCDATA(info.nmi_v3)); 1765 if (info.nmi_v3) { 1766 if (!error) { 1767 nfsm_srvpostop_fh(fhp); 1768 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1769 } 1770 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1771 &info); 1772 } 1773 return (0); 1774 nfsmout: 1775 if (nd.ni_cnd.cn_nameiop) { 1776 vrele(nd.ni_startdir); 1777 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1778 } 1779 if (dirp) 1780 vrele(dirp); 1781 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1782 if (nd.ni_dvp == nd.ni_vp) 1783 vrele(nd.ni_dvp); 1784 else 1785 vput(nd.ni_dvp); 1786 if (nd.ni_vp) 1787 vrele(nd.ni_vp); 1788 if (pathcp) 1789 free(pathcp, M_TEMP, pathlen); 1790 return (error); 1791 } 1792 1793 /* 1794 * nfs mkdir service 1795 */ 1796 int 1797 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1798 struct proc *procp, struct mbuf **mrq) 1799 { 1800 struct mbuf *nam = nfsd->nd_nam; 1801 struct ucred *cred = &nfsd->nd_cr; 1802 struct vattr va, dirfor, diraft; 1803 struct nfs_fattr *fp; 1804 struct nameidata nd; 1805 struct nfsm_info info; 1806 u_int32_t *tl; 1807 int32_t t1; 1808 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1809 char *cp2; 1810 struct vnode *vp, *dirp = NULL; 1811 nfsfh_t nfh; 1812 fhandle_t *fhp; 1813 1814 info.nmi_mreq = NULL; 1815 info.nmi_mrep = nfsd->nd_mrep; 1816 info.nmi_md = nfsd->nd_md; 1817 info.nmi_dpos = nfsd->nd_dpos; 1818 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1819 1820 fhp = &nfh.fh_generic; 1821 nfsm_srvmtofh(fhp); 1822 nfsm_srvnamesiz(len); 1823 1824 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp); 1825 nd.ni_cnd.cn_cred = cred; 1826 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1827 &info.nmi_dpos, &dirp, procp); 1828 if (dirp) { 1829 if (info.nmi_v3) 1830 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1831 else { 1832 vrele(dirp); 1833 dirp = NULL; 1834 } 1835 } 1836 if (error) { 1837 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1838 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1839 &info); 1840 if (dirp) 1841 vrele(dirp); 1842 return (0); 1843 } 1844 1845 VATTR_NULL(&va); 1846 if (info.nmi_v3) { 1847 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 1848 &info.nmi_dpos); 1849 if (error) 1850 goto nfsmout; 1851 } else { 1852 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1853 va.va_mode = nfstov_mode(*tl++); 1854 } 1855 va.va_type = VDIR; 1856 vp = nd.ni_vp; 1857 if (vp != NULL) { 1858 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1859 if (nd.ni_dvp == vp) 1860 vrele(nd.ni_dvp); 1861 else 1862 vput(nd.ni_dvp); 1863 vrele(vp); 1864 error = EEXIST; 1865 goto out; 1866 } 1867 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1868 if (!error) { 1869 vp = nd.ni_vp; 1870 memset(fhp, 0, sizeof(nfh)); 1871 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1872 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1873 if (!error) 1874 error = VOP_GETATTR(vp, &va, cred, procp); 1875 vput(vp); 1876 } 1877 out: 1878 if (dirp) { 1879 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1880 vrele(dirp); 1881 } 1882 nfsm_reply(NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPATTR(info.nmi_v3) + 1883 NFSX_WCCDATA(info.nmi_v3)); 1884 if (info.nmi_v3) { 1885 if (!error) { 1886 nfsm_srvpostop_fh(fhp); 1887 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1888 } 1889 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1890 &info); 1891 } else { 1892 nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3); 1893 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 1894 nfsm_srvfattr(nfsd, &va, fp); 1895 } 1896 return (0); 1897 nfsmout: 1898 if (dirp) 1899 vrele(dirp); 1900 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1901 if (nd.ni_dvp == nd.ni_vp) 1902 vrele(nd.ni_dvp); 1903 else 1904 vput(nd.ni_dvp); 1905 if (nd.ni_vp) 1906 vrele(nd.ni_vp); 1907 return (error); 1908 } 1909 1910 /* 1911 * nfs rmdir service 1912 */ 1913 int 1914 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1915 struct proc *procp, struct mbuf **mrq) 1916 { 1917 struct mbuf *nam = nfsd->nd_nam; 1918 struct ucred *cred = &nfsd->nd_cr; 1919 struct nfsm_info info; 1920 u_int32_t *tl; 1921 int32_t t1; 1922 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1923 char *cp2; 1924 struct vnode *vp, *dirp = NULL; 1925 struct vattr dirfor, diraft; 1926 nfsfh_t nfh; 1927 fhandle_t *fhp; 1928 struct nameidata nd; 1929 1930 info.nmi_mreq = NULL; 1931 info.nmi_mrep = nfsd->nd_mrep; 1932 info.nmi_md = nfsd->nd_md; 1933 info.nmi_dpos = nfsd->nd_dpos; 1934 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1935 1936 fhp = &nfh.fh_generic; 1937 nfsm_srvmtofh(fhp); 1938 nfsm_srvnamesiz(len); 1939 1940 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp); 1941 nd.ni_cnd.cn_cred = cred; 1942 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1943 &info.nmi_dpos, &dirp, procp); 1944 if (dirp) { 1945 if (info.nmi_v3) 1946 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1947 procp); 1948 else { 1949 vrele(dirp); 1950 dirp = NULL; 1951 } 1952 } 1953 if (error) { 1954 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1955 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1956 &info); 1957 if (dirp) 1958 vrele(dirp); 1959 return (0); 1960 } 1961 vp = nd.ni_vp; 1962 if (vp->v_type != VDIR) { 1963 error = ENOTDIR; 1964 goto out; 1965 } 1966 /* 1967 * No rmdir "." please. 1968 */ 1969 if (nd.ni_dvp == vp) { 1970 error = EINVAL; 1971 goto out; 1972 } 1973 /* 1974 * The root of a mounted filesystem cannot be deleted. 1975 */ 1976 if (vp->v_flag & VROOT) 1977 error = EBUSY; 1978 out: 1979 if (!error) { 1980 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1981 } else { 1982 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1983 if (nd.ni_dvp == nd.ni_vp) 1984 vrele(nd.ni_dvp); 1985 else 1986 vput(nd.ni_dvp); 1987 vput(vp); 1988 } 1989 if (dirp) { 1990 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1991 vrele(dirp); 1992 } 1993 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1994 if (info.nmi_v3) { 1995 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1996 &info); 1997 error = 0; 1998 } 1999 nfsmout: 2000 return(error); 2001 } 2002 2003 /* 2004 * nfs readdir service 2005 * - mallocs what it thinks is enough to read 2006 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 2007 * - calls VOP_READDIR() 2008 * - loops around building the reply 2009 * if the output generated exceeds count break out of loop 2010 * - it only knows that it has encountered eof when the VOP_READDIR() 2011 * reads nothing 2012 * - as such one readdir rpc will return eof false although you are there 2013 * and then the next will return eof 2014 * - it trims out records with d_fileno == 0 2015 * this doesn't matter for Unix clients, but they might confuse clients 2016 * for other os'. 2017 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 2018 * than requested, but this may not apply to all filesystems. For 2019 * example, client NFS does not { although it is never remote mounted 2020 * anyhow } 2021 * The alternate call nfsrv_readdirplus() does lookups as well. 2022 * PS: The NFS protocol spec. does not clarify what the "count" byte 2023 * argument is a count of.. just name strings and file id's or the 2024 * entire reply rpc or ... 2025 * I tried just file name and id sizes and it confused the Sun client, 2026 * so I am using the full rpc size now. The "paranoia.." comment refers 2027 * to including the status longwords that are not a part of the dir. 2028 * "entry" structures, but are in the rpc. 2029 */ 2030 struct flrep { 2031 nfsuint64 fl_off; 2032 u_int32_t fl_postopok; 2033 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; 2034 u_int32_t fl_fhok; 2035 u_int32_t fl_fhsize; 2036 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; 2037 }; 2038 2039 int 2040 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2041 struct proc *procp, struct mbuf **mrq) 2042 { 2043 struct mbuf *nam = nfsd->nd_nam; 2044 struct ucred *cred = &nfsd->nd_cr; 2045 struct dirent *dp; 2046 struct nfsm_info info; 2047 u_int32_t *tl; 2048 int32_t t1; 2049 char *cpos, *cend, *cp2, *rbuf; 2050 struct vnode *vp; 2051 struct vattr at; 2052 nfsfh_t nfh; 2053 fhandle_t *fhp; 2054 struct uio io; 2055 struct iovec iv; 2056 int len, nlen, pad, xfer, error = 0, getret = 1; 2057 int siz, cnt, fullsiz, eofflag, rdonly; 2058 u_quad_t off, toff, verf; 2059 2060 info.nmi_mreq = NULL; 2061 info.nmi_mrep = nfsd->nd_mrep; 2062 info.nmi_md = nfsd->nd_md; 2063 info.nmi_dpos = nfsd->nd_dpos; 2064 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2065 2066 fhp = &nfh.fh_generic; 2067 nfsm_srvmtofh(fhp); 2068 if (info.nmi_v3) { 2069 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2070 toff = fxdr_hyper(tl); 2071 tl += 2; 2072 verf = fxdr_hyper(tl); 2073 tl += 2; 2074 } else { 2075 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2076 toff = fxdr_unsigned(u_quad_t, *tl++); 2077 } 2078 off = toff; 2079 cnt = fxdr_unsigned(int, *tl); 2080 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2081 xfer = NFS_SRVMAXDATA(nfsd); 2082 if (siz > xfer) 2083 siz = xfer; 2084 if (cnt > xfer) 2085 cnt = xfer; 2086 fullsiz = siz; 2087 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2088 if (error) { 2089 nfsm_reply(NFSX_UNSIGNED); 2090 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2091 error = 0; 2092 goto nfsmout; 2093 } 2094 if (info.nmi_v3) 2095 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2096 if (!error) 2097 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2098 if (error) { 2099 vput(vp); 2100 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3)); 2101 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2102 error = 0; 2103 goto nfsmout; 2104 } 2105 VOP_UNLOCK(vp, procp); 2106 rbuf = malloc(fullsiz, M_TEMP, M_WAITOK); 2107 again: 2108 iv.iov_base = rbuf; 2109 iv.iov_len = fullsiz; 2110 io.uio_iov = &iv; 2111 io.uio_iovcnt = 1; 2112 io.uio_offset = (off_t)off; 2113 io.uio_resid = fullsiz; 2114 io.uio_segflg = UIO_SYSSPACE; 2115 io.uio_rw = UIO_READ; 2116 io.uio_procp = NULL; 2117 eofflag = 0; 2118 2119 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); 2120 error = VOP_READDIR(vp, &io, cred, &eofflag); 2121 2122 off = (off_t)io.uio_offset; 2123 if (info.nmi_v3) { 2124 getret = VOP_GETATTR(vp, &at, cred, procp); 2125 if (!error) 2126 error = getret; 2127 } 2128 2129 VOP_UNLOCK(vp, procp); 2130 if (error) { 2131 vrele(vp); 2132 free(rbuf, M_TEMP, fullsiz); 2133 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3)); 2134 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2135 error = 0; 2136 goto nfsmout; 2137 } 2138 if (io.uio_resid) { 2139 siz -= io.uio_resid; 2140 2141 /* 2142 * If nothing read, return eof 2143 * rpc reply 2144 */ 2145 if (siz == 0) { 2146 vrele(vp); 2147 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_COOKIEVERF(info.nmi_v3) + 2148 2 * NFSX_UNSIGNED); 2149 if (info.nmi_v3) { 2150 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2151 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 2152 txdr_hyper(at.va_filerev, tl); 2153 tl += 2; 2154 } else 2155 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2156 *tl++ = nfs_false; 2157 *tl = nfs_true; 2158 free(rbuf, M_TEMP, fullsiz); 2159 error = 0; 2160 goto nfsmout; 2161 } 2162 } 2163 2164 /* 2165 * Check for degenerate cases of nothing useful read. 2166 * If so go try again 2167 */ 2168 cpos = rbuf; 2169 cend = rbuf + siz; 2170 dp = (struct dirent *)cpos; 2171 2172 while (cpos < cend && dp->d_fileno == 0) { 2173 cpos += dp->d_reclen; 2174 dp = (struct dirent *)cpos; 2175 } 2176 if (cpos >= cend) { 2177 toff = off; 2178 siz = fullsiz; 2179 goto again; 2180 } 2181 2182 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 2183 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_COOKIEVERF(info.nmi_v3) + siz); 2184 if (info.nmi_v3) { 2185 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2186 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2187 txdr_hyper(at.va_filerev, tl); 2188 } 2189 2190 /* Loop through the records and build reply */ 2191 while (cpos < cend) { 2192 if (dp->d_fileno != 0) { 2193 nlen = dp->d_namlen; 2194 pad = nfsm_padlen(nlen); 2195 len += (4 * NFSX_UNSIGNED + nlen + pad); 2196 if (info.nmi_v3) 2197 len += 2 * NFSX_UNSIGNED; 2198 if (len > cnt) { 2199 eofflag = 0; 2200 break; 2201 } 2202 /* 2203 * Build the directory record xdr from 2204 * the dirent entry. 2205 */ 2206 tl = nfsm_build(&info.nmi_mb, 2207 (info.nmi_v3 ? 3 : 2) * NFSX_UNSIGNED); 2208 *tl++ = nfs_true; 2209 if (info.nmi_v3) 2210 txdr_hyper(dp->d_fileno, tl); 2211 else 2212 *tl = txdr_unsigned((u_int32_t)dp->d_fileno); 2213 2214 /* And copy the name */ 2215 nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen); 2216 2217 /* Finish off the record */ 2218 if (info.nmi_v3) { 2219 tl = nfsm_build(&info.nmi_mb, 2*NFSX_UNSIGNED); 2220 txdr_hyper(dp->d_off, tl); 2221 } else { 2222 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 2223 *tl = txdr_unsigned((u_int32_t)dp->d_off); 2224 } 2225 } 2226 cpos += dp->d_reclen; 2227 dp = (struct dirent *)cpos; 2228 } 2229 vrele(vp); 2230 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2231 *tl++ = nfs_false; 2232 if (eofflag) 2233 *tl = nfs_true; 2234 else 2235 *tl = nfs_false; 2236 free(rbuf, M_TEMP, fullsiz); 2237 nfsmout: 2238 return(error); 2239 } 2240 2241 int 2242 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2243 struct proc *procp, struct mbuf **mrq) 2244 { 2245 struct mbuf *nam = nfsd->nd_nam; 2246 struct ucred *cred = &nfsd->nd_cr; 2247 struct dirent *dp; 2248 struct nfsm_info info; 2249 u_int32_t *tl; 2250 int32_t t1; 2251 char *cpos, *cend, *cp2, *rbuf; 2252 struct vnode *vp, *nvp; 2253 struct flrep fl; 2254 nfsfh_t nfh; 2255 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 2256 struct uio io; 2257 struct iovec iv; 2258 struct vattr va, at, *vap = &va; 2259 struct nfs_fattr *fp; 2260 int len, nlen, pad, xfer, error = 0, getret = 1; 2261 int siz, cnt, fullsiz, eofflag, rdonly, dirlen; 2262 u_quad_t off, toff, verf; 2263 2264 info.nmi_mreq = NULL; 2265 info.nmi_mrep = nfsd->nd_mrep; 2266 info.nmi_md = nfsd->nd_md; 2267 info.nmi_dpos = nfsd->nd_dpos; 2268 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2269 2270 fhp = &nfh.fh_generic; 2271 nfsm_srvmtofh(fhp); 2272 nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2273 toff = fxdr_hyper(tl); 2274 tl += 2; 2275 verf = fxdr_hyper(tl); 2276 tl += 2; 2277 siz = fxdr_unsigned(int, *tl++); 2278 cnt = fxdr_unsigned(int, *tl); 2279 off = toff; 2280 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2281 xfer = NFS_SRVMAXDATA(nfsd); 2282 if (siz > xfer) 2283 siz = xfer; 2284 if (cnt > xfer) 2285 cnt = xfer; 2286 fullsiz = siz; 2287 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2288 if (error) { 2289 nfsm_reply(NFSX_UNSIGNED); 2290 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2291 error = 0; 2292 goto nfsmout; 2293 } 2294 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2295 if (!error) 2296 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2297 if (error) { 2298 vput(vp); 2299 nfsm_reply(NFSX_V3POSTOPATTR); 2300 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2301 error = 0; 2302 goto nfsmout; 2303 } 2304 VOP_UNLOCK(vp, procp); 2305 2306 rbuf = malloc(fullsiz, M_TEMP, M_WAITOK); 2307 again: 2308 iv.iov_base = rbuf; 2309 iv.iov_len = fullsiz; 2310 io.uio_iov = &iv; 2311 io.uio_iovcnt = 1; 2312 io.uio_offset = (off_t)off; 2313 io.uio_resid = fullsiz; 2314 io.uio_segflg = UIO_SYSSPACE; 2315 io.uio_rw = UIO_READ; 2316 io.uio_procp = NULL; 2317 eofflag = 0; 2318 2319 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); 2320 error = VOP_READDIR(vp, &io, cred, &eofflag); 2321 2322 off = (u_quad_t)io.uio_offset; 2323 getret = VOP_GETATTR(vp, &at, cred, procp); 2324 2325 VOP_UNLOCK(vp, procp); 2326 2327 if (!error) 2328 error = getret; 2329 if (error) { 2330 vrele(vp); 2331 free(rbuf, M_TEMP, fullsiz); 2332 nfsm_reply(NFSX_V3POSTOPATTR); 2333 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2334 error = 0; 2335 goto nfsmout; 2336 } 2337 if (io.uio_resid) { 2338 siz -= io.uio_resid; 2339 2340 /* 2341 * If nothing read, return eof 2342 * rpc reply 2343 */ 2344 if (siz == 0) { 2345 vrele(vp); 2346 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2347 2 * NFSX_UNSIGNED); 2348 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2349 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 2350 txdr_hyper(at.va_filerev, tl); 2351 tl += 2; 2352 *tl++ = nfs_false; 2353 *tl = nfs_true; 2354 free(rbuf, M_TEMP, fullsiz); 2355 error = 0; 2356 goto nfsmout; 2357 } 2358 } 2359 2360 /* 2361 * Check for degenerate cases of nothing useful read. 2362 * If so go try again 2363 */ 2364 cpos = rbuf; 2365 cend = rbuf + siz; 2366 dp = (struct dirent *)cpos; 2367 2368 while (cpos < cend && dp->d_fileno == 0) { 2369 cpos += dp->d_reclen; 2370 dp = (struct dirent *)cpos; 2371 } 2372 if (cpos >= cend) { 2373 toff = off; 2374 siz = fullsiz; 2375 goto again; 2376 } 2377 2378 /* 2379 * struct READDIRPLUS3resok { 2380 * postop_attr dir_attributes; 2381 * cookieverf3 cookieverf; 2382 * dirlistplus3 reply; 2383 * } 2384 * 2385 * struct dirlistplus3 { 2386 * entryplus3 *entries; 2387 * bool eof; 2388 * } 2389 */ 2390 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; 2391 nfsm_reply(cnt); 2392 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2393 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2394 txdr_hyper(at.va_filerev, tl); 2395 2396 /* Loop through the records and build reply */ 2397 while (cpos < cend) { 2398 if (dp->d_fileno != 0) { 2399 nlen = dp->d_namlen; 2400 pad = nfsm_padlen(nlen); 2401 2402 /* 2403 * For readdir_and_lookup get the vnode using 2404 * the file number. 2405 */ 2406 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 2407 goto invalid; 2408 memset(nfhp, 0, NFSX_V3FH); 2409 nfhp->fh_fsid = 2410 nvp->v_mount->mnt_stat.f_fsid; 2411 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 2412 vput(nvp); 2413 goto invalid; 2414 } 2415 if (VOP_GETATTR(nvp, vap, cred, procp)) { 2416 vput(nvp); 2417 goto invalid; 2418 } 2419 vput(nvp); 2420 2421 /* 2422 * If either the dircount or maxcount will be 2423 * exceeded, get out now. Both of these lengths 2424 * are calculated conservatively, including all 2425 * XDR overheads. 2426 * 2427 * Each entry: 2428 * 2 * NFSX_UNSIGNED for fileid3 2429 * 1 * NFSX_UNSIGNED for length of name 2430 * nlen + pad == space the name takes up 2431 * 2 * NFSX_UNSIGNED for the cookie 2432 * 1 * NFSX_UNSIGNED to indicate if file handle present 2433 * 1 * NFSX_UNSIGNED for the file handle length 2434 * NFSX_V3FH == space our file handle takes up 2435 * NFSX_V3POSTOPATTR == space the attributes take up 2436 * 1 * NFSX_UNSIGNED for next pointer 2437 */ 2438 len += (8 * NFSX_UNSIGNED + nlen + pad + NFSX_V3FH + 2439 NFSX_V3POSTOPATTR); 2440 dirlen += (6 * NFSX_UNSIGNED + nlen + pad); 2441 if (len > cnt || dirlen > fullsiz) { 2442 eofflag = 0; 2443 break; 2444 } 2445 2446 tl = nfsm_build(&info.nmi_mb, 3 * NFSX_UNSIGNED); 2447 *tl++ = nfs_true; 2448 txdr_hyper(dp->d_fileno, tl); 2449 2450 /* And copy the name */ 2451 nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen); 2452 2453 /* 2454 * Build the directory record xdr from 2455 * the dirent entry. 2456 */ 2457 fp = (struct nfs_fattr *)&fl.fl_fattr; 2458 nfsm_srvfattr(nfsd, vap, fp); 2459 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 2460 fl.fl_fhok = nfs_true; 2461 fl.fl_postopok = nfs_true; 2462 txdr_hyper(dp->d_off, fl.fl_off.nfsuquad); 2463 2464 /* Now copy the flrep structure out. */ 2465 nfsm_buftombuf(&info.nmi_mb, &fl, sizeof(struct flrep)); 2466 } 2467 invalid: 2468 cpos += dp->d_reclen; 2469 dp = (struct dirent *)cpos; 2470 } 2471 vrele(vp); 2472 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2473 *tl++ = nfs_false; 2474 if (eofflag) 2475 *tl = nfs_true; 2476 else 2477 *tl = nfs_false; 2478 free(rbuf, M_TEMP, fullsiz); 2479 nfsmout: 2480 return(error); 2481 } 2482 2483 /* 2484 * nfs commit service 2485 */ 2486 int 2487 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2488 struct proc *procp, struct mbuf **mrq) 2489 { 2490 struct mbuf *nam = nfsd->nd_nam; 2491 struct ucred *cred = &nfsd->nd_cr; 2492 struct vattr bfor, aft; 2493 struct vnode *vp; 2494 struct nfsm_info info; 2495 nfsfh_t nfh; 2496 fhandle_t *fhp; 2497 u_int32_t *tl; 2498 int32_t t1; 2499 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt; 2500 char *cp2; 2501 u_quad_t off; 2502 2503 info.nmi_mreq = NULL; 2504 info.nmi_mrep = nfsd->nd_mrep; 2505 info.nmi_md = nfsd->nd_md; 2506 info.nmi_dpos = nfsd->nd_dpos; 2507 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2508 2509 fhp = &nfh.fh_generic; 2510 nfsm_srvmtofh(fhp); 2511 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2512 2513 /* 2514 * XXX At this time VOP_FSYNC() does not accept offset and byte 2515 * count parameters, so these arguments are useless (someday maybe). 2516 */ 2517 off = fxdr_hyper(tl); 2518 tl += 2; 2519 cnt = fxdr_unsigned(int, *tl); 2520 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2521 if (error) { 2522 nfsm_reply(2 * NFSX_UNSIGNED); 2523 nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info); 2524 error = 0; 2525 goto nfsmout; 2526 } 2527 for_ret = VOP_GETATTR(vp, &bfor, cred, procp); 2528 error = VOP_FSYNC(vp, cred, MNT_WAIT, procp); 2529 aft_ret = VOP_GETATTR(vp, &aft, cred, procp); 2530 vput(vp); 2531 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); 2532 nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info); 2533 if (!error) { 2534 tl = nfsm_build(&info.nmi_mb, NFSX_V3WRITEVERF); 2535 *tl++ = txdr_unsigned(boottime.tv_sec); 2536 *tl = txdr_unsigned(boottime.tv_nsec/1000); 2537 } else 2538 error = 0; 2539 nfsmout: 2540 return(error); 2541 } 2542 2543 /* 2544 * nfs statfs service 2545 */ 2546 int 2547 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2548 struct proc *procp, struct mbuf **mrq) 2549 { 2550 struct mbuf *nam = nfsd->nd_nam; 2551 struct ucred *cred = &nfsd->nd_cr; 2552 struct statfs *sf; 2553 struct nfs_statfs *sfp; 2554 struct nfsm_info info; 2555 u_int32_t *tl; 2556 int32_t t1; 2557 int error = 0, rdonly, getret = 1; 2558 char *cp2; 2559 struct vnode *vp; 2560 struct vattr at; 2561 nfsfh_t nfh; 2562 fhandle_t *fhp; 2563 struct statfs statfs; 2564 u_quad_t tval; 2565 2566 info.nmi_mreq = NULL; 2567 info.nmi_mrep = nfsd->nd_mrep; 2568 info.nmi_md = nfsd->nd_md; 2569 info.nmi_dpos = nfsd->nd_dpos; 2570 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2571 2572 fhp = &nfh.fh_generic; 2573 nfsm_srvmtofh(fhp); 2574 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2575 if (error) { 2576 nfsm_reply(NFSX_UNSIGNED); 2577 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2578 error = 0; 2579 goto nfsmout; 2580 } 2581 sf = &statfs; 2582 error = VFS_STATFS(vp->v_mount, sf, procp); 2583 getret = VOP_GETATTR(vp, &at, cred, procp); 2584 vput(vp); 2585 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_STATFS(info.nmi_v3)); 2586 if (info.nmi_v3) 2587 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2588 if (error) { 2589 error = 0; 2590 goto nfsmout; 2591 } 2592 sfp = nfsm_build(&info.nmi_mb, NFSX_STATFS(info.nmi_v3)); 2593 if (info.nmi_v3) { 2594 tval = (u_quad_t)sf->f_blocks; 2595 tval *= (u_quad_t)sf->f_bsize; 2596 txdr_hyper(tval, &sfp->sf_tbytes); 2597 tval = (u_quad_t)sf->f_bfree; 2598 tval *= (u_quad_t)sf->f_bsize; 2599 txdr_hyper(tval, &sfp->sf_fbytes); 2600 tval = (u_quad_t)sf->f_bavail; 2601 tval *= (u_quad_t)sf->f_bsize; 2602 txdr_hyper(tval, &sfp->sf_abytes); 2603 tval = (u_quad_t)sf->f_files; 2604 txdr_hyper(tval, &sfp->sf_tfiles); 2605 tval = (u_quad_t)sf->f_ffree; 2606 txdr_hyper(tval, &sfp->sf_ffiles); 2607 txdr_hyper(tval, &sfp->sf_afiles); 2608 sfp->sf_invarsec = 0; 2609 } else { 2610 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 2611 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 2612 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 2613 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 2614 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 2615 } 2616 nfsmout: 2617 return(error); 2618 } 2619 2620 /* 2621 * nfs fsinfo service 2622 */ 2623 int 2624 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2625 struct proc *procp, struct mbuf **mrq) 2626 { 2627 struct mbuf *nam = nfsd->nd_nam; 2628 struct ucred *cred = &nfsd->nd_cr; 2629 struct nfsm_info info; 2630 u_int32_t *tl; 2631 struct nfsv3_fsinfo *sip; 2632 int32_t t1; 2633 int error = 0, rdonly, getret = 1, pref; 2634 char *cp2; 2635 struct vnode *vp; 2636 struct vattr at; 2637 nfsfh_t nfh; 2638 fhandle_t *fhp; 2639 2640 info.nmi_mreq = NULL; 2641 info.nmi_mrep = nfsd->nd_mrep; 2642 info.nmi_md = nfsd->nd_md; 2643 info.nmi_dpos = nfsd->nd_dpos; 2644 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2645 2646 fhp = &nfh.fh_generic; 2647 nfsm_srvmtofh(fhp); 2648 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2649 if (error) { 2650 nfsm_reply(NFSX_UNSIGNED); 2651 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2652 error = 0; 2653 goto nfsmout; 2654 } 2655 getret = VOP_GETATTR(vp, &at, cred, procp); 2656 vput(vp); 2657 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); 2658 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2659 sip = nfsm_build(&info.nmi_mb, NFSX_V3FSINFO); 2660 2661 /* 2662 * XXX 2663 * There should be file system VFS OP(s) to get this information. 2664 * For now, assume ufs. 2665 */ 2666 if (slp->ns_so->so_type == SOCK_DGRAM) 2667 pref = NFS_MAXDGRAMDATA; 2668 else 2669 pref = NFS_MAXDATA; 2670 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 2671 sip->fs_rtpref = txdr_unsigned(pref); 2672 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 2673 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 2674 sip->fs_wtpref = txdr_unsigned(pref); 2675 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 2676 sip->fs_dtpref = txdr_unsigned(pref); 2677 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff; 2678 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff; 2679 sip->fs_timedelta.nfsv3_sec = 0; 2680 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 2681 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 2682 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 2683 NFSV3FSINFO_CANSETTIME); 2684 nfsmout: 2685 return(error); 2686 } 2687 2688 /* 2689 * nfs pathconf service 2690 */ 2691 int 2692 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2693 struct proc *procp, struct mbuf **mrq) 2694 { 2695 struct mbuf *nam = nfsd->nd_nam; 2696 struct ucred *cred = &nfsd->nd_cr; 2697 struct nfsm_info info; 2698 u_int32_t *tl; 2699 struct nfsv3_pathconf *pc; 2700 int32_t t1; 2701 int error = 0, rdonly, getret = 1; 2702 register_t linkmax, namemax, chownres, notrunc; 2703 char *cp2; 2704 struct vnode *vp; 2705 struct vattr at; 2706 nfsfh_t nfh; 2707 fhandle_t *fhp; 2708 2709 info.nmi_mreq = NULL; 2710 info.nmi_mrep = nfsd->nd_mrep; 2711 info.nmi_md = nfsd->nd_md; 2712 info.nmi_dpos = nfsd->nd_dpos; 2713 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2714 2715 fhp = &nfh.fh_generic; 2716 nfsm_srvmtofh(fhp); 2717 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2718 if (error) { 2719 nfsm_reply(NFSX_UNSIGNED); 2720 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2721 error = 0; 2722 goto nfsmout; 2723 } 2724 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 2725 if (!error) 2726 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 2727 if (!error) 2728 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 2729 if (!error) 2730 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 2731 getret = VOP_GETATTR(vp, &at, cred, procp); 2732 vput(vp); 2733 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); 2734 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2735 if (error) { 2736 error = 0; 2737 goto nfsmout; 2738 } 2739 pc = nfsm_build(&info.nmi_mb, NFSX_V3PATHCONF); 2740 2741 pc->pc_linkmax = txdr_unsigned(linkmax); 2742 pc->pc_namemax = txdr_unsigned(namemax); 2743 pc->pc_notrunc = txdr_unsigned(notrunc); 2744 pc->pc_chownrestricted = txdr_unsigned(chownres); 2745 2746 /* 2747 * These should probably be supported by VOP_PATHCONF(), but 2748 * until msdosfs is exportable (why would you want to?), the 2749 * Unix defaults should be ok. 2750 */ 2751 pc->pc_caseinsensitive = nfs_false; 2752 pc->pc_casepreserving = nfs_true; 2753 nfsmout: 2754 return(error); 2755 } 2756 2757 /* 2758 * Null operation, used by clients to ping server 2759 */ 2760 /* ARGSUSED */ 2761 int 2762 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2763 struct proc *procp, struct mbuf **mrq) 2764 { 2765 struct nfsm_info info; 2766 int error = NFSERR_RETVOID; 2767 2768 info.nmi_mreq = NULL; 2769 info.nmi_mrep = nfsd->nd_mrep; 2770 info.nmi_md = nfsd->nd_md; 2771 info.nmi_dpos = nfsd->nd_dpos; 2772 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2773 2774 nfsm_reply(0); 2775 return (0); 2776 } 2777 2778 /* 2779 * No operation, used for obsolete procedures 2780 */ 2781 /* ARGSUSED */ 2782 int 2783 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2784 struct proc *procp, struct mbuf **mrq) 2785 { 2786 struct nfsm_info info; 2787 int error; 2788 2789 info.nmi_mreq = NULL; 2790 info.nmi_mrep = nfsd->nd_mrep; 2791 info.nmi_md = nfsd->nd_md; 2792 info.nmi_dpos = nfsd->nd_dpos; 2793 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2794 2795 if (nfsd->nd_repstat) 2796 error = nfsd->nd_repstat; 2797 else 2798 error = EPROCUNAVAIL; 2799 nfsm_reply(0); 2800 return (0); 2801 } 2802 2803 /* 2804 * Perform access checking for vnodes obtained from file handles that would 2805 * refer to files already opened by a Unix client. 2806 * You cannot just use vn_writechk() and VOP_ACCESS() for two reasons: 2807 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the 2808 * write case 2809 * 2 - The owner is to be given access irrespective of mode bits for some 2810 * operations, so that processes that chmod after opening a file don't 2811 * break. I don't like this because it opens a security hole, but since 2812 * the nfs server opens a security hole the size of a barn door anyhow, 2813 * what the heck. A notable exception to this rule is when VOP_ACCESS() 2814 * returns EPERM (e.g. when a file is immutable) which is always an 2815 * error. 2816 */ 2817 int 2818 nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly, 2819 struct proc *p, int override) 2820 { 2821 struct vattr vattr; 2822 int error; 2823 2824 if (flags & VWRITE) { 2825 /* Just vn_writechk() changed to check rdonly */ 2826 /* 2827 * Disallow write attempts on read-only file systems; 2828 * unless the file is a socket or a block or character 2829 * device resident on the file system. 2830 */ 2831 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 2832 switch (vp->v_type) { 2833 case VREG: 2834 case VDIR: 2835 case VLNK: 2836 return (EROFS); 2837 default: 2838 break; 2839 } 2840 } 2841 /* 2842 * If there's shared text associated with 2843 * the inode, try to free it up once. If 2844 * we fail, we can't allow writing. 2845 */ 2846 if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp)) 2847 return (ETXTBSY); 2848 } 2849 error = VOP_ACCESS(vp, flags, cred, p); 2850 /* 2851 * Allow certain operations for the owner (reads and writes 2852 * on files that are already open). 2853 */ 2854 if (override && error == EACCES && 2855 VOP_GETATTR(vp, &vattr, cred, p) == 0 && 2856 cred->cr_uid == vattr.va_uid) 2857 error = 0; 2858 return error; 2859 } 2860