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