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