xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision 0572ccaa4543b0abef8ef81e384c1d04de9f3da1)
1 /*-
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 /*
38  * nfs version 2, 3 and 4 server calls to vnode ops
39  * - these routines generally have 3 phases
40  *   1 - break down and validate rpc request in mbuf list
41  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
42  *       function in nfsd_port.c
43  *   3 - build the rpc reply in an mbuf list
44  * For nfsv4, these functions are called for each Op within the Compound RPC.
45  */
46 
47 #ifndef APPLEKEXT
48 #include <fs/nfs/nfsport.h>
49 
50 /* Global vars */
51 extern u_int32_t newnfs_false, newnfs_true;
52 extern enum vtype nv34tov_type[8];
53 extern struct timeval nfsboottime;
54 extern int nfs_rootfhset;
55 extern int nfsrv_enable_crossmntpt;
56 #endif	/* !APPLEKEXT */
57 
58 static int	nfs_async = 0;
59 SYSCTL_DECL(_vfs_nfsd);
60 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
61     "Tell client that writes were synced even though they were not");
62 
63 /*
64  * This list defines the GSS mechanisms supported.
65  * (Don't ask me how you get these strings from the RFC stuff like
66  *  iso(1), org(3)... but someone did it, so I don't need to know.)
67  */
68 static struct nfsgss_mechlist nfsgss_mechlist[] = {
69 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
70 	{ 0, "", 0 },
71 };
72 
73 /* local functions */
74 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
75     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
76     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
77     int *diraft_retp, nfsattrbit_t *attrbitp,
78     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
79     int pathlen);
80 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
81     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
82     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
83     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
84     NFSPROC_T *p, struct nfsexstuff *exp);
85 
86 /*
87  * nfs access service (not a part of NFS V2)
88  */
89 APPLESTATIC int
90 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
91     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
92 {
93 	u_int32_t *tl;
94 	int getret, error = 0;
95 	struct nfsvattr nva;
96 	u_int32_t testmode, nfsmode, supported = 0;
97 	accmode_t deletebit;
98 
99 	if (nd->nd_repstat) {
100 		nfsrv_postopattr(nd, 1, &nva);
101 		goto out;
102 	}
103 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
104 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
105 	if ((nd->nd_flag & ND_NFSV4) &&
106 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
107 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
108 	     NFSACCESS_EXECUTE))) {
109 		nd->nd_repstat = NFSERR_INVAL;
110 		vput(vp);
111 		goto out;
112 	}
113 	if (nfsmode & NFSACCESS_READ) {
114 		supported |= NFSACCESS_READ;
115 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
116 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
117 			nfsmode &= ~NFSACCESS_READ;
118 	}
119 	if (nfsmode & NFSACCESS_MODIFY) {
120 		supported |= NFSACCESS_MODIFY;
121 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
122 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
123 			nfsmode &= ~NFSACCESS_MODIFY;
124 	}
125 	if (nfsmode & NFSACCESS_EXTEND) {
126 		supported |= NFSACCESS_EXTEND;
127 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
128 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
129 			nfsmode &= ~NFSACCESS_EXTEND;
130 	}
131 	if (nfsmode & NFSACCESS_DELETE) {
132 		supported |= NFSACCESS_DELETE;
133 		if (vp->v_type == VDIR)
134 			deletebit = VDELETE_CHILD;
135 		else
136 			deletebit = VDELETE;
137 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
138 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
139 			nfsmode &= ~NFSACCESS_DELETE;
140 	}
141 	if (vnode_vtype(vp) == VDIR)
142 		testmode = NFSACCESS_LOOKUP;
143 	else
144 		testmode = NFSACCESS_EXECUTE;
145 	if (nfsmode & testmode) {
146 		supported |= (nfsmode & testmode);
147 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
148 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
149 			nfsmode &= ~testmode;
150 	}
151 	nfsmode &= supported;
152 	if (nd->nd_flag & ND_NFSV3) {
153 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
154 		nfsrv_postopattr(nd, getret, &nva);
155 	}
156 	vput(vp);
157 	if (nd->nd_flag & ND_NFSV4) {
158 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
159 		*tl++ = txdr_unsigned(supported);
160 	} else
161 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
162 	*tl = txdr_unsigned(nfsmode);
163 
164 out:
165 	NFSEXITCODE2(0, nd);
166 	return (0);
167 nfsmout:
168 	vput(vp);
169 	NFSEXITCODE2(error, nd);
170 	return (error);
171 }
172 
173 /*
174  * nfs getattr service
175  */
176 APPLESTATIC int
177 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
178     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
179 {
180 	struct nfsvattr nva;
181 	fhandle_t fh;
182 	int at_root = 0, error = 0, supports_nfsv4acls;
183 	struct nfsreferral *refp;
184 	nfsattrbit_t attrbits, tmpbits;
185 	struct mount *mp;
186 	struct vnode *tvp = NULL;
187 	struct vattr va;
188 	uint64_t mounted_on_fileno = 0;
189 	accmode_t accmode;
190 
191 	if (nd->nd_repstat)
192 		goto out;
193 	if (nd->nd_flag & ND_NFSV4) {
194 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
195 		if (error) {
196 			vput(vp);
197 			goto out;
198 		}
199 
200 		/*
201 		 * Check for a referral.
202 		 */
203 		refp = nfsv4root_getreferral(vp, NULL, 0);
204 		if (refp != NULL) {
205 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
206 			    &nd->nd_repstat);
207 			vput(vp);
208 			goto out;
209 		}
210 		if (nd->nd_repstat == 0) {
211 			accmode = 0;
212 			NFSSET_ATTRBIT(&tmpbits, &attrbits);
213 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
214 				NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
215 				accmode |= VREAD_ACL;
216 			}
217 			if (NFSNONZERO_ATTRBIT(&tmpbits))
218 				accmode |= VREAD_ATTRIBUTES;
219 			if (accmode != 0)
220 				nd->nd_repstat = nfsvno_accchk(vp, accmode,
221 				    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
222 				    NFSACCCHK_VPISLOCKED, NULL);
223 		}
224 	}
225 	if (!nd->nd_repstat)
226 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
227 	if (!nd->nd_repstat) {
228 		if (nd->nd_flag & ND_NFSV4) {
229 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
230 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
231 			if (!nd->nd_repstat)
232 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
233 				    &nva, &attrbits, nd->nd_cred, p);
234 			if (nd->nd_repstat == 0) {
235 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
236 				mp = vp->v_mount;
237 				if (nfsrv_enable_crossmntpt != 0 &&
238 				    vp->v_type == VDIR &&
239 				    (vp->v_vflag & VV_ROOT) != 0 &&
240 				    vp != rootvnode) {
241 					tvp = mp->mnt_vnodecovered;
242 					VREF(tvp);
243 					at_root = 1;
244 				} else
245 					at_root = 0;
246 				vfs_ref(mp);
247 				NFSVOPUNLOCK(vp, 0);
248 				if (at_root != 0) {
249 					if ((nd->nd_repstat =
250 					     NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
251 						nd->nd_repstat = VOP_GETATTR(
252 						    tvp, &va, nd->nd_cred);
253 						vput(tvp);
254 					} else
255 						vrele(tvp);
256 					if (nd->nd_repstat == 0)
257 						mounted_on_fileno = (uint64_t)
258 						    va.va_fileid;
259 					else
260 						at_root = 0;
261 				}
262 				if (nd->nd_repstat == 0)
263 					nd->nd_repstat = vfs_busy(mp, 0);
264 				vfs_rel(mp);
265 				if (nd->nd_repstat == 0) {
266 					(void)nfsvno_fillattr(nd, mp, vp, &nva,
267 					    &fh, 0, &attrbits, nd->nd_cred, p,
268 					    isdgram, 1, supports_nfsv4acls,
269 					    at_root, mounted_on_fileno);
270 					vfs_unbusy(mp);
271 				}
272 				vrele(vp);
273 			} else
274 				vput(vp);
275 		} else {
276 			nfsrv_fillattr(nd, &nva);
277 			vput(vp);
278 		}
279 	} else {
280 		vput(vp);
281 	}
282 
283 out:
284 	NFSEXITCODE2(error, nd);
285 	return (error);
286 }
287 
288 /*
289  * nfs setattr service
290  */
291 APPLESTATIC int
292 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
293     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
294 {
295 	struct nfsvattr nva, nva2;
296 	u_int32_t *tl;
297 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
298 	struct timespec guard = { 0, 0 };
299 	nfsattrbit_t attrbits, retbits;
300 	nfsv4stateid_t stateid;
301 	NFSACL_T *aclp = NULL;
302 
303 	if (nd->nd_repstat) {
304 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
305 		goto out;
306 	}
307 #ifdef NFS4_ACL_EXTATTR_NAME
308 	aclp = acl_alloc(M_WAITOK);
309 	aclp->acl_cnt = 0;
310 #endif
311 	NFSVNO_ATTRINIT(&nva);
312 	NFSZERO_ATTRBIT(&retbits);
313 	if (nd->nd_flag & ND_NFSV4) {
314 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
315 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
316 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
317 	}
318 	error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
319 	if (error)
320 		goto nfsmout;
321 	preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
322 	if (!nd->nd_repstat)
323 		nd->nd_repstat = preat_ret;
324 	if (nd->nd_flag & ND_NFSV3) {
325 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
326 		gcheck = fxdr_unsigned(int, *tl);
327 		if (gcheck) {
328 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
329 			fxdr_nfsv3time(tl, &guard);
330 		}
331 		if (!nd->nd_repstat && gcheck &&
332 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
333 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
334 			nd->nd_repstat = NFSERR_NOT_SYNC;
335 		if (nd->nd_repstat) {
336 			vput(vp);
337 #ifdef NFS4_ACL_EXTATTR_NAME
338 			acl_free(aclp);
339 #endif
340 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
341 			goto out;
342 		}
343 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
344 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
345 
346 	/*
347 	 * Now that we have all the fields, lets do it.
348 	 * If the size is being changed write access is required, otherwise
349 	 * just check for a read only file system.
350 	 */
351 	if (!nd->nd_repstat) {
352 		if (NFSVNO_NOTSETSIZE(&nva)) {
353 			if (NFSVNO_EXRDONLY(exp) ||
354 			    (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
355 				nd->nd_repstat = EROFS;
356 		} else {
357 			if (vnode_vtype(vp) != VREG)
358 				nd->nd_repstat = EINVAL;
359 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
360 			    NFSVNO_EXSTRICTACCESS(exp))
361 				nd->nd_repstat = nfsvno_accchk(vp,
362 				    VWRITE, nd->nd_cred, exp, p,
363 				    NFSACCCHK_NOOVERRIDE,
364 				    NFSACCCHK_VPISLOCKED, NULL);
365 		}
366 	}
367 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
368 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
369 		    &nva, &attrbits, exp, p);
370 
371 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
372 	    /*
373 	     * For V4, try setting the attrbutes in sets, so that the
374 	     * reply bitmap will be correct for an error case.
375 	     */
376 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
377 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
378 		NFSVNO_ATTRINIT(&nva2);
379 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
380 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
381 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
382 		    exp);
383 		if (!nd->nd_repstat) {
384 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
385 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
386 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
387 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
388 		}
389 	    }
390 	    if (!nd->nd_repstat &&
391 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
392 		NFSVNO_ATTRINIT(&nva2);
393 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
394 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
395 		    exp);
396 		if (!nd->nd_repstat)
397 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
398 	    }
399 	    if (!nd->nd_repstat &&
400 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
401 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
402 		NFSVNO_ATTRINIT(&nva2);
403 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
404 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
405 		if (nva.na_vaflags & VA_UTIMES_NULL) {
406 			nva2.na_vaflags |= VA_UTIMES_NULL;
407 			NFSVNO_SETACTIVE(&nva2, vaflags);
408 		}
409 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
410 		    exp);
411 		if (!nd->nd_repstat) {
412 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
413 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
414 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
415 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
416 		}
417 	    }
418 	    if (!nd->nd_repstat &&
419 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
420 		NFSVNO_ATTRINIT(&nva2);
421 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
422 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
423 		    exp);
424 		if (!nd->nd_repstat)
425 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
426 	    }
427 
428 #ifdef NFS4_ACL_EXTATTR_NAME
429 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
430 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
431 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
432 		if (!nd->nd_repstat)
433 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
434 	    }
435 #endif
436 	} else if (!nd->nd_repstat) {
437 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
438 		    exp);
439 	}
440 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
441 		postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
442 		if (!nd->nd_repstat)
443 			nd->nd_repstat = postat_ret;
444 	}
445 	vput(vp);
446 #ifdef NFS4_ACL_EXTATTR_NAME
447 	acl_free(aclp);
448 #endif
449 	if (nd->nd_flag & ND_NFSV3)
450 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
451 	else if (nd->nd_flag & ND_NFSV4)
452 		(void) nfsrv_putattrbit(nd, &retbits);
453 	else if (!nd->nd_repstat)
454 		nfsrv_fillattr(nd, &nva);
455 
456 out:
457 	NFSEXITCODE2(0, nd);
458 	return (0);
459 nfsmout:
460 	vput(vp);
461 #ifdef NFS4_ACL_EXTATTR_NAME
462 	acl_free(aclp);
463 #endif
464 	if (nd->nd_flag & ND_NFSV4) {
465 		/*
466 		 * For all nd_repstat, the V4 reply includes a bitmap,
467 		 * even NFSERR_BADXDR, which is what this will end up
468 		 * returning.
469 		 */
470 		(void) nfsrv_putattrbit(nd, &retbits);
471 	}
472 	NFSEXITCODE2(error, nd);
473 	return (error);
474 }
475 
476 /*
477  * nfs lookup rpc
478  * (Also performs lookup parent for v4)
479  */
480 APPLESTATIC int
481 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
482     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
483     struct nfsexstuff *exp)
484 {
485 	struct nameidata named;
486 	vnode_t vp, dirp = NULL;
487 	int error = 0, dattr_ret = 1;
488 	struct nfsvattr nva, dattr;
489 	char *bufp;
490 	u_long *hashp;
491 
492 	if (nd->nd_repstat) {
493 		nfsrv_postopattr(nd, dattr_ret, &dattr);
494 		goto out;
495 	}
496 
497 	/*
498 	 * For some reason, if dp is a symlink, the error
499 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
500 	 */
501 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
502 		nd->nd_repstat = NFSERR_SYMLINK;
503 		vrele(dp);
504 		goto out;
505 	}
506 
507 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
508 	    LOCKLEAF | SAVESTART);
509 	nfsvno_setpathbuf(&named, &bufp, &hashp);
510 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
511 	if (error) {
512 		vrele(dp);
513 		nfsvno_relpathbuf(&named);
514 		goto out;
515 	}
516 	if (!nd->nd_repstat) {
517 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
518 	} else {
519 		vrele(dp);
520 		nfsvno_relpathbuf(&named);
521 	}
522 	if (nd->nd_repstat) {
523 		if (dirp) {
524 			if (nd->nd_flag & ND_NFSV3)
525 				dattr_ret = nfsvno_getattr(dirp, &dattr,
526 				    nd->nd_cred, p, 0);
527 			vrele(dirp);
528 		}
529 		if (nd->nd_flag & ND_NFSV3)
530 			nfsrv_postopattr(nd, dattr_ret, &dattr);
531 		goto out;
532 	}
533 	if (named.ni_startdir)
534 		vrele(named.ni_startdir);
535 	nfsvno_relpathbuf(&named);
536 	vp = named.ni_vp;
537 	if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
538 	    vp->v_type != VDIR && vp->v_type != VLNK)
539 		/*
540 		 * Only allow lookup of VDIR and VLNK for traversal of
541 		 * non-exported volumes during NFSv4 mounting.
542 		 */
543 		nd->nd_repstat = ENOENT;
544 	if (nd->nd_repstat == 0)
545 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
546 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
547 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
548 	if (vpp != NULL && nd->nd_repstat == 0)
549 		*vpp = vp;
550 	else
551 		vput(vp);
552 	if (dirp) {
553 		if (nd->nd_flag & ND_NFSV3)
554 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
555 			    p, 0);
556 		vrele(dirp);
557 	}
558 	if (nd->nd_repstat) {
559 		if (nd->nd_flag & ND_NFSV3)
560 			nfsrv_postopattr(nd, dattr_ret, &dattr);
561 		goto out;
562 	}
563 	if (nd->nd_flag & ND_NFSV2) {
564 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
565 		nfsrv_fillattr(nd, &nva);
566 	} else if (nd->nd_flag & ND_NFSV3) {
567 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
568 		nfsrv_postopattr(nd, 0, &nva);
569 		nfsrv_postopattr(nd, dattr_ret, &dattr);
570 	}
571 
572 out:
573 	NFSEXITCODE2(error, nd);
574 	return (error);
575 }
576 
577 /*
578  * nfs readlink service
579  */
580 APPLESTATIC int
581 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
582     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
583 {
584 	u_int32_t *tl;
585 	mbuf_t mp = NULL, mpend = NULL;
586 	int getret = 1, len;
587 	struct nfsvattr nva;
588 
589 	if (nd->nd_repstat) {
590 		nfsrv_postopattr(nd, getret, &nva);
591 		goto out;
592 	}
593 	if (vnode_vtype(vp) != VLNK) {
594 		if (nd->nd_flag & ND_NFSV2)
595 			nd->nd_repstat = ENXIO;
596 		else
597 			nd->nd_repstat = EINVAL;
598 	}
599 	if (!nd->nd_repstat)
600 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
601 		    &mp, &mpend, &len);
602 	if (nd->nd_flag & ND_NFSV3)
603 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
604 	vput(vp);
605 	if (nd->nd_flag & ND_NFSV3)
606 		nfsrv_postopattr(nd, getret, &nva);
607 	if (nd->nd_repstat)
608 		goto out;
609 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
610 	*tl = txdr_unsigned(len);
611 	mbuf_setnext(nd->nd_mb, mp);
612 	nd->nd_mb = mpend;
613 	nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
614 
615 out:
616 	NFSEXITCODE2(0, nd);
617 	return (0);
618 }
619 
620 /*
621  * nfs read service
622  */
623 APPLESTATIC int
624 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
625     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
626 {
627 	u_int32_t *tl;
628 	int error = 0, cnt, getret = 1, reqlen, eof = 0;
629 	mbuf_t m2, m3;
630 	struct nfsvattr nva;
631 	off_t off = 0x0;
632 	struct nfsstate st, *stp = &st;
633 	struct nfslock lo, *lop = &lo;
634 	nfsv4stateid_t stateid;
635 	nfsquad_t clientid;
636 
637 	if (nd->nd_repstat) {
638 		nfsrv_postopattr(nd, getret, &nva);
639 		goto out;
640 	}
641 	if (nd->nd_flag & ND_NFSV2) {
642 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
643 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
644 		reqlen = fxdr_unsigned(int, *tl);
645 	} else if (nd->nd_flag & ND_NFSV3) {
646 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
647 		off = fxdr_hyper(tl);
648 		tl += 2;
649 		reqlen = fxdr_unsigned(int, *tl);
650 	} else {
651 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
652 		reqlen = fxdr_unsigned(int, *(tl + 6));
653 	}
654 	if (reqlen > NFS_SRVMAXDATA(nd)) {
655 		reqlen = NFS_SRVMAXDATA(nd);
656 	} else if (reqlen < 0) {
657 		error = EBADRPC;
658 		goto nfsmout;
659 	}
660 	if (nd->nd_flag & ND_NFSV4) {
661 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
662 		lop->lo_flags = NFSLCK_READ;
663 		stp->ls_ownerlen = 0;
664 		stp->ls_op = NULL;
665 		stp->ls_uid = nd->nd_cred->cr_uid;
666 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
667 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
668 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
669 		if (nd->nd_flag & ND_IMPLIEDCLID) {
670 			if (nd->nd_clientid.qval != clientid.qval)
671 				printf("EEK! multiple clids\n");
672 		} else {
673 			nd->nd_flag |= ND_IMPLIEDCLID;
674 			nd->nd_clientid.qval = clientid.qval;
675 		}
676 		stp->ls_stateid.other[2] = *tl++;
677 		off = fxdr_hyper(tl);
678 		lop->lo_first = off;
679 		tl += 2;
680 		lop->lo_end = off + reqlen;
681 		/*
682 		 * Paranoia, just in case it wraps around.
683 		 */
684 		if (lop->lo_end < off)
685 			lop->lo_end = NFS64BITSSET;
686 	}
687 	if (vnode_vtype(vp) != VREG) {
688 		if (nd->nd_flag & ND_NFSV3)
689 			nd->nd_repstat = EINVAL;
690 		else
691 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
692 			    EINVAL;
693 	}
694 	getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
695 	if (!nd->nd_repstat)
696 		nd->nd_repstat = getret;
697 	if (!nd->nd_repstat &&
698 	    (nva.na_uid != nd->nd_cred->cr_uid ||
699 	     NFSVNO_EXSTRICTACCESS(exp))) {
700 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
701 		    nd->nd_cred, exp, p,
702 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
703 		if (nd->nd_repstat)
704 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
705 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
706 			    NFSACCCHK_VPISLOCKED, NULL);
707 	}
708 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
709 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
710 		    &stateid, exp, nd, p);
711 	if (nd->nd_repstat) {
712 		vput(vp);
713 		if (nd->nd_flag & ND_NFSV3)
714 			nfsrv_postopattr(nd, getret, &nva);
715 		goto out;
716 	}
717 	if (off >= nva.na_size) {
718 		cnt = 0;
719 		eof = 1;
720 	} else if (reqlen == 0)
721 		cnt = 0;
722 	else if ((off + reqlen) >= nva.na_size) {
723 		cnt = nva.na_size - off;
724 		eof = 1;
725 	} else
726 		cnt = reqlen;
727 	m3 = NULL;
728 	if (cnt > 0) {
729 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
730 		    &m3, &m2);
731 		if (!(nd->nd_flag & ND_NFSV4)) {
732 			getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
733 			if (!nd->nd_repstat)
734 				nd->nd_repstat = getret;
735 		}
736 		if (nd->nd_repstat) {
737 			vput(vp);
738 			if (m3)
739 				mbuf_freem(m3);
740 			if (nd->nd_flag & ND_NFSV3)
741 				nfsrv_postopattr(nd, getret, &nva);
742 			goto out;
743 		}
744 	}
745 	vput(vp);
746 	if (nd->nd_flag & ND_NFSV2) {
747 		nfsrv_fillattr(nd, &nva);
748 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
749 	} else {
750 		if (nd->nd_flag & ND_NFSV3) {
751 			nfsrv_postopattr(nd, getret, &nva);
752 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
753 			*tl++ = txdr_unsigned(cnt);
754 		} else
755 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
756 		if (eof)
757 			*tl++ = newnfs_true;
758 		else
759 			*tl++ = newnfs_false;
760 	}
761 	*tl = txdr_unsigned(cnt);
762 	if (m3) {
763 		mbuf_setnext(nd->nd_mb, m3);
764 		nd->nd_mb = m2;
765 		nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
766 	}
767 
768 out:
769 	NFSEXITCODE2(0, nd);
770 	return (0);
771 nfsmout:
772 	vput(vp);
773 	NFSEXITCODE2(error, nd);
774 	return (error);
775 }
776 
777 /*
778  * nfs write service
779  */
780 APPLESTATIC int
781 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
782     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
783 {
784 	int i, cnt;
785 	u_int32_t *tl;
786 	mbuf_t mp;
787 	struct nfsvattr nva, forat;
788 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
789 	int stable = NFSWRITE_FILESYNC;
790 	off_t off;
791 	struct nfsstate st, *stp = &st;
792 	struct nfslock lo, *lop = &lo;
793 	nfsv4stateid_t stateid;
794 	nfsquad_t clientid;
795 
796 	if (nd->nd_repstat) {
797 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
798 		goto out;
799 	}
800 	if (nd->nd_flag & ND_NFSV2) {
801 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
802 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
803 		tl += 2;
804 		retlen = len = fxdr_unsigned(int32_t, *tl);
805 	} else if (nd->nd_flag & ND_NFSV3) {
806 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
807 		off = fxdr_hyper(tl);
808 		tl += 3;
809 		stable = fxdr_unsigned(int, *tl++);
810 		retlen = len = fxdr_unsigned(int32_t, *tl);
811 	} else {
812 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
813 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
814 		lop->lo_flags = NFSLCK_WRITE;
815 		stp->ls_ownerlen = 0;
816 		stp->ls_op = NULL;
817 		stp->ls_uid = nd->nd_cred->cr_uid;
818 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
819 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
820 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
821 		if (nd->nd_flag & ND_IMPLIEDCLID) {
822 			if (nd->nd_clientid.qval != clientid.qval)
823 				printf("EEK! multiple clids\n");
824 		} else {
825 			nd->nd_flag |= ND_IMPLIEDCLID;
826 			nd->nd_clientid.qval = clientid.qval;
827 		}
828 		stp->ls_stateid.other[2] = *tl++;
829 		off = fxdr_hyper(tl);
830 		lop->lo_first = off;
831 		tl += 2;
832 		stable = fxdr_unsigned(int, *tl++);
833 		retlen = len = fxdr_unsigned(int32_t, *tl);
834 		lop->lo_end = off + len;
835 		/*
836 		 * Paranoia, just in case it wraps around, which shouldn't
837 		 * ever happen anyhow.
838 		 */
839 		if (lop->lo_end < lop->lo_first)
840 			lop->lo_end = NFS64BITSSET;
841 	}
842 
843 	/*
844 	 * Loop through the mbuf chain, counting how many mbufs are a
845 	 * part of this write operation, so the iovec size is known.
846 	 */
847 	cnt = 0;
848 	mp = nd->nd_md;
849 	i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
850 	while (len > 0) {
851 		if (i > 0) {
852 			len -= i;
853 			cnt++;
854 		}
855 		mp = mbuf_next(mp);
856 		if (!mp) {
857 			if (len > 0) {
858 				error = EBADRPC;
859 				goto nfsmout;
860 			}
861 		} else
862 			i = mbuf_len(mp);
863 	}
864 
865 	if (retlen > NFS_MAXDATA || retlen < 0)
866 		nd->nd_repstat = EIO;
867 	if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
868 		if (nd->nd_flag & ND_NFSV3)
869 			nd->nd_repstat = EINVAL;
870 		else
871 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
872 			    EINVAL;
873 	}
874 	forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
875 	if (!nd->nd_repstat)
876 		nd->nd_repstat = forat_ret;
877 	if (!nd->nd_repstat &&
878 	    (forat.na_uid != nd->nd_cred->cr_uid ||
879 	     NFSVNO_EXSTRICTACCESS(exp)))
880 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
881 		    nd->nd_cred, exp, p,
882 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
883 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
884 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
885 		    &stateid, exp, nd, p);
886 	}
887 	if (nd->nd_repstat) {
888 		vput(vp);
889 		if (nd->nd_flag & ND_NFSV3)
890 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
891 		goto out;
892 	}
893 
894 	/*
895 	 * For NFS Version 2, it is not obvious what a write of zero length
896 	 * should do, but I might as well be consistent with Version 3,
897 	 * which is to return ok so long as there are no permission problems.
898 	 */
899 	if (retlen > 0) {
900 		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
901 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
902 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
903 		if (error)
904 			panic("nfsrv_write mbuf");
905 	}
906 	if (nd->nd_flag & ND_NFSV4)
907 		aftat_ret = 0;
908 	else
909 		aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
910 	vput(vp);
911 	if (!nd->nd_repstat)
912 		nd->nd_repstat = aftat_ret;
913 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
914 		if (nd->nd_flag & ND_NFSV3)
915 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
916 		if (nd->nd_repstat)
917 			goto out;
918 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
919 		*tl++ = txdr_unsigned(retlen);
920 		/*
921 		 * If nfs_async is set, then pretend the write was FILESYNC.
922 		 * Warning: Doing this violates RFC1813 and runs a risk
923 		 * of data written by a client being lost when the server
924 		 * crashes/reboots.
925 		 */
926 		if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
927 			*tl++ = txdr_unsigned(stable);
928 		else
929 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
930 		/*
931 		 * Actually, there is no need to txdr these fields,
932 		 * but it may make the values more human readable,
933 		 * for debugging purposes.
934 		 */
935 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
936 		*tl = txdr_unsigned(nfsboottime.tv_usec);
937 	} else if (!nd->nd_repstat)
938 		nfsrv_fillattr(nd, &nva);
939 
940 out:
941 	NFSEXITCODE2(0, nd);
942 	return (0);
943 nfsmout:
944 	vput(vp);
945 	NFSEXITCODE2(error, nd);
946 	return (error);
947 }
948 
949 /*
950  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
951  * now does a truncate to 0 length via. setattr if it already exists
952  * The core creation routine has been extracted out into nfsrv_creatsub(),
953  * so it can also be used by nfsrv_open() for V4.
954  */
955 APPLESTATIC int
956 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
957     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
958 {
959 	struct nfsvattr nva, dirfor, diraft;
960 	struct nfsv2_sattr *sp;
961 	struct nameidata named;
962 	u_int32_t *tl;
963 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
964 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
965 	NFSDEV_T rdev = 0;
966 	vnode_t vp = NULL, dirp = NULL;
967 	fhandle_t fh;
968 	char *bufp;
969 	u_long *hashp;
970 	enum vtype vtyp;
971 	int32_t cverf[2], tverf[2] = { 0, 0 };
972 
973 	if (nd->nd_repstat) {
974 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
975 		goto out;
976 	}
977 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
978 	    LOCKPARENT | LOCKLEAF | SAVESTART);
979 	nfsvno_setpathbuf(&named, &bufp, &hashp);
980 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
981 	if (error)
982 		goto nfsmout;
983 	if (!nd->nd_repstat) {
984 		NFSVNO_ATTRINIT(&nva);
985 		if (nd->nd_flag & ND_NFSV2) {
986 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
987 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
988 			if (vtyp == VNON)
989 				vtyp = VREG;
990 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
991 			NFSVNO_SETATTRVAL(&nva, mode,
992 			    nfstov_mode(sp->sa_mode));
993 			switch (nva.na_type) {
994 			case VREG:
995 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
996 				if (tsize != -1)
997 					NFSVNO_SETATTRVAL(&nva, size,
998 					    (u_quad_t)tsize);
999 				break;
1000 			case VCHR:
1001 			case VBLK:
1002 			case VFIFO:
1003 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1004 				break;
1005 			default:
1006 				break;
1007 			};
1008 		} else {
1009 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1010 			how = fxdr_unsigned(int, *tl);
1011 			switch (how) {
1012 			case NFSCREATE_GUARDED:
1013 			case NFSCREATE_UNCHECKED:
1014 				error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1015 				if (error)
1016 					goto nfsmout;
1017 				break;
1018 			case NFSCREATE_EXCLUSIVE:
1019 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1020 				cverf[0] = *tl++;
1021 				cverf[1] = *tl;
1022 				exclusive_flag = 1;
1023 				break;
1024 			};
1025 			NFSVNO_SETATTRVAL(&nva, type, VREG);
1026 		}
1027 	}
1028 	if (nd->nd_repstat) {
1029 		nfsvno_relpathbuf(&named);
1030 		if (nd->nd_flag & ND_NFSV3) {
1031 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1032 			    p, 1);
1033 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1034 			    &diraft);
1035 		}
1036 		vput(dp);
1037 		goto out;
1038 	}
1039 
1040 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1041 	if (dirp) {
1042 		if (nd->nd_flag & ND_NFSV2) {
1043 			vrele(dirp);
1044 			dirp = NULL;
1045 		} else {
1046 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1047 			    p, 0);
1048 		}
1049 	}
1050 	if (nd->nd_repstat) {
1051 		if (nd->nd_flag & ND_NFSV3)
1052 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1053 			    &diraft);
1054 		if (dirp)
1055 			vrele(dirp);
1056 		goto out;
1057 	}
1058 
1059 	if (!(nd->nd_flag & ND_NFSV2)) {
1060 		switch (how) {
1061 		case NFSCREATE_GUARDED:
1062 			if (named.ni_vp)
1063 				nd->nd_repstat = EEXIST;
1064 			break;
1065 		case NFSCREATE_UNCHECKED:
1066 			break;
1067 		case NFSCREATE_EXCLUSIVE:
1068 			if (named.ni_vp == NULL)
1069 				NFSVNO_SETATTRVAL(&nva, mode, 0);
1070 			break;
1071 		};
1072 	}
1073 
1074 	/*
1075 	 * Iff doesn't exist, create it
1076 	 * otherwise just truncate to 0 length
1077 	 *   should I set the mode too ?
1078 	 */
1079 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1080 	    &exclusive_flag, cverf, rdev, p, exp);
1081 
1082 	if (!nd->nd_repstat) {
1083 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1084 		if (!nd->nd_repstat)
1085 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1086 			    p, 1);
1087 		vput(vp);
1088 		if (!nd->nd_repstat) {
1089 			tverf[0] = nva.na_atime.tv_sec;
1090 			tverf[1] = nva.na_atime.tv_nsec;
1091 		}
1092 	}
1093 	if (nd->nd_flag & ND_NFSV2) {
1094 		if (!nd->nd_repstat) {
1095 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1096 			nfsrv_fillattr(nd, &nva);
1097 		}
1098 	} else {
1099 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1100 		    || cverf[1] != tverf[1]))
1101 			nd->nd_repstat = EEXIST;
1102 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1103 		vrele(dirp);
1104 		if (!nd->nd_repstat) {
1105 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1106 			nfsrv_postopattr(nd, 0, &nva);
1107 		}
1108 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1109 	}
1110 
1111 out:
1112 	NFSEXITCODE2(0, nd);
1113 	return (0);
1114 nfsmout:
1115 	vput(dp);
1116 	nfsvno_relpathbuf(&named);
1117 	NFSEXITCODE2(error, nd);
1118 	return (error);
1119 }
1120 
1121 /*
1122  * nfs v3 mknod service (and v4 create)
1123  */
1124 APPLESTATIC int
1125 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1126     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1127     struct nfsexstuff *exp)
1128 {
1129 	struct nfsvattr nva, dirfor, diraft;
1130 	u_int32_t *tl;
1131 	struct nameidata named;
1132 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1133 	u_int32_t major, minor;
1134 	enum vtype vtyp = VNON;
1135 	nfstype nfs4type = NFNON;
1136 	vnode_t vp, dirp = NULL;
1137 	nfsattrbit_t attrbits;
1138 	char *bufp = NULL, *pathcp = NULL;
1139 	u_long *hashp, cnflags;
1140 	NFSACL_T *aclp = NULL;
1141 
1142 	NFSVNO_ATTRINIT(&nva);
1143 	cnflags = (LOCKPARENT | SAVESTART);
1144 	if (nd->nd_repstat) {
1145 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1146 		goto out;
1147 	}
1148 #ifdef NFS4_ACL_EXTATTR_NAME
1149 	aclp = acl_alloc(M_WAITOK);
1150 	aclp->acl_cnt = 0;
1151 #endif
1152 
1153 	/*
1154 	 * For V4, the creation stuff is here, Yuck!
1155 	 */
1156 	if (nd->nd_flag & ND_NFSV4) {
1157 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1158 		vtyp = nfsv34tov_type(*tl);
1159 		nfs4type = fxdr_unsigned(nfstype, *tl);
1160 		switch (nfs4type) {
1161 		case NFLNK:
1162 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1163 			    &pathlen);
1164 			if (error)
1165 				goto nfsmout;
1166 			break;
1167 		case NFCHR:
1168 		case NFBLK:
1169 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1170 			major = fxdr_unsigned(u_int32_t, *tl++);
1171 			minor = fxdr_unsigned(u_int32_t, *tl);
1172 			nva.na_rdev = NFSMAKEDEV(major, minor);
1173 			break;
1174 		case NFSOCK:
1175 		case NFFIFO:
1176 			break;
1177 		case NFDIR:
1178 			cnflags = (LOCKPARENT | SAVENAME);
1179 			break;
1180 		default:
1181 			nd->nd_repstat = NFSERR_BADTYPE;
1182 			vrele(dp);
1183 #ifdef NFS4_ACL_EXTATTR_NAME
1184 			acl_free(aclp);
1185 #endif
1186 			goto out;
1187 		}
1188 	}
1189 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1190 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1191 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1192 	if (error)
1193 		goto nfsmout;
1194 	if (!nd->nd_repstat) {
1195 		if (nd->nd_flag & ND_NFSV3) {
1196 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1197 			vtyp = nfsv34tov_type(*tl);
1198 		}
1199 		error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1200 		if (error)
1201 			goto nfsmout;
1202 		nva.na_type = vtyp;
1203 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1204 		    (vtyp == VCHR || vtyp == VBLK)) {
1205 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1206 			major = fxdr_unsigned(u_int32_t, *tl++);
1207 			minor = fxdr_unsigned(u_int32_t, *tl);
1208 			nva.na_rdev = NFSMAKEDEV(major, minor);
1209 		}
1210 	}
1211 
1212 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1213 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1214 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1215 		    dirfor.na_gid == nva.na_gid)
1216 			NFSVNO_UNSET(&nva, gid);
1217 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1218 	}
1219 	if (nd->nd_repstat) {
1220 		vrele(dp);
1221 #ifdef NFS4_ACL_EXTATTR_NAME
1222 		acl_free(aclp);
1223 #endif
1224 		nfsvno_relpathbuf(&named);
1225 		if (pathcp)
1226 			FREE(pathcp, M_TEMP);
1227 		if (nd->nd_flag & ND_NFSV3)
1228 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1229 			    &diraft);
1230 		goto out;
1231 	}
1232 
1233 	/*
1234 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1235 	 * in va_mode, so we'll have to set a default here.
1236 	 */
1237 	if (NFSVNO_NOTSETMODE(&nva)) {
1238 		if (vtyp == VLNK)
1239 			nva.na_mode = 0755;
1240 		else
1241 			nva.na_mode = 0400;
1242 	}
1243 
1244 	if (vtyp == VDIR)
1245 		named.ni_cnd.cn_flags |= WILLBEDIR;
1246 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1247 	if (nd->nd_repstat) {
1248 		if (dirp) {
1249 			if (nd->nd_flag & ND_NFSV3)
1250 				dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1251 				    nd->nd_cred, p, 0);
1252 			vrele(dirp);
1253 		}
1254 #ifdef NFS4_ACL_EXTATTR_NAME
1255 		acl_free(aclp);
1256 #endif
1257 		if (nd->nd_flag & ND_NFSV3)
1258 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1259 			    &diraft);
1260 		goto out;
1261 	}
1262 	if (dirp)
1263 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1264 
1265 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1266 		if (vtyp == VDIR) {
1267 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1268 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1269 			    exp);
1270 #ifdef NFS4_ACL_EXTATTR_NAME
1271 			acl_free(aclp);
1272 #endif
1273 			goto out;
1274 		} else if (vtyp == VLNK) {
1275 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1276 			    &dirfor, &diraft, &diraft_ret, &attrbits,
1277 			    aclp, p, exp, pathcp, pathlen);
1278 #ifdef NFS4_ACL_EXTATTR_NAME
1279 			acl_free(aclp);
1280 #endif
1281 			FREE(pathcp, M_TEMP);
1282 			goto out;
1283 		}
1284 	}
1285 
1286 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1287 	if (!nd->nd_repstat) {
1288 		vp = named.ni_vp;
1289 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1290 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1291 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1292 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1293 			    p, 1);
1294 		if (vpp != NULL && nd->nd_repstat == 0) {
1295 			NFSVOPUNLOCK(vp, 0);
1296 			*vpp = vp;
1297 		} else
1298 			vput(vp);
1299 	}
1300 
1301 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1302 	vrele(dirp);
1303 	if (!nd->nd_repstat) {
1304 		if (nd->nd_flag & ND_NFSV3) {
1305 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1306 			nfsrv_postopattr(nd, 0, &nva);
1307 		} else {
1308 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1309 			*tl++ = newnfs_false;
1310 			txdr_hyper(dirfor.na_filerev, tl);
1311 			tl += 2;
1312 			txdr_hyper(diraft.na_filerev, tl);
1313 			(void) nfsrv_putattrbit(nd, &attrbits);
1314 		}
1315 	}
1316 	if (nd->nd_flag & ND_NFSV3)
1317 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1318 #ifdef NFS4_ACL_EXTATTR_NAME
1319 	acl_free(aclp);
1320 #endif
1321 
1322 out:
1323 	NFSEXITCODE2(0, nd);
1324 	return (0);
1325 nfsmout:
1326 	vrele(dp);
1327 #ifdef NFS4_ACL_EXTATTR_NAME
1328 	acl_free(aclp);
1329 #endif
1330 	if (bufp)
1331 		nfsvno_relpathbuf(&named);
1332 	if (pathcp)
1333 		FREE(pathcp, M_TEMP);
1334 
1335 	NFSEXITCODE2(error, nd);
1336 	return (error);
1337 }
1338 
1339 /*
1340  * nfs remove service
1341  */
1342 APPLESTATIC int
1343 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1344     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1345 {
1346 	struct nameidata named;
1347 	u_int32_t *tl;
1348 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
1349 	vnode_t dirp = NULL;
1350 	struct nfsvattr dirfor, diraft;
1351 	char *bufp;
1352 	u_long *hashp;
1353 
1354 	if (nd->nd_repstat) {
1355 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1356 		goto out;
1357 	}
1358 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1359 	    LOCKPARENT | LOCKLEAF);
1360 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1361 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1362 	if (error) {
1363 		vput(dp);
1364 		nfsvno_relpathbuf(&named);
1365 		goto out;
1366 	}
1367 	if (!nd->nd_repstat) {
1368 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1369 	} else {
1370 		vput(dp);
1371 		nfsvno_relpathbuf(&named);
1372 	}
1373 	if (dirp) {
1374 		if (!(nd->nd_flag & ND_NFSV2)) {
1375 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1376 			    nd->nd_cred, p, 0);
1377 		} else {
1378 			vrele(dirp);
1379 			dirp = NULL;
1380 		}
1381 	}
1382 	if (!nd->nd_repstat) {
1383 		if (nd->nd_flag & ND_NFSV4) {
1384 			if (vnode_vtype(named.ni_vp) == VDIR)
1385 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1386 				    nd->nd_cred, p, exp);
1387 			else
1388 				nd->nd_repstat = nfsvno_removesub(&named, 1,
1389 				    nd->nd_cred, p, exp);
1390 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
1391 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1392 			    nd->nd_cred, p, exp);
1393 		} else {
1394 			nd->nd_repstat = nfsvno_removesub(&named, 0,
1395 			    nd->nd_cred, p, exp);
1396 		}
1397 	}
1398 	if (!(nd->nd_flag & ND_NFSV2)) {
1399 		if (dirp) {
1400 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1401 			    p, 0);
1402 			vrele(dirp);
1403 		}
1404 		if (nd->nd_flag & ND_NFSV3) {
1405 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1406 			    &diraft);
1407 		} else if (!nd->nd_repstat) {
1408 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1409 			*tl++ = newnfs_false;
1410 			txdr_hyper(dirfor.na_filerev, tl);
1411 			tl += 2;
1412 			txdr_hyper(diraft.na_filerev, tl);
1413 		}
1414 	}
1415 
1416 out:
1417 	NFSEXITCODE2(error, nd);
1418 	return (error);
1419 }
1420 
1421 /*
1422  * nfs rename service
1423  */
1424 APPLESTATIC int
1425 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1426     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1427     struct nfsexstuff *toexp)
1428 {
1429 	u_int32_t *tl;
1430 	int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1431 	int tdirfor_ret = 1, tdiraft_ret = 1;
1432 	struct nameidata fromnd, tond;
1433 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1434 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1435 	struct nfsexstuff tnes;
1436 	struct nfsrvfh tfh;
1437 	char *bufp, *tbufp = NULL;
1438 	u_long *hashp;
1439 	fhandle_t fh;
1440 
1441 	if (nd->nd_repstat) {
1442 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1443 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1444 		goto out;
1445 	}
1446 	if (!(nd->nd_flag & ND_NFSV2))
1447 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1448 	tond.ni_cnd.cn_nameiop = 0;
1449 	tond.ni_startdir = NULL;
1450 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1451 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1452 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1453 	if (error) {
1454 		vput(dp);
1455 		if (todp)
1456 			vrele(todp);
1457 		nfsvno_relpathbuf(&fromnd);
1458 		goto out;
1459 	}
1460 	/*
1461 	 * Unlock dp in this code section, so it is unlocked before
1462 	 * tdp gets locked. This avoids a potential LOR if tdp is the
1463 	 * parent directory of dp.
1464 	 */
1465 	if (nd->nd_flag & ND_NFSV4) {
1466 		tdp = todp;
1467 		tnes = *toexp;
1468 		if (dp != tdp) {
1469 			NFSVOPUNLOCK(dp, 0);
1470 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1471 			    p, 0);	/* Might lock tdp. */
1472 		} else {
1473 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1474 			    p, 1);
1475 			NFSVOPUNLOCK(dp, 0);
1476 		}
1477 	} else {
1478 		tfh.nfsrvfh_len = 0;
1479 		error = nfsrv_mtofh(nd, &tfh);
1480 		if (error == 0)
1481 			error = nfsvno_getfh(dp, &fh, p);
1482 		if (error) {
1483 			vput(dp);
1484 			/* todp is always NULL except NFSv4 */
1485 			nfsvno_relpathbuf(&fromnd);
1486 			goto out;
1487 		}
1488 
1489 		/* If this is the same file handle, just VREF() the vnode. */
1490 		if (tfh.nfsrvfh_len == NFSX_MYFH &&
1491 		    !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1492 			VREF(dp);
1493 			tdp = dp;
1494 			tnes = *exp;
1495 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1496 			    p, 1);
1497 			NFSVOPUNLOCK(dp, 0);
1498 		} else {
1499 			NFSVOPUNLOCK(dp, 0);
1500 			nd->nd_cred->cr_uid = nd->nd_saveduid;
1501 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1502 			    0, p);	/* Locks tdp. */
1503 			if (tdp) {
1504 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1505 				    nd->nd_cred, p, 1);
1506 				NFSVOPUNLOCK(tdp, 0);
1507 			}
1508 		}
1509 	}
1510 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1511 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1512 	if (!nd->nd_repstat) {
1513 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1514 		if (error) {
1515 			if (tdp)
1516 				vrele(tdp);
1517 			vrele(dp);
1518 			nfsvno_relpathbuf(&fromnd);
1519 			nfsvno_relpathbuf(&tond);
1520 			goto out;
1521 		}
1522 	}
1523 	if (nd->nd_repstat) {
1524 		if (nd->nd_flag & ND_NFSV3) {
1525 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1526 			    &fdiraft);
1527 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1528 			    &tdiraft);
1529 		}
1530 		if (tdp)
1531 			vrele(tdp);
1532 		vrele(dp);
1533 		nfsvno_relpathbuf(&fromnd);
1534 		nfsvno_relpathbuf(&tond);
1535 		goto out;
1536 	}
1537 
1538 	/*
1539 	 * Done parsing, now down to business.
1540 	 */
1541 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1542 	if (nd->nd_repstat) {
1543 		if (nd->nd_flag & ND_NFSV3) {
1544 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1545 			    &fdiraft);
1546 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1547 			    &tdiraft);
1548 		}
1549 		if (fdirp)
1550 			vrele(fdirp);
1551 		if (tdp)
1552 			vrele(tdp);
1553 		nfsvno_relpathbuf(&tond);
1554 		goto out;
1555 	}
1556 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
1557 		tond.ni_cnd.cn_flags |= WILLBEDIR;
1558 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1559 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1560 	    nd->nd_flag, nd->nd_cred, p);
1561 	if (fdirp)
1562 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1563 		    0);
1564 	if (tdirp)
1565 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1566 		    0);
1567 	if (fdirp)
1568 		vrele(fdirp);
1569 	if (tdirp)
1570 		vrele(tdirp);
1571 	if (nd->nd_flag & ND_NFSV3) {
1572 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1573 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1574 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1575 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1576 		*tl++ = newnfs_false;
1577 		txdr_hyper(fdirfor.na_filerev, tl);
1578 		tl += 2;
1579 		txdr_hyper(fdiraft.na_filerev, tl);
1580 		tl += 2;
1581 		*tl++ = newnfs_false;
1582 		txdr_hyper(tdirfor.na_filerev, tl);
1583 		tl += 2;
1584 		txdr_hyper(tdiraft.na_filerev, tl);
1585 	}
1586 
1587 out:
1588 	NFSEXITCODE2(error, nd);
1589 	return (error);
1590 }
1591 
1592 /*
1593  * nfs link service
1594  */
1595 APPLESTATIC int
1596 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1597     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1598     struct nfsexstuff *toexp)
1599 {
1600 	struct nameidata named;
1601 	u_int32_t *tl;
1602 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1603 	vnode_t dirp = NULL, dp = NULL;
1604 	struct nfsvattr dirfor, diraft, at;
1605 	struct nfsexstuff tnes;
1606 	struct nfsrvfh dfh;
1607 	char *bufp;
1608 	u_long *hashp;
1609 
1610 	if (nd->nd_repstat) {
1611 		nfsrv_postopattr(nd, getret, &at);
1612 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1613 		goto out;
1614 	}
1615 	NFSVOPUNLOCK(vp, 0);
1616 	if (vnode_vtype(vp) == VDIR) {
1617 		if (nd->nd_flag & ND_NFSV4)
1618 			nd->nd_repstat = NFSERR_ISDIR;
1619 		else
1620 			nd->nd_repstat = NFSERR_INVAL;
1621 		if (tovp)
1622 			vrele(tovp);
1623 	} else if (vnode_vtype(vp) == VLNK) {
1624 		if (nd->nd_flag & ND_NFSV2)
1625 			nd->nd_repstat = NFSERR_INVAL;
1626 		else
1627 			nd->nd_repstat = NFSERR_NOTSUPP;
1628 		if (tovp)
1629 			vrele(tovp);
1630 	}
1631 	if (!nd->nd_repstat) {
1632 		if (nd->nd_flag & ND_NFSV4) {
1633 			dp = tovp;
1634 			tnes = *toexp;
1635 		} else {
1636 			error = nfsrv_mtofh(nd, &dfh);
1637 			if (error) {
1638 				vrele(vp);
1639 				/* tovp is always NULL unless NFSv4 */
1640 				goto out;
1641 			}
1642 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1643 			    p);
1644 			if (dp)
1645 				NFSVOPUNLOCK(dp, 0);
1646 		}
1647 	}
1648 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1649 	    LOCKPARENT | SAVENAME);
1650 	if (!nd->nd_repstat) {
1651 		nfsvno_setpathbuf(&named, &bufp, &hashp);
1652 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1653 		if (error) {
1654 			vrele(vp);
1655 			if (dp)
1656 				vrele(dp);
1657 			nfsvno_relpathbuf(&named);
1658 			goto out;
1659 		}
1660 		if (!nd->nd_repstat) {
1661 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1662 			    p, &dirp);
1663 		} else {
1664 			if (dp)
1665 				vrele(dp);
1666 			nfsvno_relpathbuf(&named);
1667 		}
1668 	}
1669 	if (dirp) {
1670 		if (nd->nd_flag & ND_NFSV2) {
1671 			vrele(dirp);
1672 			dirp = NULL;
1673 		} else {
1674 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1675 			    nd->nd_cred, p, 0);
1676 		}
1677 	}
1678 	if (!nd->nd_repstat)
1679 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1680 	if (nd->nd_flag & ND_NFSV3)
1681 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1682 	if (dirp) {
1683 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1684 		vrele(dirp);
1685 	}
1686 	vrele(vp);
1687 	if (nd->nd_flag & ND_NFSV3) {
1688 		nfsrv_postopattr(nd, getret, &at);
1689 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1690 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1691 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1692 		*tl++ = newnfs_false;
1693 		txdr_hyper(dirfor.na_filerev, tl);
1694 		tl += 2;
1695 		txdr_hyper(diraft.na_filerev, tl);
1696 	}
1697 
1698 out:
1699 	NFSEXITCODE2(error, nd);
1700 	return (error);
1701 }
1702 
1703 /*
1704  * nfs symbolic link service
1705  */
1706 APPLESTATIC int
1707 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1708     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1709     struct nfsexstuff *exp)
1710 {
1711 	struct nfsvattr nva, dirfor, diraft;
1712 	struct nameidata named;
1713 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1714 	vnode_t dirp = NULL;
1715 	char *bufp, *pathcp = NULL;
1716 	u_long *hashp;
1717 
1718 	if (nd->nd_repstat) {
1719 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1720 		goto out;
1721 	}
1722 	if (vpp)
1723 		*vpp = NULL;
1724 	NFSVNO_ATTRINIT(&nva);
1725 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1726 	    LOCKPARENT | SAVESTART);
1727 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1728 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1729 	if (!error && !nd->nd_repstat)
1730 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1731 	if (error) {
1732 		vrele(dp);
1733 		nfsvno_relpathbuf(&named);
1734 		goto out;
1735 	}
1736 	if (!nd->nd_repstat) {
1737 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1738 	} else {
1739 		vrele(dp);
1740 		nfsvno_relpathbuf(&named);
1741 	}
1742 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1743 		vrele(dirp);
1744 		dirp = NULL;
1745 	}
1746 
1747 	/*
1748 	 * And call nfsrvd_symlinksub() to do the common code. It will
1749 	 * return EBADRPC upon a parsing error, 0 otherwise.
1750 	 */
1751 	if (!nd->nd_repstat) {
1752 		if (dirp != NULL)
1753 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1754 			    p, 0);
1755 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1756 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1757 		    pathcp, pathlen);
1758 	} else if (dirp != NULL) {
1759 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1760 		vrele(dirp);
1761 	}
1762 	if (pathcp)
1763 		FREE(pathcp, M_TEMP);
1764 
1765 	if (nd->nd_flag & ND_NFSV3) {
1766 		if (!nd->nd_repstat) {
1767 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1768 			nfsrv_postopattr(nd, 0, &nva);
1769 		}
1770 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1771 	}
1772 
1773 out:
1774 	NFSEXITCODE2(error, nd);
1775 	return (error);
1776 }
1777 
1778 /*
1779  * Common code for creating a symbolic link.
1780  */
1781 static void
1782 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1783     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1784     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1785     int *diraft_retp, nfsattrbit_t *attrbitp,
1786     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1787     int pathlen)
1788 {
1789 	u_int32_t *tl;
1790 
1791 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1792 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1793 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1794 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1795 		if (nd->nd_flag & ND_NFSV3) {
1796 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1797 			if (!nd->nd_repstat)
1798 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1799 				    nvap, nd->nd_cred, p, 1);
1800 		}
1801 		if (vpp != NULL && nd->nd_repstat == 0) {
1802 			NFSVOPUNLOCK(ndp->ni_vp, 0);
1803 			*vpp = ndp->ni_vp;
1804 		} else
1805 			vput(ndp->ni_vp);
1806 	}
1807 	if (dirp) {
1808 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1809 		vrele(dirp);
1810 	}
1811 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1812 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1813 		*tl++ = newnfs_false;
1814 		txdr_hyper(dirforp->na_filerev, tl);
1815 		tl += 2;
1816 		txdr_hyper(diraftp->na_filerev, tl);
1817 		(void) nfsrv_putattrbit(nd, attrbitp);
1818 	}
1819 
1820 	NFSEXITCODE2(0, nd);
1821 }
1822 
1823 /*
1824  * nfs mkdir service
1825  */
1826 APPLESTATIC int
1827 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1828     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1829     struct nfsexstuff *exp)
1830 {
1831 	struct nfsvattr nva, dirfor, diraft;
1832 	struct nameidata named;
1833 	u_int32_t *tl;
1834 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
1835 	vnode_t dirp = NULL;
1836 	char *bufp;
1837 	u_long *hashp;
1838 
1839 	if (nd->nd_repstat) {
1840 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1841 		goto out;
1842 	}
1843 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1844 	    LOCKPARENT | SAVENAME);
1845 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1846 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1847 	if (error)
1848 		goto nfsmout;
1849 	if (!nd->nd_repstat) {
1850 		NFSVNO_ATTRINIT(&nva);
1851 		if (nd->nd_flag & ND_NFSV3) {
1852 			error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1853 			if (error)
1854 				goto nfsmout;
1855 		} else {
1856 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1857 			nva.na_mode = nfstov_mode(*tl++);
1858 		}
1859 	}
1860 	if (!nd->nd_repstat) {
1861 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1862 	} else {
1863 		vrele(dp);
1864 		nfsvno_relpathbuf(&named);
1865 	}
1866 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1867 		vrele(dirp);
1868 		dirp = NULL;
1869 	}
1870 	if (nd->nd_repstat) {
1871 		if (dirp != NULL) {
1872 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1873 			    p, 0);
1874 			vrele(dirp);
1875 		}
1876 		if (nd->nd_flag & ND_NFSV3)
1877 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1878 			    &diraft);
1879 		goto out;
1880 	}
1881 	if (dirp != NULL)
1882 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1883 
1884 	/*
1885 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1886 	 */
1887 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1888 	    &diraft_ret, NULL, NULL, p, exp);
1889 
1890 	if (nd->nd_flag & ND_NFSV3) {
1891 		if (!nd->nd_repstat) {
1892 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1893 			nfsrv_postopattr(nd, 0, &nva);
1894 		}
1895 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1896 	} else if (!nd->nd_repstat) {
1897 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1898 		nfsrv_fillattr(nd, &nva);
1899 	}
1900 
1901 out:
1902 	NFSEXITCODE2(0, nd);
1903 	return (0);
1904 nfsmout:
1905 	vrele(dp);
1906 	nfsvno_relpathbuf(&named);
1907 	NFSEXITCODE2(error, nd);
1908 	return (error);
1909 }
1910 
1911 /*
1912  * Code common to mkdir for V2,3 and 4.
1913  */
1914 static void
1915 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1916     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1917     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1918     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1919     NFSPROC_T *p, struct nfsexstuff *exp)
1920 {
1921 	vnode_t vp;
1922 	u_int32_t *tl;
1923 
1924 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
1925 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1926 	    nd->nd_cred, p, exp);
1927 	if (!nd->nd_repstat) {
1928 		vp = ndp->ni_vp;
1929 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1930 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1931 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1932 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1933 			    p, 1);
1934 		if (vpp && !nd->nd_repstat) {
1935 			NFSVOPUNLOCK(vp, 0);
1936 			*vpp = vp;
1937 		} else {
1938 			vput(vp);
1939 		}
1940 	}
1941 	if (dirp) {
1942 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1943 		vrele(dirp);
1944 	}
1945 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1946 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1947 		*tl++ = newnfs_false;
1948 		txdr_hyper(dirforp->na_filerev, tl);
1949 		tl += 2;
1950 		txdr_hyper(diraftp->na_filerev, tl);
1951 		(void) nfsrv_putattrbit(nd, attrbitp);
1952 	}
1953 
1954 	NFSEXITCODE2(0, nd);
1955 }
1956 
1957 /*
1958  * nfs commit service
1959  */
1960 APPLESTATIC int
1961 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1962     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1963 {
1964 	struct nfsvattr bfor, aft;
1965 	u_int32_t *tl;
1966 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
1967 	u_int64_t off;
1968 
1969 	if (nd->nd_repstat) {
1970 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1971 		goto out;
1972 	}
1973 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1974 	/*
1975 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
1976 	 * count parameters, so these arguments are useless (someday maybe).
1977 	 */
1978 	off = fxdr_hyper(tl);
1979 	tl += 2;
1980 	cnt = fxdr_unsigned(int, *tl);
1981 	if (nd->nd_flag & ND_NFSV3)
1982 		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1983 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1984 	if (nd->nd_flag & ND_NFSV3) {
1985 		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1986 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1987 	}
1988 	vput(vp);
1989 	if (!nd->nd_repstat) {
1990 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1991 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
1992 		*tl = txdr_unsigned(nfsboottime.tv_usec);
1993 	}
1994 
1995 out:
1996 	NFSEXITCODE2(0, nd);
1997 	return (0);
1998 nfsmout:
1999 	vput(vp);
2000 	NFSEXITCODE2(error, nd);
2001 	return (error);
2002 }
2003 
2004 /*
2005  * nfs statfs service
2006  */
2007 APPLESTATIC int
2008 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2009     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2010 {
2011 	struct statfs *sf;
2012 	u_int32_t *tl;
2013 	int getret = 1;
2014 	struct nfsvattr at;
2015 	struct statfs sfs;
2016 	u_quad_t tval;
2017 
2018 	if (nd->nd_repstat) {
2019 		nfsrv_postopattr(nd, getret, &at);
2020 		goto out;
2021 	}
2022 	sf = &sfs;
2023 	nd->nd_repstat = nfsvno_statfs(vp, sf);
2024 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2025 	vput(vp);
2026 	if (nd->nd_flag & ND_NFSV3)
2027 		nfsrv_postopattr(nd, getret, &at);
2028 	if (nd->nd_repstat)
2029 		goto out;
2030 	if (nd->nd_flag & ND_NFSV2) {
2031 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2032 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
2033 		*tl++ = txdr_unsigned(sf->f_bsize);
2034 		*tl++ = txdr_unsigned(sf->f_blocks);
2035 		*tl++ = txdr_unsigned(sf->f_bfree);
2036 		*tl = txdr_unsigned(sf->f_bavail);
2037 	} else {
2038 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2039 		tval = (u_quad_t)sf->f_blocks;
2040 		tval *= (u_quad_t)sf->f_bsize;
2041 		txdr_hyper(tval, tl); tl += 2;
2042 		tval = (u_quad_t)sf->f_bfree;
2043 		tval *= (u_quad_t)sf->f_bsize;
2044 		txdr_hyper(tval, tl); tl += 2;
2045 		tval = (u_quad_t)sf->f_bavail;
2046 		tval *= (u_quad_t)sf->f_bsize;
2047 		txdr_hyper(tval, tl); tl += 2;
2048 		tval = (u_quad_t)sf->f_files;
2049 		txdr_hyper(tval, tl); tl += 2;
2050 		tval = (u_quad_t)sf->f_ffree;
2051 		txdr_hyper(tval, tl); tl += 2;
2052 		tval = (u_quad_t)sf->f_ffree;
2053 		txdr_hyper(tval, tl); tl += 2;
2054 		*tl = 0;
2055 	}
2056 
2057 out:
2058 	NFSEXITCODE2(0, nd);
2059 	return (0);
2060 }
2061 
2062 /*
2063  * nfs fsinfo service
2064  */
2065 APPLESTATIC int
2066 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2067     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2068 {
2069 	u_int32_t *tl;
2070 	struct nfsfsinfo fs;
2071 	int getret = 1;
2072 	struct nfsvattr at;
2073 
2074 	if (nd->nd_repstat) {
2075 		nfsrv_postopattr(nd, getret, &at);
2076 		goto out;
2077 	}
2078 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2079 	nfsvno_getfs(&fs, isdgram);
2080 	vput(vp);
2081 	nfsrv_postopattr(nd, getret, &at);
2082 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2083 	*tl++ = txdr_unsigned(fs.fs_rtmax);
2084 	*tl++ = txdr_unsigned(fs.fs_rtpref);
2085 	*tl++ = txdr_unsigned(fs.fs_rtmult);
2086 	*tl++ = txdr_unsigned(fs.fs_wtmax);
2087 	*tl++ = txdr_unsigned(fs.fs_wtpref);
2088 	*tl++ = txdr_unsigned(fs.fs_wtmult);
2089 	*tl++ = txdr_unsigned(fs.fs_dtpref);
2090 	txdr_hyper(fs.fs_maxfilesize, tl);
2091 	tl += 2;
2092 	txdr_nfsv3time(&fs.fs_timedelta, tl);
2093 	tl += 2;
2094 	*tl = txdr_unsigned(fs.fs_properties);
2095 
2096 out:
2097 	NFSEXITCODE2(0, nd);
2098 	return (0);
2099 }
2100 
2101 /*
2102  * nfs pathconf service
2103  */
2104 APPLESTATIC int
2105 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2106     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2107 {
2108 	struct nfsv3_pathconf *pc;
2109 	int getret = 1;
2110 	register_t linkmax, namemax, chownres, notrunc;
2111 	struct nfsvattr at;
2112 
2113 	if (nd->nd_repstat) {
2114 		nfsrv_postopattr(nd, getret, &at);
2115 		goto out;
2116 	}
2117 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2118 	    nd->nd_cred, p);
2119 	if (!nd->nd_repstat)
2120 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2121 		    nd->nd_cred, p);
2122 	if (!nd->nd_repstat)
2123 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2124 		    &chownres, nd->nd_cred, p);
2125 	if (!nd->nd_repstat)
2126 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2127 		    nd->nd_cred, p);
2128 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2129 	vput(vp);
2130 	nfsrv_postopattr(nd, getret, &at);
2131 	if (!nd->nd_repstat) {
2132 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2133 		pc->pc_linkmax = txdr_unsigned(linkmax);
2134 		pc->pc_namemax = txdr_unsigned(namemax);
2135 		pc->pc_notrunc = txdr_unsigned(notrunc);
2136 		pc->pc_chownrestricted = txdr_unsigned(chownres);
2137 
2138 		/*
2139 		 * These should probably be supported by VOP_PATHCONF(), but
2140 		 * until msdosfs is exportable (why would you want to?), the
2141 		 * Unix defaults should be ok.
2142 		 */
2143 		pc->pc_caseinsensitive = newnfs_false;
2144 		pc->pc_casepreserving = newnfs_true;
2145 	}
2146 
2147 out:
2148 	NFSEXITCODE2(0, nd);
2149 	return (0);
2150 }
2151 
2152 /*
2153  * nfsv4 lock service
2154  */
2155 APPLESTATIC int
2156 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2157     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2158 {
2159 	u_int32_t *tl;
2160 	int i;
2161 	struct nfsstate *stp = NULL;
2162 	struct nfslock *lop;
2163 	struct nfslockconflict cf;
2164 	int error = 0;
2165 	u_short flags = NFSLCK_LOCK, lflags;
2166 	u_int64_t offset, len;
2167 	nfsv4stateid_t stateid;
2168 	nfsquad_t clientid;
2169 
2170 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2171 	i = fxdr_unsigned(int, *tl++);
2172 	switch (i) {
2173 	case NFSV4LOCKT_READW:
2174 		flags |= NFSLCK_BLOCKING;
2175 	case NFSV4LOCKT_READ:
2176 		lflags = NFSLCK_READ;
2177 		break;
2178 	case NFSV4LOCKT_WRITEW:
2179 		flags |= NFSLCK_BLOCKING;
2180 	case NFSV4LOCKT_WRITE:
2181 		lflags = NFSLCK_WRITE;
2182 		break;
2183 	default:
2184 		nd->nd_repstat = NFSERR_BADXDR;
2185 		goto nfsmout;
2186 	};
2187 	if (*tl++ == newnfs_true)
2188 		flags |= NFSLCK_RECLAIM;
2189 	offset = fxdr_hyper(tl);
2190 	tl += 2;
2191 	len = fxdr_hyper(tl);
2192 	tl += 2;
2193 	if (*tl == newnfs_true)
2194 		flags |= NFSLCK_OPENTOLOCK;
2195 	if (flags & NFSLCK_OPENTOLOCK) {
2196 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2197 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2198 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2199 			nd->nd_repstat = NFSERR_BADXDR;
2200 			goto nfsmout;
2201 		}
2202 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2203 			M_NFSDSTATE, M_WAITOK);
2204 		stp->ls_ownerlen = i;
2205 		stp->ls_op = nd->nd_rp;
2206 		stp->ls_seq = fxdr_unsigned(int, *tl++);
2207 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2208 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2209 			NFSX_STATEIDOTHER);
2210 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2211 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2212 		clientid.lval[0] = *tl++;
2213 		clientid.lval[1] = *tl++;
2214 		if (nd->nd_flag & ND_IMPLIEDCLID) {
2215 			if (nd->nd_clientid.qval != clientid.qval)
2216 				printf("EEK! multiple clids\n");
2217 		} else {
2218 			nd->nd_flag |= ND_IMPLIEDCLID;
2219 			nd->nd_clientid.qval = clientid.qval;
2220 		}
2221 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2222 		if (error)
2223 			goto nfsmout;
2224 	} else {
2225 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2226 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2227 			M_NFSDSTATE, M_WAITOK);
2228 		stp->ls_ownerlen = 0;
2229 		stp->ls_op = nd->nd_rp;
2230 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2231 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2232 			NFSX_STATEIDOTHER);
2233 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2234 		stp->ls_seq = fxdr_unsigned(int, *tl);
2235 		clientid.lval[0] = stp->ls_stateid.other[0];
2236 		clientid.lval[1] = stp->ls_stateid.other[1];
2237 		if (nd->nd_flag & ND_IMPLIEDCLID) {
2238 			if (nd->nd_clientid.qval != clientid.qval)
2239 				printf("EEK! multiple clids\n");
2240 		} else {
2241 			nd->nd_flag |= ND_IMPLIEDCLID;
2242 			nd->nd_clientid.qval = clientid.qval;
2243 		}
2244 	}
2245 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2246 		M_NFSDLOCK, M_WAITOK);
2247 	lop->lo_first = offset;
2248 	if (len == NFS64BITSSET) {
2249 		lop->lo_end = NFS64BITSSET;
2250 	} else {
2251 		lop->lo_end = offset + len;
2252 		if (lop->lo_end <= lop->lo_first)
2253 			nd->nd_repstat = NFSERR_INVAL;
2254 	}
2255 	lop->lo_flags = lflags;
2256 	stp->ls_flags = flags;
2257 	stp->ls_uid = nd->nd_cred->cr_uid;
2258 
2259 	/*
2260 	 * Do basic access checking.
2261 	 */
2262 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2263 	    if (vnode_vtype(vp) == VDIR)
2264 		nd->nd_repstat = NFSERR_ISDIR;
2265 	    else
2266 		nd->nd_repstat = NFSERR_INVAL;
2267 	}
2268 	if (!nd->nd_repstat) {
2269 	    if (lflags & NFSLCK_WRITE) {
2270 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2271 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2272 		    NFSACCCHK_VPISLOCKED, NULL);
2273 	    } else {
2274 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2275 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2276 		    NFSACCCHK_VPISLOCKED, NULL);
2277 		if (nd->nd_repstat)
2278 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2279 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2280 			NFSACCCHK_VPISLOCKED, NULL);
2281 	    }
2282 	}
2283 
2284 	/*
2285 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2286 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
2287 	 * of nd_repstat, if it gets that far.
2288 	 */
2289 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2290 		&stateid, exp, nd, p);
2291 	if (lop)
2292 		FREE((caddr_t)lop, M_NFSDLOCK);
2293 	if (stp)
2294 		FREE((caddr_t)stp, M_NFSDSTATE);
2295 	if (!nd->nd_repstat) {
2296 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2297 		*tl++ = txdr_unsigned(stateid.seqid);
2298 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2299 	} else if (nd->nd_repstat == NFSERR_DENIED) {
2300 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2301 		txdr_hyper(cf.cl_first, tl);
2302 		tl += 2;
2303 		if (cf.cl_end == NFS64BITSSET)
2304 			len = NFS64BITSSET;
2305 		else
2306 			len = cf.cl_end - cf.cl_first;
2307 		txdr_hyper(len, tl);
2308 		tl += 2;
2309 		if (cf.cl_flags == NFSLCK_WRITE)
2310 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2311 		else
2312 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2313 		*tl++ = stateid.other[0];
2314 		*tl = stateid.other[1];
2315 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2316 	}
2317 	vput(vp);
2318 	NFSEXITCODE2(0, nd);
2319 	return (0);
2320 nfsmout:
2321 	vput(vp);
2322 	if (stp)
2323 		free((caddr_t)stp, M_NFSDSTATE);
2324 	NFSEXITCODE2(error, nd);
2325 	return (error);
2326 }
2327 
2328 /*
2329  * nfsv4 lock test service
2330  */
2331 APPLESTATIC int
2332 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2333     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2334 {
2335 	u_int32_t *tl;
2336 	int i;
2337 	struct nfsstate *stp = NULL;
2338 	struct nfslock lo, *lop = &lo;
2339 	struct nfslockconflict cf;
2340 	int error = 0;
2341 	nfsv4stateid_t stateid;
2342 	nfsquad_t clientid;
2343 	u_int64_t len;
2344 
2345 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2346 	i = fxdr_unsigned(int, *(tl + 7));
2347 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2348 		nd->nd_repstat = NFSERR_BADXDR;
2349 		goto nfsmout;
2350 	}
2351 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2352 	    M_NFSDSTATE, M_WAITOK);
2353 	stp->ls_ownerlen = i;
2354 	stp->ls_op = NULL;
2355 	stp->ls_flags = NFSLCK_TEST;
2356 	stp->ls_uid = nd->nd_cred->cr_uid;
2357 	i = fxdr_unsigned(int, *tl++);
2358 	switch (i) {
2359 	case NFSV4LOCKT_READW:
2360 		stp->ls_flags |= NFSLCK_BLOCKING;
2361 	case NFSV4LOCKT_READ:
2362 		lo.lo_flags = NFSLCK_READ;
2363 		break;
2364 	case NFSV4LOCKT_WRITEW:
2365 		stp->ls_flags |= NFSLCK_BLOCKING;
2366 	case NFSV4LOCKT_WRITE:
2367 		lo.lo_flags = NFSLCK_WRITE;
2368 		break;
2369 	default:
2370 		nd->nd_repstat = NFSERR_BADXDR;
2371 		goto nfsmout;
2372 	};
2373 	lo.lo_first = fxdr_hyper(tl);
2374 	tl += 2;
2375 	len = fxdr_hyper(tl);
2376 	if (len == NFS64BITSSET) {
2377 		lo.lo_end = NFS64BITSSET;
2378 	} else {
2379 		lo.lo_end = lo.lo_first + len;
2380 		if (lo.lo_end <= lo.lo_first)
2381 			nd->nd_repstat = NFSERR_INVAL;
2382 	}
2383 	tl += 2;
2384 	clientid.lval[0] = *tl++;
2385 	clientid.lval[1] = *tl;
2386 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2387 		if (nd->nd_clientid.qval != clientid.qval)
2388 			printf("EEK! multiple clids\n");
2389 	} else {
2390 		nd->nd_flag |= ND_IMPLIEDCLID;
2391 		nd->nd_clientid.qval = clientid.qval;
2392 	}
2393 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2394 	if (error)
2395 		goto nfsmout;
2396 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2397 	    if (vnode_vtype(vp) == VDIR)
2398 		nd->nd_repstat = NFSERR_ISDIR;
2399 	    else
2400 		nd->nd_repstat = NFSERR_INVAL;
2401 	}
2402 	if (!nd->nd_repstat)
2403 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2404 	    &stateid, exp, nd, p);
2405 	if (stp)
2406 		FREE((caddr_t)stp, M_NFSDSTATE);
2407 	if (nd->nd_repstat) {
2408 	    if (nd->nd_repstat == NFSERR_DENIED) {
2409 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2410 		txdr_hyper(cf.cl_first, tl);
2411 		tl += 2;
2412 		if (cf.cl_end == NFS64BITSSET)
2413 			len = NFS64BITSSET;
2414 		else
2415 			len = cf.cl_end - cf.cl_first;
2416 		txdr_hyper(len, tl);
2417 		tl += 2;
2418 		if (cf.cl_flags == NFSLCK_WRITE)
2419 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2420 		else
2421 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2422 		*tl++ = stp->ls_stateid.other[0];
2423 		*tl = stp->ls_stateid.other[1];
2424 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2425 	    }
2426 	}
2427 	vput(vp);
2428 	NFSEXITCODE2(0, nd);
2429 	return (0);
2430 nfsmout:
2431 	vput(vp);
2432 	if (stp)
2433 		free((caddr_t)stp, M_NFSDSTATE);
2434 	NFSEXITCODE2(error, nd);
2435 	return (error);
2436 }
2437 
2438 /*
2439  * nfsv4 unlock service
2440  */
2441 APPLESTATIC int
2442 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2443     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2444 {
2445 	u_int32_t *tl;
2446 	int i;
2447 	struct nfsstate *stp;
2448 	struct nfslock *lop;
2449 	int error = 0;
2450 	nfsv4stateid_t stateid;
2451 	nfsquad_t clientid;
2452 	u_int64_t len;
2453 
2454 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2455 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2456 	    M_NFSDSTATE, M_WAITOK);
2457 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2458 	    M_NFSDLOCK, M_WAITOK);
2459 	stp->ls_flags = NFSLCK_UNLOCK;
2460 	lop->lo_flags = NFSLCK_UNLOCK;
2461 	stp->ls_op = nd->nd_rp;
2462 	i = fxdr_unsigned(int, *tl++);
2463 	switch (i) {
2464 	case NFSV4LOCKT_READW:
2465 		stp->ls_flags |= NFSLCK_BLOCKING;
2466 	case NFSV4LOCKT_READ:
2467 		break;
2468 	case NFSV4LOCKT_WRITEW:
2469 		stp->ls_flags |= NFSLCK_BLOCKING;
2470 	case NFSV4LOCKT_WRITE:
2471 		break;
2472 	default:
2473 		nd->nd_repstat = NFSERR_BADXDR;
2474 		free(stp, M_NFSDSTATE);
2475 		free(lop, M_NFSDLOCK);
2476 		goto nfsmout;
2477 	};
2478 	stp->ls_ownerlen = 0;
2479 	stp->ls_uid = nd->nd_cred->cr_uid;
2480 	stp->ls_seq = fxdr_unsigned(int, *tl++);
2481 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2482 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2483 	    NFSX_STATEIDOTHER);
2484 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2485 	lop->lo_first = fxdr_hyper(tl);
2486 	tl += 2;
2487 	len = fxdr_hyper(tl);
2488 	if (len == NFS64BITSSET) {
2489 		lop->lo_end = NFS64BITSSET;
2490 	} else {
2491 		lop->lo_end = lop->lo_first + len;
2492 		if (lop->lo_end <= lop->lo_first)
2493 			nd->nd_repstat = NFSERR_INVAL;
2494 	}
2495 	clientid.lval[0] = stp->ls_stateid.other[0];
2496 	clientid.lval[1] = stp->ls_stateid.other[1];
2497 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2498 		if (nd->nd_clientid.qval != clientid.qval)
2499 			printf("EEK! multiple clids\n");
2500 	} else {
2501 		nd->nd_flag |= ND_IMPLIEDCLID;
2502 		nd->nd_clientid.qval = clientid.qval;
2503 	}
2504 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2505 	    if (vnode_vtype(vp) == VDIR)
2506 		nd->nd_repstat = NFSERR_ISDIR;
2507 	    else
2508 		nd->nd_repstat = NFSERR_INVAL;
2509 	}
2510 	/*
2511 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2512 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
2513 	 * value of nd_repstat, if it gets that far.
2514 	 */
2515 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2516 	    &stateid, exp, nd, p);
2517 	if (stp)
2518 		FREE((caddr_t)stp, M_NFSDSTATE);
2519 	if (lop)
2520 		free((caddr_t)lop, M_NFSDLOCK);
2521 	if (!nd->nd_repstat) {
2522 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2523 		*tl++ = txdr_unsigned(stateid.seqid);
2524 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2525 	}
2526 nfsmout:
2527 	vput(vp);
2528 	NFSEXITCODE2(error, nd);
2529 	return (error);
2530 }
2531 
2532 /*
2533  * nfsv4 open service
2534  */
2535 APPLESTATIC int
2536 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2537     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2538     struct nfsexstuff *exp)
2539 {
2540 	u_int32_t *tl;
2541 	int i;
2542 	struct nfsstate *stp = NULL;
2543 	int error = 0, create, claim, exclusive_flag = 0;
2544 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2545 	int how = NFSCREATE_UNCHECKED;
2546 	int32_t cverf[2], tverf[2] = { 0, 0 };
2547 	vnode_t vp = NULL, dirp = NULL;
2548 	struct nfsvattr nva, dirfor, diraft;
2549 	struct nameidata named;
2550 	nfsv4stateid_t stateid, delegstateid;
2551 	nfsattrbit_t attrbits;
2552 	nfsquad_t clientid;
2553 	char *bufp = NULL;
2554 	u_long *hashp;
2555 	NFSACL_T *aclp = NULL;
2556 
2557 #ifdef NFS4_ACL_EXTATTR_NAME
2558 	aclp = acl_alloc(M_WAITOK);
2559 	aclp->acl_cnt = 0;
2560 #endif
2561 	NFSZERO_ATTRBIT(&attrbits);
2562 	named.ni_startdir = NULL;
2563 	named.ni_cnd.cn_nameiop = 0;
2564 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2565 	i = fxdr_unsigned(int, *(tl + 5));
2566 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2567 		nd->nd_repstat = NFSERR_BADXDR;
2568 		goto nfsmout;
2569 	}
2570 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2571 	    M_NFSDSTATE, M_WAITOK);
2572 	stp->ls_ownerlen = i;
2573 	stp->ls_op = nd->nd_rp;
2574 	stp->ls_flags = NFSLCK_OPEN;
2575 	stp->ls_uid = nd->nd_cred->cr_uid;
2576 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2577 	i = fxdr_unsigned(int, *tl++);
2578 	switch (i) {
2579 	case NFSV4OPEN_ACCESSREAD:
2580 		stp->ls_flags |= NFSLCK_READACCESS;
2581 		break;
2582 	case NFSV4OPEN_ACCESSWRITE:
2583 		stp->ls_flags |= NFSLCK_WRITEACCESS;
2584 		break;
2585 	case NFSV4OPEN_ACCESSBOTH:
2586 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2587 		break;
2588 	default:
2589 		nd->nd_repstat = NFSERR_INVAL;
2590 	};
2591 	i = fxdr_unsigned(int, *tl++);
2592 	switch (i) {
2593 	case NFSV4OPEN_DENYNONE:
2594 		break;
2595 	case NFSV4OPEN_DENYREAD:
2596 		stp->ls_flags |= NFSLCK_READDENY;
2597 		break;
2598 	case NFSV4OPEN_DENYWRITE:
2599 		stp->ls_flags |= NFSLCK_WRITEDENY;
2600 		break;
2601 	case NFSV4OPEN_DENYBOTH:
2602 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2603 		break;
2604 	default:
2605 		nd->nd_repstat = NFSERR_INVAL;
2606 	};
2607 	clientid.lval[0] = *tl++;
2608 	clientid.lval[1] = *tl;
2609 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2610 		if (nd->nd_clientid.qval != clientid.qval)
2611 			printf("EEK! multiple clids\n");
2612 	} else {
2613 		nd->nd_flag |= ND_IMPLIEDCLID;
2614 		nd->nd_clientid.qval = clientid.qval;
2615 	}
2616 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2617 	if (error)
2618 		goto nfsmout;
2619 	NFSVNO_ATTRINIT(&nva);
2620 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2621 	create = fxdr_unsigned(int, *tl);
2622 	if (!nd->nd_repstat)
2623 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2624 	if (create == NFSV4OPEN_CREATE) {
2625 		nva.na_type = VREG;
2626 		nva.na_mode = 0;
2627 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2628 		how = fxdr_unsigned(int, *tl);
2629 		switch (how) {
2630 		case NFSCREATE_UNCHECKED:
2631 		case NFSCREATE_GUARDED:
2632 			error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2633 			if (error)
2634 				goto nfsmout;
2635 			/*
2636 			 * If the na_gid being set is the same as that of
2637 			 * the directory it is going in, clear it, since
2638 			 * that is what will be set by default. This allows
2639 			 * a user that isn't in that group to do the create.
2640 			 */
2641 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2642 			    nva.na_gid == dirfor.na_gid)
2643 				NFSVNO_UNSET(&nva, gid);
2644 			if (!nd->nd_repstat)
2645 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2646 			break;
2647 		case NFSCREATE_EXCLUSIVE:
2648 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2649 			cverf[0] = *tl++;
2650 			cverf[1] = *tl;
2651 			break;
2652 		default:
2653 			nd->nd_repstat = NFSERR_BADXDR;
2654 			goto nfsmout;
2655 		};
2656 	} else if (create != NFSV4OPEN_NOCREATE) {
2657 		nd->nd_repstat = NFSERR_BADXDR;
2658 		goto nfsmout;
2659 	}
2660 
2661 	/*
2662 	 * Now, handle the claim, which usually includes looking up a
2663 	 * name in the directory referenced by dp. The exception is
2664 	 * NFSV4OPEN_CLAIMPREVIOUS.
2665 	 */
2666 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2667 	claim = fxdr_unsigned(int, *tl);
2668 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2669 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2670 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2671 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2672 		stp->ls_flags |= NFSLCK_DELEGCUR;
2673 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2674 		stp->ls_flags |= NFSLCK_DELEGPREV;
2675 	}
2676 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2677 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2678 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2679 		    claim != NFSV4OPEN_CLAIMNULL)
2680 			nd->nd_repstat = NFSERR_INVAL;
2681 		if (nd->nd_repstat) {
2682 			nd->nd_repstat = nfsrv_opencheck(clientid,
2683 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
2684 			goto nfsmout;
2685 		}
2686 		if (create == NFSV4OPEN_CREATE)
2687 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2688 			LOCKPARENT | LOCKLEAF | SAVESTART);
2689 		else
2690 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2691 			LOCKLEAF | SAVESTART);
2692 		nfsvno_setpathbuf(&named, &bufp, &hashp);
2693 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2694 		if (error) {
2695 			vrele(dp);
2696 #ifdef NFS4_ACL_EXTATTR_NAME
2697 			acl_free(aclp);
2698 #endif
2699 			FREE((caddr_t)stp, M_NFSDSTATE);
2700 			nfsvno_relpathbuf(&named);
2701 			NFSEXITCODE2(error, nd);
2702 			return (error);
2703 		}
2704 		if (!nd->nd_repstat) {
2705 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2706 			    p, &dirp);
2707 		} else {
2708 			vrele(dp);
2709 			nfsvno_relpathbuf(&named);
2710 		}
2711 		if (create == NFSV4OPEN_CREATE) {
2712 		    switch (how) {
2713 		    case NFSCREATE_UNCHECKED:
2714 			if (named.ni_vp) {
2715 				/*
2716 				 * Clear the setable attribute bits, except
2717 				 * for Size, if it is being truncated.
2718 				 */
2719 				NFSZERO_ATTRBIT(&attrbits);
2720 				if (NFSVNO_ISSETSIZE(&nva))
2721 					NFSSETBIT_ATTRBIT(&attrbits,
2722 					    NFSATTRBIT_SIZE);
2723 			}
2724 			break;
2725 		    case NFSCREATE_GUARDED:
2726 			if (named.ni_vp && !nd->nd_repstat)
2727 				nd->nd_repstat = EEXIST;
2728 			break;
2729 		    case NFSCREATE_EXCLUSIVE:
2730 			exclusive_flag = 1;
2731 			if (!named.ni_vp)
2732 				nva.na_mode = 0;
2733 		    };
2734 		}
2735 		nfsvno_open(nd, &named, clientid, &stateid, stp,
2736 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2737 		    nd->nd_cred, p, exp, &vp);
2738 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2739 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2740 		i = fxdr_unsigned(int, *tl);
2741 		switch (i) {
2742 		case NFSV4OPEN_DELEGATEREAD:
2743 			stp->ls_flags |= NFSLCK_DELEGREAD;
2744 			break;
2745 		case NFSV4OPEN_DELEGATEWRITE:
2746 			stp->ls_flags |= NFSLCK_DELEGWRITE;
2747 		case NFSV4OPEN_DELEGATENONE:
2748 			break;
2749 		default:
2750 			nd->nd_repstat = NFSERR_BADXDR;
2751 			goto nfsmout;
2752 		};
2753 		stp->ls_flags |= NFSLCK_RECLAIM;
2754 		vp = dp;
2755 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2756 		if ((vp->v_iflag & VI_DOOMED) == 0)
2757 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2758 			    stp, vp, nd, p, nd->nd_repstat);
2759 		else
2760 			nd->nd_repstat = NFSERR_PERM;
2761 	} else {
2762 		nd->nd_repstat = NFSERR_BADXDR;
2763 		goto nfsmout;
2764 	}
2765 
2766 	/*
2767 	 * Do basic access checking.
2768 	 */
2769 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2770 		/*
2771 		 * The IETF working group decided that this is the correct
2772 		 * error return for all non-regular files.
2773 		 */
2774 		nd->nd_repstat = NFSERR_SYMLINK;
2775 	}
2776 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2777 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2778 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2779 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2780 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2781 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2782 	    if (nd->nd_repstat)
2783 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2784 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2785 		    NFSACCCHK_VPISLOCKED, NULL);
2786 	}
2787 
2788 	if (!nd->nd_repstat) {
2789 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2790 		if (!nd->nd_repstat) {
2791 			tverf[0] = nva.na_atime.tv_sec;
2792 			tverf[1] = nva.na_atime.tv_nsec;
2793 		}
2794 	}
2795 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2796 	    cverf[1] != tverf[1]))
2797 		nd->nd_repstat = EEXIST;
2798 	/*
2799 	 * Do the open locking/delegation stuff.
2800 	 */
2801 	if (!nd->nd_repstat)
2802 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2803 		&delegstateid, &rflags, exp, p, nva.na_filerev);
2804 
2805 	/*
2806 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2807 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2808 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
2809 	 */
2810 	if (vp)
2811 		NFSVOPUNLOCK(vp, 0);
2812 	if (stp)
2813 		FREE((caddr_t)stp, M_NFSDSTATE);
2814 	if (!nd->nd_repstat && dirp)
2815 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2816 		    0);
2817 	if (!nd->nd_repstat) {
2818 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2819 		*tl++ = txdr_unsigned(stateid.seqid);
2820 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2821 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2822 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2823 			*tl++ = newnfs_true;
2824 			*tl++ = 0;
2825 			*tl++ = 0;
2826 			*tl++ = 0;
2827 			*tl++ = 0;
2828 		} else {
2829 			*tl++ = newnfs_false;	/* Since dirp is not locked */
2830 			txdr_hyper(dirfor.na_filerev, tl);
2831 			tl += 2;
2832 			txdr_hyper(diraft.na_filerev, tl);
2833 			tl += 2;
2834 		}
2835 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2836 		(void) nfsrv_putattrbit(nd, &attrbits);
2837 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2838 		if (rflags & NFSV4OPEN_READDELEGATE)
2839 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2840 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2841 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2842 		else
2843 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2844 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2845 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2846 			*tl++ = txdr_unsigned(delegstateid.seqid);
2847 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2848 			    NFSX_STATEIDOTHER);
2849 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2850 			if (rflags & NFSV4OPEN_RECALL)
2851 				*tl = newnfs_true;
2852 			else
2853 				*tl = newnfs_false;
2854 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2855 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2856 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2857 				txdr_hyper(nva.na_size, tl);
2858 			}
2859 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2860 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2861 			*tl++ = txdr_unsigned(0x0);
2862 			acemask = NFSV4ACE_ALLFILESMASK;
2863 			if (nva.na_mode & S_IRUSR)
2864 			    acemask |= NFSV4ACE_READMASK;
2865 			if (nva.na_mode & S_IWUSR)
2866 			    acemask |= NFSV4ACE_WRITEMASK;
2867 			if (nva.na_mode & S_IXUSR)
2868 			    acemask |= NFSV4ACE_EXECUTEMASK;
2869 			*tl = txdr_unsigned(acemask);
2870 			(void) nfsm_strtom(nd, "OWNER@", 6);
2871 		}
2872 		*vpp = vp;
2873 	} else if (vp) {
2874 		vrele(vp);
2875 	}
2876 	if (dirp)
2877 		vrele(dirp);
2878 #ifdef NFS4_ACL_EXTATTR_NAME
2879 	acl_free(aclp);
2880 #endif
2881 	NFSEXITCODE2(0, nd);
2882 	return (0);
2883 nfsmout:
2884 	vrele(dp);
2885 #ifdef NFS4_ACL_EXTATTR_NAME
2886 	acl_free(aclp);
2887 #endif
2888 	if (stp)
2889 		FREE((caddr_t)stp, M_NFSDSTATE);
2890 	NFSEXITCODE2(error, nd);
2891 	return (error);
2892 }
2893 
2894 /*
2895  * nfsv4 close service
2896  */
2897 APPLESTATIC int
2898 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2899     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2900 {
2901 	u_int32_t *tl;
2902 	struct nfsstate st, *stp = &st;
2903 	int error = 0;
2904 	nfsv4stateid_t stateid;
2905 	nfsquad_t clientid;
2906 
2907 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2908 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2909 	stp->ls_ownerlen = 0;
2910 	stp->ls_op = nd->nd_rp;
2911 	stp->ls_uid = nd->nd_cred->cr_uid;
2912 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2913 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2914 	    NFSX_STATEIDOTHER);
2915 	stp->ls_flags = NFSLCK_CLOSE;
2916 	clientid.lval[0] = stp->ls_stateid.other[0];
2917 	clientid.lval[1] = stp->ls_stateid.other[1];
2918 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2919 		if (nd->nd_clientid.qval != clientid.qval)
2920 			printf("EEK! multiple clids\n");
2921 	} else {
2922 		nd->nd_flag |= ND_IMPLIEDCLID;
2923 		nd->nd_clientid.qval = clientid.qval;
2924 	}
2925 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2926 	vput(vp);
2927 	if (!nd->nd_repstat) {
2928 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2929 		*tl++ = txdr_unsigned(stateid.seqid);
2930 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2931 	}
2932 	NFSEXITCODE2(0, nd);
2933 	return (0);
2934 nfsmout:
2935 	vput(vp);
2936 	NFSEXITCODE2(error, nd);
2937 	return (error);
2938 }
2939 
2940 /*
2941  * nfsv4 delegpurge service
2942  */
2943 APPLESTATIC int
2944 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2945     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2946 {
2947 	u_int32_t *tl;
2948 	int error = 0;
2949 	nfsquad_t clientid;
2950 
2951 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2952 		nd->nd_repstat = NFSERR_WRONGSEC;
2953 		goto nfsmout;
2954 	}
2955 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2956 	clientid.lval[0] = *tl++;
2957 	clientid.lval[1] = *tl;
2958 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2959 		if (nd->nd_clientid.qval != clientid.qval)
2960 			printf("EEK! multiple clids\n");
2961 	} else {
2962 		nd->nd_flag |= ND_IMPLIEDCLID;
2963 		nd->nd_clientid.qval = clientid.qval;
2964 	}
2965 	nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2966 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2967 nfsmout:
2968 	NFSEXITCODE2(error, nd);
2969 	return (error);
2970 }
2971 
2972 /*
2973  * nfsv4 delegreturn service
2974  */
2975 APPLESTATIC int
2976 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2977     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2978 {
2979 	u_int32_t *tl;
2980 	int error = 0;
2981 	nfsv4stateid_t stateid;
2982 	nfsquad_t clientid;
2983 
2984 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2985 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2986 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2987 	clientid.lval[0] = stateid.other[0];
2988 	clientid.lval[1] = stateid.other[1];
2989 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2990 		if (nd->nd_clientid.qval != clientid.qval)
2991 			printf("EEK! multiple clids\n");
2992 	} else {
2993 		nd->nd_flag |= ND_IMPLIEDCLID;
2994 		nd->nd_clientid.qval = clientid.qval;
2995 	}
2996 	nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2997 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2998 nfsmout:
2999 	vput(vp);
3000 	NFSEXITCODE2(error, nd);
3001 	return (error);
3002 }
3003 
3004 /*
3005  * nfsv4 get file handle service
3006  */
3007 APPLESTATIC int
3008 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3009     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3010 {
3011 	fhandle_t fh;
3012 
3013 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3014 	vput(vp);
3015 	if (!nd->nd_repstat)
3016 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3017 	NFSEXITCODE2(0, nd);
3018 	return (0);
3019 }
3020 
3021 /*
3022  * nfsv4 open confirm service
3023  */
3024 APPLESTATIC int
3025 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3026     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3027 {
3028 	u_int32_t *tl;
3029 	struct nfsstate st, *stp = &st;
3030 	int error = 0;
3031 	nfsv4stateid_t stateid;
3032 	nfsquad_t clientid;
3033 
3034 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3035 	stp->ls_ownerlen = 0;
3036 	stp->ls_op = nd->nd_rp;
3037 	stp->ls_uid = nd->nd_cred->cr_uid;
3038 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3039 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3040 	    NFSX_STATEIDOTHER);
3041 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3042 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3043 	stp->ls_flags = NFSLCK_CONFIRM;
3044 	clientid.lval[0] = stp->ls_stateid.other[0];
3045 	clientid.lval[1] = stp->ls_stateid.other[1];
3046 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3047 		if (nd->nd_clientid.qval != clientid.qval)
3048 			printf("EEK! multiple clids\n");
3049 	} else {
3050 		nd->nd_flag |= ND_IMPLIEDCLID;
3051 		nd->nd_clientid.qval = clientid.qval;
3052 	}
3053 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3054 	if (!nd->nd_repstat) {
3055 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3056 		*tl++ = txdr_unsigned(stateid.seqid);
3057 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3058 	}
3059 nfsmout:
3060 	vput(vp);
3061 	NFSEXITCODE2(error, nd);
3062 	return (error);
3063 }
3064 
3065 /*
3066  * nfsv4 open downgrade service
3067  */
3068 APPLESTATIC int
3069 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3070     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3071 {
3072 	u_int32_t *tl;
3073 	int i;
3074 	struct nfsstate st, *stp = &st;
3075 	int error = 0;
3076 	nfsv4stateid_t stateid;
3077 	nfsquad_t clientid;
3078 
3079 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3080 	stp->ls_ownerlen = 0;
3081 	stp->ls_op = nd->nd_rp;
3082 	stp->ls_uid = nd->nd_cred->cr_uid;
3083 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3084 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3085 	    NFSX_STATEIDOTHER);
3086 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3087 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3088 	i = fxdr_unsigned(int, *tl++);
3089 	switch (i) {
3090 	case NFSV4OPEN_ACCESSREAD:
3091 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3092 		break;
3093 	case NFSV4OPEN_ACCESSWRITE:
3094 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3095 		break;
3096 	case NFSV4OPEN_ACCESSBOTH:
3097 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3098 		    NFSLCK_DOWNGRADE);
3099 		break;
3100 	default:
3101 		nd->nd_repstat = NFSERR_BADXDR;
3102 	};
3103 	i = fxdr_unsigned(int, *tl);
3104 	switch (i) {
3105 	case NFSV4OPEN_DENYNONE:
3106 		break;
3107 	case NFSV4OPEN_DENYREAD:
3108 		stp->ls_flags |= NFSLCK_READDENY;
3109 		break;
3110 	case NFSV4OPEN_DENYWRITE:
3111 		stp->ls_flags |= NFSLCK_WRITEDENY;
3112 		break;
3113 	case NFSV4OPEN_DENYBOTH:
3114 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3115 		break;
3116 	default:
3117 		nd->nd_repstat = NFSERR_BADXDR;
3118 	};
3119 
3120 	clientid.lval[0] = stp->ls_stateid.other[0];
3121 	clientid.lval[1] = stp->ls_stateid.other[1];
3122 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3123 		if (nd->nd_clientid.qval != clientid.qval)
3124 			printf("EEK! multiple clids\n");
3125 	} else {
3126 		nd->nd_flag |= ND_IMPLIEDCLID;
3127 		nd->nd_clientid.qval = clientid.qval;
3128 	}
3129 	if (!nd->nd_repstat)
3130 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3131 		    nd, p);
3132 	if (!nd->nd_repstat) {
3133 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3134 		*tl++ = txdr_unsigned(stateid.seqid);
3135 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3136 	}
3137 nfsmout:
3138 	vput(vp);
3139 	NFSEXITCODE2(error, nd);
3140 	return (error);
3141 }
3142 
3143 /*
3144  * nfsv4 renew lease service
3145  */
3146 APPLESTATIC int
3147 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3148     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3149 {
3150 	u_int32_t *tl;
3151 	int error = 0;
3152 	nfsquad_t clientid;
3153 
3154 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3155 		nd->nd_repstat = NFSERR_WRONGSEC;
3156 		goto nfsmout;
3157 	}
3158 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3159 	clientid.lval[0] = *tl++;
3160 	clientid.lval[1] = *tl;
3161 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3162 		if (nd->nd_clientid.qval != clientid.qval)
3163 			printf("EEK! multiple clids\n");
3164 	} else {
3165 		nd->nd_flag |= ND_IMPLIEDCLID;
3166 		nd->nd_clientid.qval = clientid.qval;
3167 	}
3168 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3169 	    NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3170 nfsmout:
3171 	NFSEXITCODE2(error, nd);
3172 	return (error);
3173 }
3174 
3175 /*
3176  * nfsv4 security info service
3177  */
3178 APPLESTATIC int
3179 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3180     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3181 {
3182 	u_int32_t *tl;
3183 	int len;
3184 	struct nameidata named;
3185 	vnode_t dirp = NULL, vp;
3186 	struct nfsrvfh fh;
3187 	struct nfsexstuff retnes;
3188 	u_int32_t *sizp;
3189 	int error = 0, savflag, i;
3190 	char *bufp;
3191 	u_long *hashp;
3192 
3193 	/*
3194 	 * All this just to get the export flags for the name.
3195 	 */
3196 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3197 	    LOCKLEAF | SAVESTART);
3198 	nfsvno_setpathbuf(&named, &bufp, &hashp);
3199 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3200 	if (error) {
3201 		vput(dp);
3202 		nfsvno_relpathbuf(&named);
3203 		goto out;
3204 	}
3205 	if (!nd->nd_repstat) {
3206 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3207 	} else {
3208 		vput(dp);
3209 		nfsvno_relpathbuf(&named);
3210 	}
3211 	if (dirp)
3212 		vrele(dirp);
3213 	if (nd->nd_repstat)
3214 		goto out;
3215 	vrele(named.ni_startdir);
3216 	nfsvno_relpathbuf(&named);
3217 	fh.nfsrvfh_len = NFSX_MYFH;
3218 	vp = named.ni_vp;
3219 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3220 	vput(vp);
3221 	savflag = nd->nd_flag;
3222 	if (!nd->nd_repstat) {
3223 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3224 		if (vp)
3225 			vput(vp);
3226 	}
3227 	nd->nd_flag = savflag;
3228 	if (nd->nd_repstat)
3229 		goto out;
3230 
3231 	/*
3232 	 * Finally have the export flags for name, so we can create
3233 	 * the security info.
3234 	 */
3235 	len = 0;
3236 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3237 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
3238 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
3239 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3240 			*tl = txdr_unsigned(RPCAUTH_UNIX);
3241 			len++;
3242 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3243 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3244 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3245 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3246 			    nfsgss_mechlist[KERBV_MECH].len);
3247 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3248 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3249 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3250 			len++;
3251 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3252 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3253 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3254 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3255 			    nfsgss_mechlist[KERBV_MECH].len);
3256 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3257 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3258 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3259 			len++;
3260 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3261 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3262 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3263 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3264 			    nfsgss_mechlist[KERBV_MECH].len);
3265 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3266 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3267 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3268 			len++;
3269 		}
3270 	}
3271 	*sizp = txdr_unsigned(len);
3272 
3273 out:
3274 	NFSEXITCODE2(error, nd);
3275 	return (error);
3276 }
3277 
3278 /*
3279  * nfsv4 set client id service
3280  */
3281 APPLESTATIC int
3282 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3283     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3284 {
3285 	u_int32_t *tl;
3286 	int i;
3287 	int error = 0, idlen;
3288 	struct nfsclient *clp = NULL;
3289 	struct sockaddr_in *rad;
3290 	u_char *verf, *ucp, *ucp2, addrbuf[24];
3291 	nfsquad_t clientid, confirm;
3292 
3293 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3294 		nd->nd_repstat = NFSERR_WRONGSEC;
3295 		goto out;
3296 	}
3297 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3298 	verf = (u_char *)tl;
3299 	tl += (NFSX_VERF / NFSX_UNSIGNED);
3300 	i = fxdr_unsigned(int, *tl);
3301 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3302 		nd->nd_repstat = NFSERR_BADXDR;
3303 		goto nfsmout;
3304 	}
3305 	idlen = i;
3306 	if (nd->nd_flag & ND_GSS)
3307 		i += nd->nd_princlen;
3308 	MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3309 	    M_NFSDCLIENT, M_WAITOK);
3310 	NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3311 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3312 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3313 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3314 	clp->lc_req.nr_cred = NULL;
3315 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3316 	clp->lc_idlen = idlen;
3317 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3318 	if (error)
3319 		goto nfsmout;
3320 	if (nd->nd_flag & ND_GSS) {
3321 		clp->lc_flags = LCL_GSS;
3322 		if (nd->nd_flag & ND_GSSINTEGRITY)
3323 			clp->lc_flags |= LCL_GSSINTEGRITY;
3324 		else if (nd->nd_flag & ND_GSSPRIVACY)
3325 			clp->lc_flags |= LCL_GSSPRIVACY;
3326 	} else {
3327 		clp->lc_flags = 0;
3328 	}
3329 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3330 		clp->lc_flags |= LCL_NAME;
3331 		clp->lc_namelen = nd->nd_princlen;
3332 		clp->lc_name = &clp->lc_id[idlen];
3333 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3334 	} else {
3335 		clp->lc_uid = nd->nd_cred->cr_uid;
3336 		clp->lc_gid = nd->nd_cred->cr_gid;
3337 	}
3338 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3339 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3340 	error = nfsrv_getclientipaddr(nd, clp);
3341 	if (error)
3342 		goto nfsmout;
3343 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3344 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3345 
3346 	/*
3347 	 * nfsrv_setclient() does the actual work of adding it to the
3348 	 * client list. If there is no error, the structure has been
3349 	 * linked into the client list and clp should no longer be used
3350 	 * here. When an error is returned, it has not been linked in,
3351 	 * so it should be free'd.
3352 	 */
3353 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3354 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3355 		if (clp->lc_flags & LCL_TCPCALLBACK)
3356 			(void) nfsm_strtom(nd, "tcp", 3);
3357 		else
3358 			(void) nfsm_strtom(nd, "udp", 3);
3359 		rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3360 		ucp = (u_char *)&rad->sin_addr.s_addr;
3361 		ucp2 = (u_char *)&rad->sin_port;
3362 		sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3363 		    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3364 		    ucp2[0] & 0xff, ucp2[1] & 0xff);
3365 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3366 	}
3367 	if (clp) {
3368 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3369 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3370 		free((caddr_t)clp, M_NFSDCLIENT);
3371 	}
3372 	if (!nd->nd_repstat) {
3373 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3374 		*tl++ = clientid.lval[0];
3375 		*tl++ = clientid.lval[1];
3376 		*tl++ = confirm.lval[0];
3377 		*tl = confirm.lval[1];
3378 	}
3379 
3380 out:
3381 	NFSEXITCODE2(0, nd);
3382 	return (0);
3383 nfsmout:
3384 	if (clp) {
3385 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3386 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3387 		free((caddr_t)clp, M_NFSDCLIENT);
3388 	}
3389 	NFSEXITCODE2(error, nd);
3390 	return (error);
3391 }
3392 
3393 /*
3394  * nfsv4 set client id confirm service
3395  */
3396 APPLESTATIC int
3397 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3398     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3399     __unused struct nfsexstuff *exp)
3400 {
3401 	u_int32_t *tl;
3402 	int error = 0;
3403 	nfsquad_t clientid, confirm;
3404 
3405 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3406 		nd->nd_repstat = NFSERR_WRONGSEC;
3407 		goto nfsmout;
3408 	}
3409 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3410 	clientid.lval[0] = *tl++;
3411 	clientid.lval[1] = *tl++;
3412 	confirm.lval[0] = *tl++;
3413 	confirm.lval[1] = *tl;
3414 
3415 	/*
3416 	 * nfsrv_getclient() searches the client list for a match and
3417 	 * returns the appropriate NFSERR status.
3418 	 */
3419 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3420 	    NULL, confirm, nd, p);
3421 nfsmout:
3422 	NFSEXITCODE2(error, nd);
3423 	return (error);
3424 }
3425 
3426 /*
3427  * nfsv4 verify service
3428  */
3429 APPLESTATIC int
3430 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3431     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3432 {
3433 	int error = 0, ret, fhsize = NFSX_MYFH;
3434 	struct nfsvattr nva;
3435 	struct statfs sf;
3436 	struct nfsfsinfo fs;
3437 	fhandle_t fh;
3438 
3439 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3440 	if (!nd->nd_repstat)
3441 		nd->nd_repstat = nfsvno_statfs(vp, &sf);
3442 	if (!nd->nd_repstat)
3443 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3444 	if (!nd->nd_repstat) {
3445 		nfsvno_getfs(&fs, isdgram);
3446 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3447 		    &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3448 		if (!error) {
3449 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3450 				if (ret == 0)
3451 					nd->nd_repstat = NFSERR_SAME;
3452 				else if (ret != NFSERR_NOTSAME)
3453 					nd->nd_repstat = ret;
3454 			} else if (ret)
3455 				nd->nd_repstat = ret;
3456 		}
3457 	}
3458 	vput(vp);
3459 	NFSEXITCODE2(error, nd);
3460 	return (error);
3461 }
3462 
3463 /*
3464  * nfs openattr rpc
3465  */
3466 APPLESTATIC int
3467 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3468     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3469     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3470 {
3471 	u_int32_t *tl;
3472 	int error = 0, createdir;
3473 
3474 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3475 	createdir = fxdr_unsigned(int, *tl);
3476 	nd->nd_repstat = NFSERR_NOTSUPP;
3477 nfsmout:
3478 	vrele(dp);
3479 	NFSEXITCODE2(error, nd);
3480 	return (error);
3481 }
3482 
3483 /*
3484  * nfsv4 release lock owner service
3485  */
3486 APPLESTATIC int
3487 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3488     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3489 {
3490 	u_int32_t *tl;
3491 	struct nfsstate *stp = NULL;
3492 	int error = 0, len;
3493 	nfsquad_t clientid;
3494 
3495 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3496 		nd->nd_repstat = NFSERR_WRONGSEC;
3497 		goto nfsmout;
3498 	}
3499 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3500 	len = fxdr_unsigned(int, *(tl + 2));
3501 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3502 		nd->nd_repstat = NFSERR_BADXDR;
3503 		goto nfsmout;
3504 	}
3505 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3506 	    M_NFSDSTATE, M_WAITOK);
3507 	stp->ls_ownerlen = len;
3508 	stp->ls_op = NULL;
3509 	stp->ls_flags = NFSLCK_RELEASE;
3510 	stp->ls_uid = nd->nd_cred->cr_uid;
3511 	clientid.lval[0] = *tl++;
3512 	clientid.lval[1] = *tl;
3513 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3514 		if (nd->nd_clientid.qval != clientid.qval)
3515 			printf("EEK! multiple clids\n");
3516 	} else {
3517 		nd->nd_flag |= ND_IMPLIEDCLID;
3518 		nd->nd_clientid.qval = clientid.qval;
3519 	}
3520 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
3521 	if (error)
3522 		goto nfsmout;
3523 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3524 	FREE((caddr_t)stp, M_NFSDSTATE);
3525 
3526 	NFSEXITCODE2(0, nd);
3527 	return (0);
3528 nfsmout:
3529 	if (stp)
3530 		free((caddr_t)stp, M_NFSDSTATE);
3531 	NFSEXITCODE2(error, nd);
3532 	return (error);
3533 }
3534