xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision 4ed925457ab06e83238a5db33e89ccc94b99a713)
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;
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, LOCKPARENT);
1553 	if (!nd->nd_repstat) {
1554 		nfsvno_setpathbuf(&named, &bufp, &hashp);
1555 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1556 		if (error) {
1557 			vrele(vp);
1558 			if (dp) {
1559 				if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1560 				    !(nd->nd_flag & ND_NFSV4))
1561 					nfsvno_unlockvfs(mp);
1562 				vrele(dp);
1563 			}
1564 			nfsvno_relpathbuf(&named);
1565 			return (error);
1566 		}
1567 		if (!nd->nd_repstat) {
1568 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1569 			    p, &dirp);
1570 		} else {
1571 			if (dp)
1572 				vrele(dp);
1573 			nfsvno_relpathbuf(&named);
1574 		}
1575 	}
1576 	if (dirp) {
1577 		if (nd->nd_flag & ND_NFSV2) {
1578 			vrele(dirp);
1579 			dirp = NULL;
1580 		} else {
1581 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1582 			    nd->nd_cred, p);
1583 		}
1584 	}
1585 	if (!nd->nd_repstat)
1586 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1587 	if (nd->nd_flag & ND_NFSV3)
1588 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1589 	if (dirp) {
1590 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
1591 		vrele(dirp);
1592 	}
1593 	if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1594 	    !(nd->nd_flag & ND_NFSV4))
1595 		nfsvno_unlockvfs(mp);
1596 	vrele(vp);
1597 	if (nd->nd_flag & ND_NFSV3) {
1598 		nfsrv_postopattr(nd, getret, &at);
1599 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1600 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1601 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1602 		*tl++ = newnfs_false;
1603 		txdr_hyper(dirfor.na_filerev, tl);
1604 		tl += 2;
1605 		txdr_hyper(diraft.na_filerev, tl);
1606 	}
1607 	return (0);
1608 }
1609 
1610 /*
1611  * nfs symbolic link service
1612  */
1613 APPLESTATIC int
1614 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1615     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1616     struct nfsexstuff *exp)
1617 {
1618 	struct nfsvattr nva, dirfor, diraft;
1619 	struct nameidata named;
1620 	int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1621 	vnode_t dirp = NULL;
1622 	char *bufp, *pathcp = NULL;
1623 	u_long *hashp;
1624 
1625 	if (nd->nd_repstat) {
1626 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1627 		return (0);
1628 	}
1629 	if (vpp)
1630 		*vpp = NULL;
1631 	NFSVNO_ATTRINIT(&nva);
1632 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1633 	    LOCKPARENT | SAVESTART);
1634 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1635 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1636 	if (!error && !nd->nd_repstat)
1637 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1638 	if (error) {
1639 		vrele(dp);
1640 		nfsvno_relpathbuf(&named);
1641 		return (error);
1642 	}
1643 	if (!nd->nd_repstat) {
1644 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1645 	} else {
1646 		vrele(dp);
1647 		nfsvno_relpathbuf(&named);
1648 	}
1649 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1650 		vrele(dirp);
1651 		dirp = NULL;
1652 	}
1653 
1654 	/*
1655 	 * And call nfsrvd_symlinksub() to do the common code. It will
1656 	 * return EBADRPC upon a parsing error, 0 otherwise.
1657 	 */
1658 	if (!nd->nd_repstat) {
1659 		if (dirp != NULL)
1660 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1661 			    p);
1662 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1663 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1664 		    pathcp, pathlen);
1665 	} else if (dirp != NULL) {
1666 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p);
1667 		vrele(dirp);
1668 	}
1669 	if (pathcp)
1670 		FREE(pathcp, M_TEMP);
1671 
1672 	if (nd->nd_flag & ND_NFSV3) {
1673 		if (!nd->nd_repstat) {
1674 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1675 			nfsrv_postopattr(nd, 0, &nva);
1676 		}
1677 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1678 	}
1679 	return (0);
1680 }
1681 
1682 /*
1683  * Common code for creating a symbolic link.
1684  */
1685 static void
1686 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1687     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1688     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1689     int *diraft_retp, nfsattrbit_t *attrbitp,
1690     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1691     int pathlen)
1692 {
1693 	u_int32_t *tl;
1694 
1695 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1696 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1697 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1698 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1699 		if (nd->nd_flag & ND_NFSV3) {
1700 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1701 			if (!nd->nd_repstat)
1702 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1703 				    nvap, nd->nd_cred, p);
1704 		}
1705 		if (vpp) {
1706 			NFSVOPUNLOCK(ndp->ni_vp, 0, p);
1707 			*vpp = ndp->ni_vp;
1708 		} else {
1709 			vput(ndp->ni_vp);
1710 		}
1711 	}
1712 	if (dirp) {
1713 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p);
1714 		vrele(dirp);
1715 	}
1716 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1717 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1718 		*tl++ = newnfs_false;
1719 		txdr_hyper(dirforp->na_filerev, tl);
1720 		tl += 2;
1721 		txdr_hyper(diraftp->na_filerev, tl);
1722 		(void) nfsrv_putattrbit(nd, attrbitp);
1723 	}
1724 }
1725 
1726 /*
1727  * nfs mkdir service
1728  */
1729 APPLESTATIC int
1730 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1731     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1732     struct nfsexstuff *exp)
1733 {
1734 	struct nfsvattr nva, dirfor, diraft;
1735 	struct nameidata named;
1736 	u_int32_t *tl;
1737 	int error, dirfor_ret = 1, diraft_ret = 1;
1738 	vnode_t dirp = NULL;
1739 	char *bufp;
1740 	u_long *hashp;
1741 
1742 	if (nd->nd_repstat) {
1743 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1744 		return (0);
1745 	}
1746 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT);
1747 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1748 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1749 	if (error) {
1750 		vrele(dp);
1751 		nfsvno_relpathbuf(&named);
1752 		return (error);
1753 	}
1754 	if (!nd->nd_repstat) {
1755 		NFSVNO_ATTRINIT(&nva);
1756 		if (nd->nd_flag & ND_NFSV3) {
1757 			error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1758 			if (error) {
1759 				vrele(dp);
1760 				nfsvno_relpathbuf(&named);
1761 				return (error);
1762 			}
1763 		} else {
1764 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1765 			nva.na_mode = nfstov_mode(*tl++);
1766 		}
1767 	}
1768 	if (!nd->nd_repstat) {
1769 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1770 	} else {
1771 		vrele(dp);
1772 		nfsvno_relpathbuf(&named);
1773 	}
1774 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1775 		vrele(dirp);
1776 		dirp = NULL;
1777 	}
1778 	if (nd->nd_repstat) {
1779 		if (dirp != NULL) {
1780 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1781 			    p);
1782 			vrele(dirp);
1783 		}
1784 		if (nd->nd_flag & ND_NFSV3)
1785 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1786 			    &diraft);
1787 		return (0);
1788 	}
1789 	if (dirp != NULL)
1790 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p);
1791 
1792 	/*
1793 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1794 	 */
1795 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1796 	    &diraft_ret, NULL, NULL, p, exp);
1797 
1798 	if (nd->nd_flag & ND_NFSV3) {
1799 		if (!nd->nd_repstat) {
1800 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1801 			nfsrv_postopattr(nd, 0, &nva);
1802 		}
1803 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1804 	} else if (!nd->nd_repstat) {
1805 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1806 		nfsrv_fillattr(nd, &nva);
1807 	}
1808 	return (0);
1809 nfsmout:
1810 	vrele(dp);
1811 	nfsvno_relpathbuf(&named);
1812 	return (error);
1813 }
1814 
1815 /*
1816  * Code common to mkdir for V2,3 and 4.
1817  */
1818 static void
1819 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1820     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1821     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1822     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1823     NFSPROC_T *p, struct nfsexstuff *exp)
1824 {
1825 	vnode_t vp;
1826 	u_int32_t *tl;
1827 
1828 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
1829 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1830 	    nd->nd_cred, p, exp);
1831 	if (!nd->nd_repstat) {
1832 		vp = ndp->ni_vp;
1833 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1834 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1835 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1836 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1837 			    p);
1838 		if (vpp && !nd->nd_repstat) {
1839 			NFSVOPUNLOCK(vp, 0, p);
1840 			*vpp = vp;
1841 		} else {
1842 			vput(vp);
1843 		}
1844 	}
1845 	if (dirp) {
1846 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p);
1847 		vrele(dirp);
1848 	}
1849 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1850 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1851 		*tl++ = newnfs_false;
1852 		txdr_hyper(dirforp->na_filerev, tl);
1853 		tl += 2;
1854 		txdr_hyper(diraftp->na_filerev, tl);
1855 		(void) nfsrv_putattrbit(nd, attrbitp);
1856 	}
1857 }
1858 
1859 /*
1860  * nfs commit service
1861  */
1862 APPLESTATIC int
1863 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1864     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1865 {
1866 	struct nfsvattr bfor, aft;
1867 	u_int32_t *tl;
1868 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
1869 	u_int64_t off;
1870 
1871 	if (nd->nd_repstat) {
1872 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1873 		return (0);
1874 	}
1875 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1876 	/*
1877 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
1878 	 * count parameters, so these arguments are useless (someday maybe).
1879 	 */
1880 	off = fxdr_hyper(tl);
1881 	tl += 2;
1882 	cnt = fxdr_unsigned(int, *tl);
1883 	if (nd->nd_flag & ND_NFSV3)
1884 		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p);
1885 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1886 	if (nd->nd_flag & ND_NFSV3) {
1887 		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p);
1888 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1889 	}
1890 	vput(vp);
1891 	if (!nd->nd_repstat) {
1892 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1893 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
1894 		*tl = txdr_unsigned(nfsboottime.tv_usec);
1895 	}
1896 	return (0);
1897 nfsmout:
1898 	vput(vp);
1899 	return (error);
1900 }
1901 
1902 /*
1903  * nfs statfs service
1904  */
1905 APPLESTATIC int
1906 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1907     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1908 {
1909 	struct statfs *sf;
1910 	u_int32_t *tl;
1911 	int getret = 1;
1912 	struct nfsvattr at;
1913 	struct statfs sfs;
1914 	u_quad_t tval;
1915 
1916 	if (nd->nd_repstat) {
1917 		nfsrv_postopattr(nd, getret, &at);
1918 		return (0);
1919 	}
1920 	sf = &sfs;
1921 	nd->nd_repstat = nfsvno_statfs(vp, sf);
1922 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1923 	vput(vp);
1924 	if (nd->nd_flag & ND_NFSV3)
1925 		nfsrv_postopattr(nd, getret, &at);
1926 	if (nd->nd_repstat)
1927 		return (0);
1928 	if (nd->nd_flag & ND_NFSV2) {
1929 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1930 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
1931 		*tl++ = txdr_unsigned(sf->f_bsize);
1932 		*tl++ = txdr_unsigned(sf->f_blocks);
1933 		*tl++ = txdr_unsigned(sf->f_bfree);
1934 		*tl = txdr_unsigned(sf->f_bavail);
1935 	} else {
1936 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1937 		tval = (u_quad_t)sf->f_blocks;
1938 		tval *= (u_quad_t)sf->f_bsize;
1939 		txdr_hyper(tval, tl); tl += 2;
1940 		tval = (u_quad_t)sf->f_bfree;
1941 		tval *= (u_quad_t)sf->f_bsize;
1942 		txdr_hyper(tval, tl); tl += 2;
1943 		tval = (u_quad_t)sf->f_bavail;
1944 		tval *= (u_quad_t)sf->f_bsize;
1945 		txdr_hyper(tval, tl); tl += 2;
1946 		tval = (u_quad_t)sf->f_files;
1947 		txdr_hyper(tval, tl); tl += 2;
1948 		tval = (u_quad_t)sf->f_ffree;
1949 		txdr_hyper(tval, tl); tl += 2;
1950 		tval = (u_quad_t)sf->f_ffree;
1951 		txdr_hyper(tval, tl); tl += 2;
1952 		*tl = 0;
1953 	}
1954 	return (0);
1955 }
1956 
1957 /*
1958  * nfs fsinfo service
1959  */
1960 APPLESTATIC int
1961 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1962     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1963 {
1964 	u_int32_t *tl;
1965 	struct nfsfsinfo fs;
1966 	int getret = 1;
1967 	struct nfsvattr at;
1968 
1969 	if (nd->nd_repstat) {
1970 		nfsrv_postopattr(nd, getret, &at);
1971 		return (0);
1972 	}
1973 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1974 	nfsvno_getfs(&fs, isdgram);
1975 	vput(vp);
1976 	nfsrv_postopattr(nd, getret, &at);
1977 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1978 	*tl++ = txdr_unsigned(fs.fs_rtmax);
1979 	*tl++ = txdr_unsigned(fs.fs_rtpref);
1980 	*tl++ = txdr_unsigned(fs.fs_rtmult);
1981 	*tl++ = txdr_unsigned(fs.fs_wtmax);
1982 	*tl++ = txdr_unsigned(fs.fs_wtpref);
1983 	*tl++ = txdr_unsigned(fs.fs_wtmult);
1984 	*tl++ = txdr_unsigned(fs.fs_dtpref);
1985 	txdr_hyper(fs.fs_maxfilesize, tl);
1986 	tl += 2;
1987 	txdr_nfsv3time(&fs.fs_timedelta, tl);
1988 	tl += 2;
1989 	*tl = txdr_unsigned(fs.fs_properties);
1990 	return (0);
1991 }
1992 
1993 /*
1994  * nfs pathconf service
1995  */
1996 APPLESTATIC int
1997 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
1998     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1999 {
2000 	struct nfsv3_pathconf *pc;
2001 	int getret = 1;
2002 	register_t linkmax, namemax, chownres, notrunc;
2003 	struct nfsvattr at;
2004 
2005 	if (nd->nd_repstat) {
2006 		nfsrv_postopattr(nd, getret, &at);
2007 		return (0);
2008 	}
2009 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2010 	    nd->nd_cred, p);
2011 	if (!nd->nd_repstat)
2012 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2013 		    nd->nd_cred, p);
2014 	if (!nd->nd_repstat)
2015 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2016 		    &chownres, nd->nd_cred, p);
2017 	if (!nd->nd_repstat)
2018 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2019 		    nd->nd_cred, p);
2020 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
2021 	vput(vp);
2022 	nfsrv_postopattr(nd, getret, &at);
2023 	if (!nd->nd_repstat) {
2024 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2025 		pc->pc_linkmax = txdr_unsigned(linkmax);
2026 		pc->pc_namemax = txdr_unsigned(namemax);
2027 		pc->pc_notrunc = txdr_unsigned(notrunc);
2028 		pc->pc_chownrestricted = txdr_unsigned(chownres);
2029 
2030 		/*
2031 		 * These should probably be supported by VOP_PATHCONF(), but
2032 		 * until msdosfs is exportable (why would you want to?), the
2033 		 * Unix defaults should be ok.
2034 		 */
2035 		pc->pc_caseinsensitive = newnfs_false;
2036 		pc->pc_casepreserving = newnfs_true;
2037 	}
2038 	return (0);
2039 }
2040 
2041 /*
2042  * nfsv4 lock service
2043  */
2044 APPLESTATIC int
2045 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2046     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2047 {
2048 	u_int32_t *tl;
2049 	int i;
2050 	struct nfsstate *stp = NULL;
2051 	struct nfslock *lop;
2052 	struct nfslockconflict cf;
2053 	int error = 0;
2054 	u_short flags = NFSLCK_LOCK, lflags;
2055 	u_int64_t offset, len;
2056 	nfsv4stateid_t stateid;
2057 	nfsquad_t clientid;
2058 
2059 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2060 	i = fxdr_unsigned(int, *tl++);
2061 	switch (i) {
2062 	case NFSV4LOCKT_READW:
2063 		flags |= NFSLCK_BLOCKING;
2064 	case NFSV4LOCKT_READ:
2065 		lflags = NFSLCK_READ;
2066 		break;
2067 	case NFSV4LOCKT_WRITEW:
2068 		flags |= NFSLCK_BLOCKING;
2069 	case NFSV4LOCKT_WRITE:
2070 		lflags = NFSLCK_WRITE;
2071 		break;
2072 	default:
2073 		nd->nd_repstat = NFSERR_BADXDR;
2074 		goto nfsmout;
2075 	};
2076 	if (*tl++ == newnfs_true)
2077 		flags |= NFSLCK_RECLAIM;
2078 	offset = fxdr_hyper(tl);
2079 	tl += 2;
2080 	len = fxdr_hyper(tl);
2081 	tl += 2;
2082 	if (*tl == newnfs_true)
2083 		flags |= NFSLCK_OPENTOLOCK;
2084 	if (flags & NFSLCK_OPENTOLOCK) {
2085 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2086 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2087 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2088 			M_NFSDSTATE, M_WAITOK);
2089 		stp->ls_ownerlen = i;
2090 		stp->ls_op = nd->nd_rp;
2091 		stp->ls_seq = fxdr_unsigned(int, *tl++);
2092 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2093 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2094 			NFSX_STATEIDOTHER);
2095 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2096 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2097 		clientid.lval[0] = *tl++;
2098 		clientid.lval[1] = *tl++;
2099 		if (nd->nd_flag & ND_IMPLIEDCLID) {
2100 			if (nd->nd_clientid.qval != clientid.qval)
2101 				printf("EEK! multiple clids\n");
2102 		} else {
2103 			nd->nd_flag |= ND_IMPLIEDCLID;
2104 			nd->nd_clientid.qval = clientid.qval;
2105 		}
2106 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2107 		if (error)
2108 			goto nfsmout;
2109 	} else {
2110 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2111 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2112 			M_NFSDSTATE, M_WAITOK);
2113 		stp->ls_ownerlen = 0;
2114 		stp->ls_op = nd->nd_rp;
2115 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2116 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2117 			NFSX_STATEIDOTHER);
2118 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2119 		stp->ls_seq = fxdr_unsigned(int, *tl);
2120 		clientid.lval[0] = stp->ls_stateid.other[0];
2121 		clientid.lval[1] = stp->ls_stateid.other[1];
2122 		if (nd->nd_flag & ND_IMPLIEDCLID) {
2123 			if (nd->nd_clientid.qval != clientid.qval)
2124 				printf("EEK! multiple clids\n");
2125 		} else {
2126 			nd->nd_flag |= ND_IMPLIEDCLID;
2127 			nd->nd_clientid.qval = clientid.qval;
2128 		}
2129 	}
2130 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2131 		M_NFSDLOCK, M_WAITOK);
2132 	lop->lo_first = offset;
2133 	if (len == NFS64BITSSET) {
2134 		lop->lo_end = NFS64BITSSET;
2135 	} else {
2136 		lop->lo_end = offset + len;
2137 		if (lop->lo_end <= lop->lo_first)
2138 			nd->nd_repstat = NFSERR_INVAL;
2139 	}
2140 	lop->lo_flags = lflags;
2141 	stp->ls_flags = flags;
2142 	stp->ls_uid = nd->nd_cred->cr_uid;
2143 
2144 	/*
2145 	 * Do basic access checking.
2146 	 */
2147 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2148 	    if (vnode_vtype(vp) == VDIR)
2149 		nd->nd_repstat = NFSERR_ISDIR;
2150 	    else
2151 		nd->nd_repstat = NFSERR_INVAL;
2152 	}
2153 	if (!nd->nd_repstat) {
2154 	    if (lflags & NFSLCK_WRITE) {
2155 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2156 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2157 		    NFSACCCHK_VPISLOCKED, NULL);
2158 	    } else {
2159 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2160 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2161 		    NFSACCCHK_VPISLOCKED, NULL);
2162 		if (nd->nd_repstat)
2163 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2164 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2165 			NFSACCCHK_VPISLOCKED, NULL);
2166 	    }
2167 	}
2168 
2169 	/*
2170 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2171 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
2172 	 * of nd_repstat, if it gets that far.
2173 	 */
2174 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2175 		&stateid, exp, nd, p);
2176 	if (lop)
2177 		FREE((caddr_t)lop, M_NFSDLOCK);
2178 	if (stp)
2179 		FREE((caddr_t)stp, M_NFSDSTATE);
2180 	if (!nd->nd_repstat) {
2181 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2182 		*tl++ = txdr_unsigned(stateid.seqid);
2183 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2184 	} else if (nd->nd_repstat == NFSERR_DENIED) {
2185 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2186 		txdr_hyper(cf.cl_first, tl);
2187 		tl += 2;
2188 		if (cf.cl_end == NFS64BITSSET)
2189 			len = NFS64BITSSET;
2190 		else
2191 			len = cf.cl_end - cf.cl_first;
2192 		txdr_hyper(len, tl);
2193 		tl += 2;
2194 		if (cf.cl_flags == NFSLCK_WRITE)
2195 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2196 		else
2197 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2198 		*tl++ = stateid.other[0];
2199 		*tl = stateid.other[1];
2200 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2201 	}
2202 	vput(vp);
2203 	return (0);
2204 nfsmout:
2205 	vput(vp);
2206 	if (stp)
2207 		free((caddr_t)stp, M_NFSDSTATE);
2208 	return (error);
2209 }
2210 
2211 /*
2212  * nfsv4 lock test service
2213  */
2214 APPLESTATIC int
2215 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2216     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2217 {
2218 	u_int32_t *tl;
2219 	int i;
2220 	struct nfsstate *stp = NULL;
2221 	struct nfslock lo, *lop = &lo;
2222 	struct nfslockconflict cf;
2223 	int error = 0;
2224 	nfsv4stateid_t stateid;
2225 	nfsquad_t clientid;
2226 	u_int64_t len;
2227 
2228 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2229 	i = fxdr_unsigned(int, *(tl + 7));
2230 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2231 	    M_NFSDSTATE, M_WAITOK);
2232 	stp->ls_ownerlen = i;
2233 	stp->ls_op = NULL;
2234 	stp->ls_flags = NFSLCK_TEST;
2235 	stp->ls_uid = nd->nd_cred->cr_uid;
2236 	i = fxdr_unsigned(int, *tl++);
2237 	switch (i) {
2238 	case NFSV4LOCKT_READW:
2239 		stp->ls_flags |= NFSLCK_BLOCKING;
2240 	case NFSV4LOCKT_READ:
2241 		lo.lo_flags = NFSLCK_READ;
2242 		break;
2243 	case NFSV4LOCKT_WRITEW:
2244 		stp->ls_flags |= NFSLCK_BLOCKING;
2245 	case NFSV4LOCKT_WRITE:
2246 		lo.lo_flags = NFSLCK_WRITE;
2247 		break;
2248 	default:
2249 		nd->nd_repstat = NFSERR_BADXDR;
2250 		goto nfsmout;
2251 	};
2252 	lo.lo_first = fxdr_hyper(tl);
2253 	tl += 2;
2254 	len = fxdr_hyper(tl);
2255 	if (len == NFS64BITSSET) {
2256 		lo.lo_end = NFS64BITSSET;
2257 	} else {
2258 		lo.lo_end = lo.lo_first + len;
2259 		if (lo.lo_end <= lo.lo_first)
2260 			nd->nd_repstat = NFSERR_INVAL;
2261 	}
2262 	tl += 2;
2263 	clientid.lval[0] = *tl++;
2264 	clientid.lval[1] = *tl;
2265 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2266 		if (nd->nd_clientid.qval != clientid.qval)
2267 			printf("EEK! multiple clids\n");
2268 	} else {
2269 		nd->nd_flag |= ND_IMPLIEDCLID;
2270 		nd->nd_clientid.qval = clientid.qval;
2271 	}
2272 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2273 	if (error)
2274 		goto nfsmout;
2275 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2276 	    if (vnode_vtype(vp) == VDIR)
2277 		nd->nd_repstat = NFSERR_ISDIR;
2278 	    else
2279 		nd->nd_repstat = NFSERR_INVAL;
2280 	}
2281 	if (!nd->nd_repstat)
2282 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2283 	    &stateid, exp, nd, p);
2284 	if (stp)
2285 		FREE((caddr_t)stp, M_NFSDSTATE);
2286 	if (nd->nd_repstat) {
2287 	    if (nd->nd_repstat == NFSERR_DENIED) {
2288 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2289 		txdr_hyper(cf.cl_first, tl);
2290 		tl += 2;
2291 		if (cf.cl_end == NFS64BITSSET)
2292 			len = NFS64BITSSET;
2293 		else
2294 			len = cf.cl_end - cf.cl_first;
2295 		txdr_hyper(len, tl);
2296 		tl += 2;
2297 		if (cf.cl_flags == NFSLCK_WRITE)
2298 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2299 		else
2300 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2301 		*tl++ = stp->ls_stateid.other[0];
2302 		*tl = stp->ls_stateid.other[1];
2303 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2304 	    }
2305 	}
2306 	vput(vp);
2307 	return (0);
2308 nfsmout:
2309 	vput(vp);
2310 	if (stp)
2311 		free((caddr_t)stp, M_NFSDSTATE);
2312 	return (error);
2313 }
2314 
2315 /*
2316  * nfsv4 unlock service
2317  */
2318 APPLESTATIC int
2319 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2320     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2321 {
2322 	u_int32_t *tl;
2323 	int i;
2324 	struct nfsstate *stp;
2325 	struct nfslock *lop;
2326 	int error = 0;
2327 	nfsv4stateid_t stateid;
2328 	nfsquad_t clientid;
2329 	u_int64_t len;
2330 
2331 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2332 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2333 	    M_NFSDSTATE, M_WAITOK);
2334 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2335 	    M_NFSDLOCK, M_WAITOK);
2336 	stp->ls_flags = NFSLCK_UNLOCK;
2337 	lop->lo_flags = NFSLCK_UNLOCK;
2338 	stp->ls_op = nd->nd_rp;
2339 	i = fxdr_unsigned(int, *tl++);
2340 	switch (i) {
2341 	case NFSV4LOCKT_READW:
2342 		stp->ls_flags |= NFSLCK_BLOCKING;
2343 	case NFSV4LOCKT_READ:
2344 		break;
2345 	case NFSV4LOCKT_WRITEW:
2346 		stp->ls_flags |= NFSLCK_BLOCKING;
2347 	case NFSV4LOCKT_WRITE:
2348 		break;
2349 	default:
2350 		nd->nd_repstat = NFSERR_BADXDR;
2351 		goto nfsmout;
2352 	};
2353 	stp->ls_ownerlen = 0;
2354 	stp->ls_uid = nd->nd_cred->cr_uid;
2355 	stp->ls_seq = fxdr_unsigned(int, *tl++);
2356 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2357 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2358 	    NFSX_STATEIDOTHER);
2359 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2360 	lop->lo_first = fxdr_hyper(tl);
2361 	tl += 2;
2362 	len = fxdr_hyper(tl);
2363 	if (len == NFS64BITSSET) {
2364 		lop->lo_end = NFS64BITSSET;
2365 	} else {
2366 		lop->lo_end = lop->lo_first + len;
2367 		if (lop->lo_end <= lop->lo_first)
2368 			nd->nd_repstat = NFSERR_INVAL;
2369 	}
2370 	clientid.lval[0] = stp->ls_stateid.other[0];
2371 	clientid.lval[1] = stp->ls_stateid.other[1];
2372 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2373 		if (nd->nd_clientid.qval != clientid.qval)
2374 			printf("EEK! multiple clids\n");
2375 	} else {
2376 		nd->nd_flag |= ND_IMPLIEDCLID;
2377 		nd->nd_clientid.qval = clientid.qval;
2378 	}
2379 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2380 	    if (vnode_vtype(vp) == VDIR)
2381 		nd->nd_repstat = NFSERR_ISDIR;
2382 	    else
2383 		nd->nd_repstat = NFSERR_INVAL;
2384 	}
2385 	/*
2386 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2387 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
2388 	 * value of nd_repstat, if it gets that far.
2389 	 */
2390 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2391 	    &stateid, exp, nd, p);
2392 	if (stp)
2393 		FREE((caddr_t)stp, M_NFSDSTATE);
2394 	if (lop)
2395 		free((caddr_t)lop, M_NFSDLOCK);
2396 	if (!nd->nd_repstat) {
2397 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2398 		*tl++ = txdr_unsigned(stateid.seqid);
2399 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2400 	}
2401 nfsmout:
2402 	vput(vp);
2403 	return (error);
2404 }
2405 
2406 /*
2407  * nfsv4 open service
2408  */
2409 APPLESTATIC int
2410 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2411     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2412     struct nfsexstuff *exp)
2413 {
2414 	u_int32_t *tl;
2415 	int i;
2416 	struct nfsstate *stp = NULL;
2417 	int error = 0, create, claim, exclusive_flag = 0;
2418 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2419 	int how = NFSCREATE_UNCHECKED;
2420 	int32_t cverf[2], tverf[2] = { 0, 0 };
2421 	vnode_t vp = NULL, dirp = NULL;
2422 	struct nfsvattr nva, dirfor, diraft;
2423 	struct nameidata named;
2424 	nfsv4stateid_t stateid, delegstateid;
2425 	nfsattrbit_t attrbits;
2426 	nfsquad_t clientid;
2427 	char *bufp = NULL;
2428 	u_long *hashp;
2429 	NFSACL_T *aclp = NULL;
2430 
2431 #ifdef NFS4_ACL_EXTATTR_NAME
2432 	aclp = acl_alloc(M_WAITOK);
2433 	aclp->acl_cnt = 0;
2434 #endif
2435 	NFSZERO_ATTRBIT(&attrbits);
2436 	named.ni_startdir = NULL;
2437 	named.ni_cnd.cn_nameiop = 0;
2438 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2439 	i = fxdr_unsigned(int, *(tl + 5));
2440 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2441 	    M_NFSDSTATE, M_WAITOK);
2442 	stp->ls_ownerlen = i;
2443 	stp->ls_op = nd->nd_rp;
2444 	stp->ls_flags = NFSLCK_OPEN;
2445 	stp->ls_uid = nd->nd_cred->cr_uid;
2446 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2447 	i = fxdr_unsigned(int, *tl++);
2448 	switch (i) {
2449 	case NFSV4OPEN_ACCESSREAD:
2450 		stp->ls_flags |= NFSLCK_READACCESS;
2451 		break;
2452 	case NFSV4OPEN_ACCESSWRITE:
2453 		stp->ls_flags |= NFSLCK_WRITEACCESS;
2454 		break;
2455 	case NFSV4OPEN_ACCESSBOTH:
2456 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2457 		break;
2458 	default:
2459 		nd->nd_repstat = NFSERR_INVAL;
2460 	};
2461 	i = fxdr_unsigned(int, *tl++);
2462 	switch (i) {
2463 	case NFSV4OPEN_DENYNONE:
2464 		break;
2465 	case NFSV4OPEN_DENYREAD:
2466 		stp->ls_flags |= NFSLCK_READDENY;
2467 		break;
2468 	case NFSV4OPEN_DENYWRITE:
2469 		stp->ls_flags |= NFSLCK_WRITEDENY;
2470 		break;
2471 	case NFSV4OPEN_DENYBOTH:
2472 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2473 		break;
2474 	default:
2475 		nd->nd_repstat = NFSERR_INVAL;
2476 	};
2477 	clientid.lval[0] = *tl++;
2478 	clientid.lval[1] = *tl;
2479 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2480 		if (nd->nd_clientid.qval != clientid.qval)
2481 			printf("EEK! multiple clids\n");
2482 	} else {
2483 		nd->nd_flag |= ND_IMPLIEDCLID;
2484 		nd->nd_clientid.qval = clientid.qval;
2485 	}
2486 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2487 	if (error) {
2488 		vrele(dp);
2489 #ifdef NFS4_ACL_EXTATTR_NAME
2490 		acl_free(aclp);
2491 #endif
2492 		FREE((caddr_t)stp, M_NFSDSTATE);
2493 		return (error);
2494 	}
2495 	NFSVNO_ATTRINIT(&nva);
2496 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2497 	create = fxdr_unsigned(int, *tl);
2498 	if (!nd->nd_repstat)
2499 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p);
2500 	if (create == NFSV4OPEN_CREATE) {
2501 		nva.na_type = VREG;
2502 		nva.na_mode = 0;
2503 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2504 		how = fxdr_unsigned(int, *tl);
2505 		switch (how) {
2506 		case NFSCREATE_UNCHECKED:
2507 		case NFSCREATE_GUARDED:
2508 			error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2509 			if (error) {
2510 				vrele(dp);
2511 #ifdef NFS4_ACL_EXTATTR_NAME
2512 				acl_free(aclp);
2513 #endif
2514 				FREE((caddr_t)stp, M_NFSDSTATE);
2515 				return (error);
2516 			}
2517 			/*
2518 			 * If the na_gid being set is the same as that of
2519 			 * the directory it is going in, clear it, since
2520 			 * that is what will be set by default. This allows
2521 			 * a user that isn't in that group to do the create.
2522 			 */
2523 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2524 			    nva.na_gid == dirfor.na_gid)
2525 				NFSVNO_UNSET(&nva, gid);
2526 			if (!nd->nd_repstat)
2527 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2528 			break;
2529 		case NFSCREATE_EXCLUSIVE:
2530 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2531 			cverf[0] = *tl++;
2532 			cverf[1] = *tl;
2533 			break;
2534 		default:
2535 			nd->nd_repstat = NFSERR_BADXDR;
2536 			vrele(dp);
2537 #ifdef NFS4_ACL_EXTATTR_NAME
2538 			acl_free(aclp);
2539 #endif
2540 			FREE((caddr_t)stp, M_NFSDSTATE);
2541 			return (0);
2542 		};
2543 	} else if (create != NFSV4OPEN_NOCREATE) {
2544 		nd->nd_repstat = NFSERR_BADXDR;
2545 		vrele(dp);
2546 #ifdef NFS4_ACL_EXTATTR_NAME
2547 		acl_free(aclp);
2548 #endif
2549 		FREE((caddr_t)stp, M_NFSDSTATE);
2550 		return (0);
2551 	}
2552 
2553 	/*
2554 	 * Now, handle the claim, which usually includes looking up a
2555 	 * name in the directory referenced by dp. The exception is
2556 	 * NFSV4OPEN_CLAIMPREVIOUS.
2557 	 */
2558 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2559 	claim = fxdr_unsigned(int, *tl);
2560 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2561 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2562 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2563 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2564 		stp->ls_flags |= NFSLCK_DELEGCUR;
2565 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2566 		stp->ls_flags |= NFSLCK_DELEGPREV;
2567 	}
2568 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2569 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2570 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2571 		    claim != NFSV4OPEN_CLAIMNULL)
2572 			nd->nd_repstat = NFSERR_INVAL;
2573 		if (nd->nd_repstat) {
2574 			nd->nd_repstat = nfsrv_opencheck(clientid,
2575 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
2576 			vrele(dp);
2577 #ifdef NFS4_ACL_EXTATTR_NAME
2578 			acl_free(aclp);
2579 #endif
2580 			FREE((caddr_t)stp, M_NFSDSTATE);
2581 			return (0);
2582 		}
2583 		if (create == NFSV4OPEN_CREATE)
2584 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2585 			LOCKPARENT | LOCKLEAF | SAVESTART);
2586 		else
2587 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2588 			LOCKLEAF | SAVESTART);
2589 		nfsvno_setpathbuf(&named, &bufp, &hashp);
2590 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2591 		if (error) {
2592 			vrele(dp);
2593 #ifdef NFS4_ACL_EXTATTR_NAME
2594 			acl_free(aclp);
2595 #endif
2596 			FREE((caddr_t)stp, M_NFSDSTATE);
2597 			nfsvno_relpathbuf(&named);
2598 			return (error);
2599 		}
2600 		if (!nd->nd_repstat) {
2601 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2602 			    p, &dirp);
2603 		} else {
2604 			vrele(dp);
2605 			nfsvno_relpathbuf(&named);
2606 		}
2607 		if (create == NFSV4OPEN_CREATE) {
2608 		    switch (how) {
2609 		    case NFSCREATE_UNCHECKED:
2610 			if (named.ni_vp) {
2611 				/*
2612 				 * Clear the setable attribute bits, except
2613 				 * for Size, if it is being truncated.
2614 				 */
2615 				NFSZERO_ATTRBIT(&attrbits);
2616 				if (NFSVNO_ISSETSIZE(&nva))
2617 					NFSSETBIT_ATTRBIT(&attrbits,
2618 					    NFSATTRBIT_SIZE);
2619 			}
2620 			break;
2621 		    case NFSCREATE_GUARDED:
2622 			if (named.ni_vp && !nd->nd_repstat)
2623 				nd->nd_repstat = EEXIST;
2624 			break;
2625 		    case NFSCREATE_EXCLUSIVE:
2626 			exclusive_flag = 1;
2627 			if (!named.ni_vp)
2628 				nva.na_mode = 0;
2629 		    };
2630 		}
2631 		nfsvno_open(nd, &named, clientid, &stateid, stp,
2632 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2633 		    nd->nd_cred, p, exp, &vp);
2634 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2635 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2636 		i = fxdr_unsigned(int, *tl);
2637 		switch (i) {
2638 		case NFSV4OPEN_DELEGATEREAD:
2639 			stp->ls_flags |= NFSLCK_DELEGREAD;
2640 			break;
2641 		case NFSV4OPEN_DELEGATEWRITE:
2642 			stp->ls_flags |= NFSLCK_DELEGWRITE;
2643 		case NFSV4OPEN_DELEGATENONE:
2644 			break;
2645 		default:
2646 			nd->nd_repstat = NFSERR_BADXDR;
2647 			vrele(dp);
2648 #ifdef NFS4_ACL_EXTATTR_NAME
2649 			acl_free(aclp);
2650 #endif
2651 			FREE((caddr_t)stp, M_NFSDSTATE);
2652 			return (0);
2653 		};
2654 		stp->ls_flags |= NFSLCK_RECLAIM;
2655 		vp = dp;
2656 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
2657 		nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp,
2658 		    nd, p, nd->nd_repstat);
2659 	} else {
2660 		nd->nd_repstat = NFSERR_BADXDR;
2661 		vrele(dp);
2662 #ifdef NFS4_ACL_EXTATTR_NAME
2663 		acl_free(aclp);
2664 #endif
2665 		FREE((caddr_t)stp, M_NFSDSTATE);
2666 		return (0);
2667 	}
2668 
2669 	/*
2670 	 * Do basic access checking.
2671 	 */
2672 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2673 	    if (vnode_vtype(vp) == VDIR)
2674 		nd->nd_repstat = NFSERR_ISDIR;
2675 	    else if (vnode_vtype(vp) == VLNK)
2676 		nd->nd_repstat = NFSERR_SYMLINK;
2677 	    else
2678 		nd->nd_repstat = NFSERR_INVAL;
2679 	}
2680 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2681 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2682 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2683 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2684 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2685 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2686 	    if (nd->nd_repstat)
2687 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2688 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2689 		    NFSACCCHK_VPISLOCKED, NULL);
2690 	}
2691 
2692 	if (!nd->nd_repstat) {
2693 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p);
2694 		if (!nd->nd_repstat) {
2695 			tverf[0] = nva.na_atime.tv_sec;
2696 			tverf[1] = nva.na_atime.tv_nsec;
2697 		}
2698 	}
2699 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2700 	    cverf[1] != tverf[1]))
2701 		nd->nd_repstat = EEXIST;
2702 	/*
2703 	 * Do the open locking/delegation stuff.
2704 	 */
2705 	if (!nd->nd_repstat)
2706 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2707 		&delegstateid, &rflags, exp, p, nva.na_filerev);
2708 
2709 	/*
2710 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2711 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2712 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
2713 	 */
2714 	if (vp)
2715 		NFSVOPUNLOCK(vp, 0, p);
2716 	if (stp)
2717 		FREE((caddr_t)stp, M_NFSDSTATE);
2718 	if (!nd->nd_repstat && dirp)
2719 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
2720 	if (!nd->nd_repstat) {
2721 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2722 		*tl++ = txdr_unsigned(stateid.seqid);
2723 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2724 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2725 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2726 			*tl++ = newnfs_true;
2727 			*tl++ = 0;
2728 			*tl++ = 0;
2729 			*tl++ = 0;
2730 			*tl++ = 0;
2731 		} else {
2732 			*tl++ = newnfs_false;	/* Since dirp is not locked */
2733 			txdr_hyper(dirfor.na_filerev, tl);
2734 			tl += 2;
2735 			txdr_hyper(diraft.na_filerev, tl);
2736 			tl += 2;
2737 		}
2738 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2739 		(void) nfsrv_putattrbit(nd, &attrbits);
2740 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2741 		if (rflags & NFSV4OPEN_READDELEGATE)
2742 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2743 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2744 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2745 		else
2746 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2747 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2748 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2749 			*tl++ = txdr_unsigned(delegstateid.seqid);
2750 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2751 			    NFSX_STATEIDOTHER);
2752 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2753 			if (rflags & NFSV4OPEN_RECALL)
2754 				*tl = newnfs_true;
2755 			else
2756 				*tl = newnfs_false;
2757 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2758 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2759 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2760 				txdr_hyper(nva.na_size, tl);
2761 			}
2762 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2763 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2764 			*tl++ = txdr_unsigned(0x0);
2765 			acemask = NFSV4ACE_ALLFILESMASK;
2766 			if (nva.na_mode & S_IRUSR)
2767 			    acemask |= NFSV4ACE_READMASK;
2768 			if (nva.na_mode & S_IWUSR)
2769 			    acemask |= NFSV4ACE_WRITEMASK;
2770 			if (nva.na_mode & S_IXUSR)
2771 			    acemask |= NFSV4ACE_EXECUTEMASK;
2772 			*tl = txdr_unsigned(acemask);
2773 			(void) nfsm_strtom(nd, "OWNER@", 6);
2774 		}
2775 		*vpp = vp;
2776 	} else if (vp) {
2777 		vrele(vp);
2778 	}
2779 	if (dirp)
2780 		vrele(dirp);
2781 #ifdef NFS4_ACL_EXTATTR_NAME
2782 	acl_free(aclp);
2783 #endif
2784 	return (0);
2785 nfsmout:
2786 	vrele(dp);
2787 #ifdef NFS4_ACL_EXTATTR_NAME
2788 	acl_free(aclp);
2789 #endif
2790 	if (stp)
2791 		FREE((caddr_t)stp, M_NFSDSTATE);
2792 	return (error);
2793 }
2794 
2795 /*
2796  * nfsv4 close service
2797  */
2798 APPLESTATIC int
2799 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2800     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2801 {
2802 	u_int32_t *tl;
2803 	struct nfsstate st, *stp = &st;
2804 	int error = 0;
2805 	nfsv4stateid_t stateid;
2806 	nfsquad_t clientid;
2807 
2808 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2809 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2810 	stp->ls_ownerlen = 0;
2811 	stp->ls_op = nd->nd_rp;
2812 	stp->ls_uid = nd->nd_cred->cr_uid;
2813 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2814 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2815 	    NFSX_STATEIDOTHER);
2816 	stp->ls_flags = NFSLCK_CLOSE;
2817 	clientid.lval[0] = stp->ls_stateid.other[0];
2818 	clientid.lval[1] = stp->ls_stateid.other[1];
2819 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2820 		if (nd->nd_clientid.qval != clientid.qval)
2821 			printf("EEK! multiple clids\n");
2822 	} else {
2823 		nd->nd_flag |= ND_IMPLIEDCLID;
2824 		nd->nd_clientid.qval = clientid.qval;
2825 	}
2826 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2827 	vput(vp);
2828 	if (!nd->nd_repstat) {
2829 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2830 		*tl++ = txdr_unsigned(stateid.seqid);
2831 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2832 	}
2833 	return (0);
2834 nfsmout:
2835 	vput(vp);
2836 	return (error);
2837 }
2838 
2839 /*
2840  * nfsv4 delegpurge service
2841  */
2842 APPLESTATIC int
2843 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2844     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2845 {
2846 	u_int32_t *tl;
2847 	int error = 0;
2848 	nfsquad_t clientid;
2849 
2850 	if ((!nfs_rootfhset && !nfsv4root_set) ||
2851 	    nfsd_checkrootexp(nd)) {
2852 		nd->nd_repstat = NFSERR_WRONGSEC;
2853 		return (0);
2854 	}
2855 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2856 	clientid.lval[0] = *tl++;
2857 	clientid.lval[1] = *tl;
2858 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2859 		if (nd->nd_clientid.qval != clientid.qval)
2860 			printf("EEK! multiple clids\n");
2861 	} else {
2862 		nd->nd_flag |= ND_IMPLIEDCLID;
2863 		nd->nd_clientid.qval = clientid.qval;
2864 	}
2865 	nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2866 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2867 nfsmout:
2868 	return (error);
2869 }
2870 
2871 /*
2872  * nfsv4 delegreturn service
2873  */
2874 APPLESTATIC int
2875 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2876     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2877 {
2878 	u_int32_t *tl;
2879 	int error = 0;
2880 	nfsv4stateid_t stateid;
2881 	nfsquad_t clientid;
2882 
2883 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2884 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2885 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2886 	clientid.lval[0] = stateid.other[0];
2887 	clientid.lval[1] = stateid.other[1];
2888 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2889 		if (nd->nd_clientid.qval != clientid.qval)
2890 			printf("EEK! multiple clids\n");
2891 	} else {
2892 		nd->nd_flag |= ND_IMPLIEDCLID;
2893 		nd->nd_clientid.qval = clientid.qval;
2894 	}
2895 	nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2896 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2897 nfsmout:
2898 	vput(vp);
2899 	return (error);
2900 }
2901 
2902 /*
2903  * nfsv4 get file handle service
2904  */
2905 APPLESTATIC int
2906 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2907     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2908 {
2909 	fhandle_t fh;
2910 
2911 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2912 	vput(vp);
2913 	if (!nd->nd_repstat)
2914 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2915 	return (0);
2916 }
2917 
2918 /*
2919  * nfsv4 open confirm service
2920  */
2921 APPLESTATIC int
2922 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2923     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2924 {
2925 	u_int32_t *tl;
2926 	struct nfsstate st, *stp = &st;
2927 	int error = 0;
2928 	nfsv4stateid_t stateid;
2929 	nfsquad_t clientid;
2930 
2931 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2932 	stp->ls_ownerlen = 0;
2933 	stp->ls_op = nd->nd_rp;
2934 	stp->ls_uid = nd->nd_cred->cr_uid;
2935 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2936 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2937 	    NFSX_STATEIDOTHER);
2938 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2939 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2940 	stp->ls_flags = NFSLCK_CONFIRM;
2941 	clientid.lval[0] = stp->ls_stateid.other[0];
2942 	clientid.lval[1] = stp->ls_stateid.other[1];
2943 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2944 		if (nd->nd_clientid.qval != clientid.qval)
2945 			printf("EEK! multiple clids\n");
2946 	} else {
2947 		nd->nd_flag |= ND_IMPLIEDCLID;
2948 		nd->nd_clientid.qval = clientid.qval;
2949 	}
2950 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2951 	if (!nd->nd_repstat) {
2952 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2953 		*tl++ = txdr_unsigned(stateid.seqid);
2954 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2955 	}
2956 nfsmout:
2957 	vput(vp);
2958 	return (error);
2959 }
2960 
2961 /*
2962  * nfsv4 open downgrade service
2963  */
2964 APPLESTATIC int
2965 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
2966     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2967 {
2968 	u_int32_t *tl;
2969 	int i;
2970 	struct nfsstate st, *stp = &st;
2971 	int error = 0;
2972 	nfsv4stateid_t stateid;
2973 	nfsquad_t clientid;
2974 
2975 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
2976 	stp->ls_ownerlen = 0;
2977 	stp->ls_op = nd->nd_rp;
2978 	stp->ls_uid = nd->nd_cred->cr_uid;
2979 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2980 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2981 	    NFSX_STATEIDOTHER);
2982 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2983 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2984 	i = fxdr_unsigned(int, *tl++);
2985 	switch (i) {
2986 	case NFSV4OPEN_ACCESSREAD:
2987 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
2988 		break;
2989 	case NFSV4OPEN_ACCESSWRITE:
2990 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
2991 		break;
2992 	case NFSV4OPEN_ACCESSBOTH:
2993 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
2994 		    NFSLCK_DOWNGRADE);
2995 		break;
2996 	default:
2997 		nd->nd_repstat = NFSERR_BADXDR;
2998 	};
2999 	i = fxdr_unsigned(int, *tl);
3000 	switch (i) {
3001 	case NFSV4OPEN_DENYNONE:
3002 		break;
3003 	case NFSV4OPEN_DENYREAD:
3004 		stp->ls_flags |= NFSLCK_READDENY;
3005 		break;
3006 	case NFSV4OPEN_DENYWRITE:
3007 		stp->ls_flags |= NFSLCK_WRITEDENY;
3008 		break;
3009 	case NFSV4OPEN_DENYBOTH:
3010 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3011 		break;
3012 	default:
3013 		nd->nd_repstat = NFSERR_BADXDR;
3014 	};
3015 
3016 	clientid.lval[0] = stp->ls_stateid.other[0];
3017 	clientid.lval[1] = stp->ls_stateid.other[1];
3018 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3019 		if (nd->nd_clientid.qval != clientid.qval)
3020 			printf("EEK! multiple clids\n");
3021 	} else {
3022 		nd->nd_flag |= ND_IMPLIEDCLID;
3023 		nd->nd_clientid.qval = clientid.qval;
3024 	}
3025 	if (!nd->nd_repstat)
3026 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3027 		    nd, p);
3028 	if (!nd->nd_repstat) {
3029 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3030 		*tl++ = txdr_unsigned(stateid.seqid);
3031 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3032 	}
3033 nfsmout:
3034 	vput(vp);
3035 	return (error);
3036 }
3037 
3038 /*
3039  * nfsv4 renew lease service
3040  */
3041 APPLESTATIC int
3042 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3043     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3044 {
3045 	u_int32_t *tl;
3046 	int error = 0;
3047 	nfsquad_t clientid;
3048 
3049 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3050 	    nfsd_checkrootexp(nd)) {
3051 		nd->nd_repstat = NFSERR_WRONGSEC;
3052 		return (0);
3053 	}
3054 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3055 	clientid.lval[0] = *tl++;
3056 	clientid.lval[1] = *tl;
3057 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3058 		if (nd->nd_clientid.qval != clientid.qval)
3059 			printf("EEK! multiple clids\n");
3060 	} else {
3061 		nd->nd_flag |= ND_IMPLIEDCLID;
3062 		nd->nd_clientid.qval = clientid.qval;
3063 	}
3064 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3065 	    NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3066 nfsmout:
3067 	return (error);
3068 }
3069 
3070 /*
3071  * nfsv4 security info service
3072  */
3073 APPLESTATIC int
3074 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3075     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3076 {
3077 	u_int32_t *tl;
3078 	int len;
3079 	struct nameidata named;
3080 	vnode_t dirp = NULL, vp;
3081 	struct nfsrvfh fh;
3082 	struct nfsexstuff retnes;
3083 	mount_t mp;
3084 	u_int32_t *sizp;
3085 	int error, savflag, i;
3086 	char *bufp;
3087 	u_long *hashp;
3088 
3089 	/*
3090 	 * All this just to get the export flags for the name.
3091 	 */
3092 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3093 	    LOCKLEAF | SAVESTART);
3094 	nfsvno_setpathbuf(&named, &bufp, &hashp);
3095 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3096 	if (error) {
3097 		vput(dp);
3098 		nfsvno_relpathbuf(&named);
3099 		return (error);
3100 	}
3101 	if (!nd->nd_repstat) {
3102 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3103 	} else {
3104 		vput(dp);
3105 		nfsvno_relpathbuf(&named);
3106 	}
3107 	if (dirp)
3108 		vrele(dirp);
3109 	if (nd->nd_repstat)
3110 		return (0);
3111 	vrele(named.ni_startdir);
3112 	nfsvno_relpathbuf(&named);
3113 	fh.nfsrvfh_len = NFSX_MYFH;
3114 	vp = named.ni_vp;
3115 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3116 	mp = vnode_mount(vp);	/* so it won't try to re-lock filesys */
3117 	retnes.nes_vfslocked = exp->nes_vfslocked;
3118 	vput(vp);
3119 	savflag = nd->nd_flag;
3120 	if (!nd->nd_repstat) {
3121 		nfsd_fhtovp(nd, &fh, &vp, &retnes, &mp, 0, p);
3122 		if (vp)
3123 			vput(vp);
3124 	}
3125 	nd->nd_flag = savflag;
3126 	if (nd->nd_repstat)
3127 		return (0);
3128 
3129 	/*
3130 	 * Finally have the export flags for name, so we can create
3131 	 * the security info.
3132 	 */
3133 	len = 0;
3134 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3135 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
3136 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
3137 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3138 			*tl = txdr_unsigned(RPCAUTH_UNIX);
3139 			len++;
3140 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3141 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3142 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3143 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3144 			    nfsgss_mechlist[KERBV_MECH].len);
3145 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3146 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3147 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3148 			len++;
3149 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3150 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3151 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3152 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3153 			    nfsgss_mechlist[KERBV_MECH].len);
3154 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3155 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3156 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3157 			len++;
3158 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3159 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3160 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3161 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3162 			    nfsgss_mechlist[KERBV_MECH].len);
3163 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3164 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3165 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3166 			len++;
3167 		}
3168 	}
3169 	*sizp = txdr_unsigned(len);
3170 	return (0);
3171 }
3172 
3173 /*
3174  * nfsv4 set client id service
3175  */
3176 APPLESTATIC int
3177 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3178     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3179 {
3180 	u_int32_t *tl;
3181 	int i;
3182 	int error = 0, idlen;
3183 	struct nfsclient *clp = NULL;
3184 	struct sockaddr_in *rad;
3185 	u_char *verf, *ucp, *ucp2, addrbuf[24];
3186 	nfsquad_t clientid, confirm;
3187 
3188 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3189 	    nfsd_checkrootexp(nd)) {
3190 		nd->nd_repstat = NFSERR_WRONGSEC;
3191 		return (0);
3192 	}
3193 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3194 	verf = (u_char *)tl;
3195 	tl += (NFSX_VERF / NFSX_UNSIGNED);
3196 	i = fxdr_unsigned(int, *tl);
3197 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3198 		nd->nd_repstat = NFSERR_BADXDR;
3199 		return (error);
3200 	}
3201 	idlen = i;
3202 	if (nd->nd_flag & ND_GSS)
3203 		i += nd->nd_princlen;
3204 	MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3205 	    M_NFSDCLIENT, M_WAITOK);
3206 	NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3207 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3208 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3209 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3210 	clp->lc_req.nr_cred = NULL;
3211 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3212 	clp->lc_idlen = idlen;
3213 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3214 	if (error)
3215 		goto nfsmout;
3216 	if (nd->nd_flag & ND_GSS) {
3217 		clp->lc_flags = LCL_GSS;
3218 		if (nd->nd_flag & ND_GSSINTEGRITY)
3219 			clp->lc_flags |= LCL_GSSINTEGRITY;
3220 		else if (nd->nd_flag & ND_GSSPRIVACY)
3221 			clp->lc_flags |= LCL_GSSPRIVACY;
3222 	} else {
3223 		clp->lc_flags = 0;
3224 	}
3225 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3226 		clp->lc_flags |= LCL_NAME;
3227 		clp->lc_namelen = nd->nd_princlen;
3228 		clp->lc_name = &clp->lc_id[idlen];
3229 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3230 	} else {
3231 		clp->lc_uid = nd->nd_cred->cr_uid;
3232 		clp->lc_gid = nd->nd_cred->cr_gid;
3233 	}
3234 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3235 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3236 	error = nfsrv_getclientipaddr(nd, clp);
3237 	if (error)
3238 		goto nfsmout;
3239 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3240 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3241 
3242 	/*
3243 	 * nfsrv_setclient() does the actual work of adding it to the
3244 	 * client list. If there is no error, the structure has been
3245 	 * linked into the client list and clp should no longer be used
3246 	 * here. When an error is returned, it has not been linked in,
3247 	 * so it should be free'd.
3248 	 */
3249 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3250 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3251 		if (clp->lc_flags & LCL_TCPCALLBACK)
3252 			(void) nfsm_strtom(nd, "tcp", 3);
3253 		else
3254 			(void) nfsm_strtom(nd, "udp", 3);
3255 		rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3256 		ucp = (u_char *)&rad->sin_addr.s_addr;
3257 		ucp2 = (u_char *)&rad->sin_port;
3258 		sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3259 		    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3260 		    ucp2[0] & 0xff, ucp2[1] & 0xff);
3261 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3262 	}
3263 	if (clp) {
3264 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3265 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3266 		free((caddr_t)clp, M_NFSDCLIENT);
3267 	}
3268 	if (!nd->nd_repstat) {
3269 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3270 		*tl++ = clientid.lval[0];
3271 		*tl++ = clientid.lval[1];
3272 		*tl++ = confirm.lval[0];
3273 		*tl = confirm.lval[1];
3274 	}
3275 	return (0);
3276 nfsmout:
3277 	if (clp) {
3278 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3279 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3280 		free((caddr_t)clp, M_NFSDCLIENT);
3281 	}
3282 	return (error);
3283 }
3284 
3285 /*
3286  * nfsv4 set client id confirm service
3287  */
3288 APPLESTATIC int
3289 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3290     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3291     __unused struct nfsexstuff *exp)
3292 {
3293 	u_int32_t *tl;
3294 	int error = 0;
3295 	nfsquad_t clientid, confirm;
3296 
3297 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3298 	    nfsd_checkrootexp(nd)) {
3299 		nd->nd_repstat = NFSERR_WRONGSEC;
3300 		return (0);
3301 	}
3302 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3303 	clientid.lval[0] = *tl++;
3304 	clientid.lval[1] = *tl++;
3305 	confirm.lval[0] = *tl++;
3306 	confirm.lval[1] = *tl;
3307 
3308 	/*
3309 	 * nfsrv_getclient() searches the client list for a match and
3310 	 * returns the appropriate NFSERR status.
3311 	 */
3312 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3313 	    NULL, confirm, nd, p);
3314 nfsmout:
3315 	return (error);
3316 }
3317 
3318 /*
3319  * nfsv4 verify service
3320  */
3321 APPLESTATIC int
3322 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3323     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3324 {
3325 	int error = 0, ret, fhsize = NFSX_MYFH;
3326 	struct nfsvattr nva;
3327 	struct statfs sf;
3328 	struct nfsfsinfo fs;
3329 	fhandle_t fh;
3330 
3331 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p);
3332 	if (!nd->nd_repstat)
3333 		nd->nd_repstat = nfsvno_statfs(vp, &sf);
3334 	if (!nd->nd_repstat)
3335 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3336 	if (!nd->nd_repstat) {
3337 		nfsvno_getfs(&fs, isdgram);
3338 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3339 		    &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3340 		if (!error) {
3341 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3342 				if (ret == 0)
3343 					nd->nd_repstat = NFSERR_SAME;
3344 				else if (ret != NFSERR_NOTSAME)
3345 					nd->nd_repstat = ret;
3346 			} else if (ret)
3347 				nd->nd_repstat = ret;
3348 		}
3349 	}
3350 	vput(vp);
3351 	return (error);
3352 }
3353 
3354 /*
3355  * nfs openattr rpc
3356  */
3357 APPLESTATIC int
3358 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3359     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3360     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3361 {
3362 	u_int32_t *tl;
3363 	int error = 0, createdir;
3364 
3365 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3366 	createdir = fxdr_unsigned(int, *tl);
3367 	nd->nd_repstat = NFSERR_NOTSUPP;
3368 nfsmout:
3369 	vrele(dp);
3370 	return (error);
3371 }
3372 
3373 /*
3374  * nfsv4 release lock owner service
3375  */
3376 APPLESTATIC int
3377 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3378     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3379 {
3380 	u_int32_t *tl;
3381 	struct nfsstate *stp = NULL;
3382 	int error = 0, len;
3383 	nfsquad_t clientid;
3384 
3385 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3386 	    nfsd_checkrootexp(nd)) {
3387 		nd->nd_repstat = NFSERR_WRONGSEC;
3388 		return (0);
3389 	}
3390 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3391 	len = fxdr_unsigned(int, *(tl + 2));
3392 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3393 	    M_NFSDSTATE, M_WAITOK);
3394 	stp->ls_ownerlen = len;
3395 	stp->ls_op = NULL;
3396 	stp->ls_flags = NFSLCK_RELEASE;
3397 	stp->ls_uid = nd->nd_cred->cr_uid;
3398 	clientid.lval[0] = *tl++;
3399 	clientid.lval[1] = *tl;
3400 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3401 		if (nd->nd_clientid.qval != clientid.qval)
3402 			printf("EEK! multiple clids\n");
3403 	} else {
3404 		nd->nd_flag |= ND_IMPLIEDCLID;
3405 		nd->nd_clientid.qval = clientid.qval;
3406 	}
3407 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
3408 	if (error)
3409 		goto nfsmout;
3410 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3411 	FREE((caddr_t)stp, M_NFSDSTATE);
3412 	return (0);
3413 nfsmout:
3414 	if (stp)
3415 		free((caddr_t)stp, M_NFSDSTATE);
3416 	return (error);
3417 }
3418