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