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