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