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