xref: /openbsd/sys/nfs/nfs_serv.c (revision af61481e)
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
nfsm_reply(struct nfsm_info * infop,struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct mbuf ** mrq,int error,int statuslen)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
nfsm_srvmtofh1(struct nfsm_info * infop,struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct mbuf ** mrq)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
nfsm_srvmtofh2(struct nfsm_info * infop,fhandle_t * fhp)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
nfsrv3_access(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_getattr(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_setattr(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsm_srvnamesiz(struct nfsm_info * infop,int * lenp)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
nfsrv_lookup(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_readlink(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_read(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_write(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsm_srvpostop_fh(struct nfsm_info * infop,fhandle_t * fhp)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
nfsrv_create(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_mknod(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_remove(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_rename(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_link(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_symlink(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_mkdir(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_rmdir(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_readdir(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_readdirplus(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_commit(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_statfs(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_fsinfo(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_pathconf(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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, &notrunc);
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
nfsrv_null(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_noop(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)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
nfsrv_access(struct vnode * vp,int flags,struct ucred * cred,int rdonly,struct proc * p,int override)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