xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision 830940567b49bb0c08dfaed40418999e76616909)
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 	u_char cverf[NFSX_VERF], *cp;
869 	fhandle_t fh;
870 	char *bufp;
871 	u_long *hashp;
872 	enum vtype vtyp;
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(cp, u_char *, NFSX_VERF);
924 				NFSBCOPY(cp, cverf, NFSX_VERF);
925 				exclusive_flag = 1;
926 				break;
927 			};
928 			NFSVNO_SETATTRVAL(&nva, type, VREG);
929 		}
930 	}
931 	if (nd->nd_repstat) {
932 		nfsvno_relpathbuf(&named);
933 		if (nd->nd_flag & ND_NFSV3) {
934 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
935 			    p);
936 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
937 			    &diraft);
938 		}
939 		vput(dp);
940 		return (0);
941 	}
942 
943 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
944 	if (dirp) {
945 		if (nd->nd_flag & ND_NFSV2) {
946 			vrele(dirp);
947 			dirp = NULL;
948 		} else {
949 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
950 			    p);
951 		}
952 	}
953 	if (nd->nd_repstat) {
954 		if (nd->nd_flag & ND_NFSV3)
955 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
956 			    &diraft);
957 		if (dirp)
958 			vrele(dirp);
959 		return (0);
960 	}
961 
962 	if (!(nd->nd_flag & ND_NFSV2)) {
963 		switch (how) {
964 		case NFSCREATE_GUARDED:
965 			if (named.ni_vp)
966 				nd->nd_repstat = EEXIST;
967 			break;
968 		case NFSCREATE_UNCHECKED:
969 			break;
970 		case NFSCREATE_EXCLUSIVE:
971 			if (named.ni_vp == NULL)
972 				NFSVNO_SETATTRVAL(&nva, mode, 0);
973 			break;
974 		};
975 	}
976 
977 	/*
978 	 * Iff doesn't exist, create it
979 	 * otherwise just truncate to 0 length
980 	 *   should I set the mode too ?
981 	 */
982 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
983 	    &exclusive_flag, cverf, rdev, p, exp);
984 
985 	if (!nd->nd_repstat) {
986 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
987 		if (!nd->nd_repstat)
988 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
989 			    p);
990 		vput(vp);
991 	}
992 	if (nd->nd_flag & ND_NFSV2) {
993 		if (!nd->nd_repstat) {
994 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
995 			nfsrv_fillattr(nd, &nva);
996 		}
997 	} else {
998 		if (exclusive_flag && !nd->nd_repstat &&
999 			NFSBCMP(cverf, (caddr_t)&nva.na_atime, NFSX_VERF))
1000 			nd->nd_repstat = EEXIST;
1001 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
1002 		vrele(dirp);
1003 		if (!nd->nd_repstat) {
1004 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1005 			nfsrv_postopattr(nd, 0, &nva);
1006 		}
1007 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1008 	}
1009 	return (0);
1010 nfsmout:
1011 	vput(dp);
1012 	nfsvno_relpathbuf(&named);
1013 	return (error);
1014 }
1015 
1016 /*
1017  * nfs v3 mknod service (and v4 create)
1018  */
1019 APPLESTATIC int
1020 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1021     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1022     struct nfsexstuff *exp)
1023 {
1024 	struct nfsvattr nva, dirfor, diraft;
1025 	u_int32_t *tl;
1026 	struct nameidata named;
1027 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1028 	u_int32_t major, minor;
1029 	enum vtype vtyp = VNON;
1030 	nfstype nfs4type = NFNON;
1031 	vnode_t vp, dirp = NULL;
1032 	nfsattrbit_t attrbits;
1033 	char *bufp = NULL, *pathcp = NULL;
1034 	u_long *hashp, cnflags;
1035 	NFSACL_T *aclp = NULL;
1036 
1037 	NFSVNO_ATTRINIT(&nva);
1038 	cnflags = (LOCKPARENT | SAVESTART);
1039 	if (nd->nd_repstat) {
1040 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1041 		return (0);
1042 	}
1043 #ifdef NFS4_ACL_EXTATTR_NAME
1044 	aclp = acl_alloc(M_WAITOK);
1045 	aclp->acl_cnt = 0;
1046 #endif
1047 
1048 	/*
1049 	 * For V4, the creation stuff is here, Yuck!
1050 	 */
1051 	if (nd->nd_flag & ND_NFSV4) {
1052 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1053 		vtyp = nfsv34tov_type(*tl);
1054 		nfs4type = fxdr_unsigned(nfstype, *tl);
1055 		switch (nfs4type) {
1056 		case NFLNK:
1057 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1058 			    &pathlen);
1059 			if (error) {
1060 				vrele(dp);
1061 #ifdef NFS4_ACL_EXTATTR_NAME
1062 				acl_free(aclp);
1063 #endif
1064 				return (error);
1065 			}
1066 			break;
1067 		case NFCHR:
1068 		case NFBLK:
1069 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1070 			major = fxdr_unsigned(u_int32_t, *tl++);
1071 			minor = fxdr_unsigned(u_int32_t, *tl);
1072 			nva.na_rdev = NFSMAKEDEV(major, minor);
1073 			break;
1074 		case NFSOCK:
1075 		case NFFIFO:
1076 			break;
1077 		case NFDIR:
1078 			cnflags = LOCKPARENT;
1079 			break;
1080 		default:
1081 			nd->nd_repstat = NFSERR_BADTYPE;
1082 			vrele(dp);
1083 #ifdef NFS4_ACL_EXTATTR_NAME
1084 			acl_free(aclp);
1085 #endif
1086 			return (0);
1087 		};
1088 	}
1089 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1090 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1091 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1092 	if (error) {
1093 		vrele(dp);
1094 #ifdef NFS4_ACL_EXTATTR_NAME
1095 		acl_free(aclp);
1096 #endif
1097 		nfsvno_relpathbuf(&named);
1098 		if (pathcp)
1099 			FREE(pathcp, M_TEMP);
1100 		return (error);
1101 	}
1102 	if (!nd->nd_repstat) {
1103 		if (nd->nd_flag & ND_NFSV3) {
1104 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1105 			vtyp = nfsv34tov_type(*tl);
1106 		}
1107 		error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1108 		if (error) {
1109 			vrele(dp);
1110 #ifdef NFS4_ACL_EXTATTR_NAME
1111 			acl_free(aclp);
1112 #endif
1113 			nfsvno_relpathbuf(&named);
1114 			if (pathcp)
1115 				FREE(pathcp, M_TEMP);
1116 			return (error);
1117 		}
1118 		nva.na_type = vtyp;
1119 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1120 		    (vtyp == VCHR || vtyp == VBLK)) {
1121 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1122 			major = fxdr_unsigned(u_int32_t, *tl++);
1123 			minor = fxdr_unsigned(u_int32_t, *tl);
1124 			nva.na_rdev = NFSMAKEDEV(major, minor);
1125 		}
1126 	}
1127 
1128 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p);
1129 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1130 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1131 		    dirfor.na_gid == nva.na_gid)
1132 			NFSVNO_UNSET(&nva, gid);
1133 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1134 	}
1135 	if (nd->nd_repstat) {
1136 		vrele(dp);
1137 #ifdef NFS4_ACL_EXTATTR_NAME
1138 		acl_free(aclp);
1139 #endif
1140 		nfsvno_relpathbuf(&named);
1141 		if (pathcp)
1142 			FREE(pathcp, M_TEMP);
1143 		if (nd->nd_flag & ND_NFSV3)
1144 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1145 			    &diraft);
1146 		return (0);
1147 	}
1148 
1149 	/*
1150 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1151 	 * in va_mode, so we'll have to set a default here.
1152 	 */
1153 	if (NFSVNO_NOTSETMODE(&nva)) {
1154 		if (vtyp == VLNK)
1155 			nva.na_mode = 0755;
1156 		else
1157 			nva.na_mode = 0400;
1158 	}
1159 
1160 	if (vtyp == VDIR)
1161 		named.ni_cnd.cn_flags |= WILLBEDIR;
1162 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1163 	if (nd->nd_repstat) {
1164 		if (dirp) {
1165 			if (nd->nd_flag & ND_NFSV3)
1166 				dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1167 				    nd->nd_cred, p);
1168 			vrele(dirp);
1169 		}
1170 #ifdef NFS4_ACL_EXTATTR_NAME
1171 		acl_free(aclp);
1172 #endif
1173 		if (nd->nd_flag & ND_NFSV3)
1174 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1175 			    &diraft);
1176 		return (0);
1177 	}
1178 	if (dirp)
1179 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p);
1180 
1181 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1182 		if (vtyp == VDIR) {
1183 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1184 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1185 			    exp);
1186 #ifdef NFS4_ACL_EXTATTR_NAME
1187 			acl_free(aclp);
1188 #endif
1189 			return (0);
1190 		} else if (vtyp == VLNK) {
1191 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1192 			    &dirfor, &diraft, &diraft_ret, &attrbits,
1193 			    aclp, p, exp, pathcp, pathlen);
1194 #ifdef NFS4_ACL_EXTATTR_NAME
1195 			acl_free(aclp);
1196 #endif
1197 			FREE(pathcp, M_TEMP);
1198 			return (0);
1199 		}
1200 	}
1201 
1202 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1203 	if (!nd->nd_repstat) {
1204 		vp = named.ni_vp;
1205 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1206 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1207 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1208 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1209 			    p);
1210 		if (vpp) {
1211 			NFSVOPUNLOCK(vp, 0, p);
1212 			*vpp = vp;
1213 		} else {
1214 			vput(vp);
1215 		}
1216 	}
1217 
1218 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
1219 	vrele(dirp);
1220 	if (!nd->nd_repstat) {
1221 		if (nd->nd_flag & ND_NFSV3) {
1222 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1223 			nfsrv_postopattr(nd, 0, &nva);
1224 		} else {
1225 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1226 			*tl++ = newnfs_false;
1227 			txdr_hyper(dirfor.na_filerev, tl);
1228 			tl += 2;
1229 			txdr_hyper(diraft.na_filerev, tl);
1230 			(void) nfsrv_putattrbit(nd, &attrbits);
1231 		}
1232 	}
1233 	if (nd->nd_flag & ND_NFSV3)
1234 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1235 #ifdef NFS4_ACL_EXTATTR_NAME
1236 	acl_free(aclp);
1237 #endif
1238 	return (0);
1239 nfsmout:
1240 	vrele(dp);
1241 #ifdef NFS4_ACL_EXTATTR_NAME
1242 	acl_free(aclp);
1243 #endif
1244 	if (bufp)
1245 		nfsvno_relpathbuf(&named);
1246 	if (pathcp)
1247 		FREE(pathcp, M_TEMP);
1248 	return (error);
1249 }
1250 
1251 /*
1252  * nfs remove service
1253  */
1254 APPLESTATIC int
1255 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1256     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1257 {
1258 	struct nameidata named;
1259 	u_int32_t *tl;
1260 	int error, dirfor_ret = 1, diraft_ret = 1;
1261 	vnode_t dirp = NULL;
1262 	struct nfsvattr dirfor, diraft;
1263 	char *bufp;
1264 	u_long *hashp;
1265 
1266 	if (nd->nd_repstat) {
1267 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1268 		return (0);
1269 	}
1270 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1271 	    LOCKPARENT | LOCKLEAF);
1272 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1273 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1274 	if (error) {
1275 		vput(dp);
1276 		nfsvno_relpathbuf(&named);
1277 		return (error);
1278 	}
1279 	if (!nd->nd_repstat) {
1280 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1281 	} else {
1282 		vput(dp);
1283 		nfsvno_relpathbuf(&named);
1284 	}
1285 	if (dirp) {
1286 		if (!(nd->nd_flag & ND_NFSV2)) {
1287 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1288 			    nd->nd_cred, p);
1289 		} else {
1290 			vrele(dirp);
1291 			dirp = NULL;
1292 		}
1293 	}
1294 	if (!nd->nd_repstat) {
1295 		if (nd->nd_flag & ND_NFSV4) {
1296 			if (vnode_vtype(named.ni_vp) == VDIR)
1297 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1298 				    nd->nd_cred, p, exp);
1299 			else
1300 				nd->nd_repstat = nfsvno_removesub(&named, 1,
1301 				    nd->nd_cred, p, exp);
1302 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
1303 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1304 			    nd->nd_cred, p, exp);
1305 		} else {
1306 			nd->nd_repstat = nfsvno_removesub(&named, 0,
1307 			    nd->nd_cred, p, exp);
1308 		}
1309 	}
1310 	if (!(nd->nd_flag & ND_NFSV2)) {
1311 		if (dirp) {
1312 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1313 			    p);
1314 			vrele(dirp);
1315 		}
1316 		if (nd->nd_flag & ND_NFSV3) {
1317 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1318 			    &diraft);
1319 		} else if (!nd->nd_repstat) {
1320 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1321 			*tl++ = newnfs_false;
1322 			txdr_hyper(dirfor.na_filerev, tl);
1323 			tl += 2;
1324 			txdr_hyper(diraft.na_filerev, tl);
1325 		}
1326 	}
1327 	return (0);
1328 }
1329 
1330 /*
1331  * nfs rename service
1332  */
1333 APPLESTATIC int
1334 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1335     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1336     struct nfsexstuff *toexp)
1337 {
1338 	u_int32_t *tl;
1339 	int error, fdirfor_ret = 1, fdiraft_ret = 1;
1340 	int tdirfor_ret = 1, tdiraft_ret = 1;
1341 	struct nameidata fromnd, tond;
1342 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1343 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1344 	struct nfsexstuff tnes;
1345 	struct nfsrvfh tfh;
1346 	mount_t mp = NULL;
1347 	char *bufp, *tbufp = NULL;
1348 	u_long *hashp;
1349 
1350 	if (nd->nd_repstat) {
1351 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1352 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1353 		return (0);
1354 	}
1355 	if (!(nd->nd_flag & ND_NFSV2))
1356 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p);
1357 	tond.ni_cnd.cn_nameiop = 0;
1358 	tond.ni_startdir = NULL;
1359 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1360 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1361 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1362 	if (error) {
1363 		vput(dp);
1364 		if (todp)
1365 			vrele(todp);
1366 		nfsvno_relpathbuf(&fromnd);
1367 		return (error);
1368 	}
1369 	if (nd->nd_flag & ND_NFSV4) {
1370 		tdp = todp;
1371 		tnes = *toexp;
1372 		tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p);
1373 	} else {
1374 		error = nfsrv_mtofh(nd, &tfh);
1375 		if (error) {
1376 			vput(dp);
1377 			/* todp is always NULL except NFSv4 */
1378 			nfsvno_relpathbuf(&fromnd);
1379 			return (error);
1380 		}
1381 		nd->nd_cred->cr_uid = nd->nd_saveduid;
1382 		/* Won't lock vfs if already locked, mp == NULL */
1383 		tnes.nes_vfslocked = exp->nes_vfslocked;
1384 		nfsd_fhtovp(nd, &tfh, &tdp, &tnes, &mp, 0, p);
1385 		if (tdp) {
1386 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1387 			    p);
1388 			NFSVOPUNLOCK(tdp, 0, p);
1389 		}
1390 	}
1391 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1392 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1393 	if (!nd->nd_repstat) {
1394 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1395 		if (error) {
1396 			if (tdp) {
1397 				if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1398 				    !(nd->nd_flag & ND_NFSV4))
1399 					nfsvno_unlockvfs(mp);
1400 				vrele(tdp);
1401 			}
1402 			vput(dp);
1403 			nfsvno_relpathbuf(&fromnd);
1404 			nfsvno_relpathbuf(&tond);
1405 			return (error);
1406 		}
1407 	}
1408 	if (nd->nd_repstat) {
1409 		if (nd->nd_flag & ND_NFSV3) {
1410 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1411 			    &fdiraft);
1412 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1413 			    &tdiraft);
1414 		}
1415 		if (tdp) {
1416 			if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1417 			    !(nd->nd_flag & ND_NFSV4))
1418 				nfsvno_unlockvfs(mp);
1419 			vrele(tdp);
1420 		}
1421 		vput(dp);
1422 		nfsvno_relpathbuf(&fromnd);
1423 		nfsvno_relpathbuf(&tond);
1424 		return (0);
1425 	}
1426 
1427 	/*
1428 	 * Done parsing, now down to business.
1429 	 */
1430 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1431 	if (nd->nd_repstat) {
1432 		if (nd->nd_flag & ND_NFSV3) {
1433 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1434 			    &fdiraft);
1435 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1436 			    &tdiraft);
1437 		}
1438 		if (fdirp)
1439 			vrele(fdirp);
1440 		if (tdp) {
1441 			if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1442 			    !(nd->nd_flag & ND_NFSV4))
1443 				nfsvno_unlockvfs(mp);
1444 			vrele(tdp);
1445 		}
1446 		nfsvno_relpathbuf(&tond);
1447 		return (0);
1448 	}
1449 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
1450 		tond.ni_cnd.cn_flags |= WILLBEDIR;
1451 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1452 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1453 	    nd->nd_flag, nd->nd_cred, p);
1454 	if (fdirp)
1455 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p);
1456 	if (tdirp)
1457 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p);
1458 	if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1459 	    !(nd->nd_flag & ND_NFSV4))
1460 		nfsvno_unlockvfs(mp);
1461 	if (fdirp)
1462 		vrele(fdirp);
1463 	if (tdirp)
1464 		vrele(tdirp);
1465 	if (nd->nd_flag & ND_NFSV3) {
1466 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1467 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1468 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1469 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1470 		*tl++ = newnfs_false;
1471 		txdr_hyper(fdirfor.na_filerev, tl);
1472 		tl += 2;
1473 		txdr_hyper(fdiraft.na_filerev, tl);
1474 		tl += 2;
1475 		*tl++ = newnfs_false;
1476 		txdr_hyper(tdirfor.na_filerev, tl);
1477 		tl += 2;
1478 		txdr_hyper(tdiraft.na_filerev, tl);
1479 	}
1480 	return (0);
1481 }
1482 
1483 /*
1484  * nfs link service
1485  */
1486 APPLESTATIC int
1487 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1488     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1489     struct nfsexstuff *toexp)
1490 {
1491 	struct nameidata named;
1492 	u_int32_t *tl;
1493 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1494 	vnode_t dirp = NULL, dp = NULL;
1495 	struct nfsvattr dirfor, diraft, at;
1496 	struct nfsexstuff tnes;
1497 	struct nfsrvfh dfh;
1498 	mount_t mp = NULL;
1499 	char *bufp;
1500 	u_long *hashp;
1501 
1502 	if (nd->nd_repstat) {
1503 		nfsrv_postopattr(nd, getret, &at);
1504 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1505 		return (0);
1506 	}
1507 	NFSVOPUNLOCK(vp, 0, p);
1508 	if (vnode_vtype(vp) == VDIR) {
1509 		if (nd->nd_flag & ND_NFSV4)
1510 			nd->nd_repstat = NFSERR_ISDIR;
1511 		else
1512 			nd->nd_repstat = NFSERR_INVAL;
1513 		if (tovp)
1514 			vrele(tovp);
1515 	} else if (vnode_vtype(vp) == VLNK) {
1516 		if (nd->nd_flag & ND_NFSV2)
1517 			nd->nd_repstat = NFSERR_INVAL;
1518 		else
1519 			nd->nd_repstat = NFSERR_NOTSUPP;
1520 		if (tovp)
1521 			vrele(tovp);
1522 	}
1523 	if (!nd->nd_repstat) {
1524 		if (nd->nd_flag & ND_NFSV4) {
1525 			dp = tovp;
1526 			tnes = *toexp;
1527 		} else {
1528 			error = nfsrv_mtofh(nd, &dfh);
1529 			if (error) {
1530 				vrele(vp);
1531 				/* tovp is always NULL unless NFSv4 */
1532 				return (error);
1533 			}
1534 			/* Won't lock vfs if already locked, mp == NULL */
1535 			tnes.nes_vfslocked = exp->nes_vfslocked;
1536 			nfsd_fhtovp(nd, &dfh, &dp, &tnes, &mp, 0, p);
1537 			if (dp)
1538 				NFSVOPUNLOCK(dp, 0, p);
1539 		}
1540 	}
1541 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT);
1542 	if (!nd->nd_repstat) {
1543 		nfsvno_setpathbuf(&named, &bufp, &hashp);
1544 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1545 		if (error) {
1546 			vrele(vp);
1547 			if (dp) {
1548 				if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1549 				    !(nd->nd_flag & ND_NFSV4))
1550 					nfsvno_unlockvfs(mp);
1551 				vrele(dp);
1552 			}
1553 			nfsvno_relpathbuf(&named);
1554 			return (error);
1555 		}
1556 		if (!nd->nd_repstat) {
1557 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1558 			    p, &dirp);
1559 		} else {
1560 			if (dp)
1561 				vrele(dp);
1562 			nfsvno_relpathbuf(&named);
1563 		}
1564 	}
1565 	if (dirp) {
1566 		if (nd->nd_flag & ND_NFSV2) {
1567 			vrele(dirp);
1568 			dirp = NULL;
1569 		} else {
1570 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1571 			    nd->nd_cred, p);
1572 		}
1573 	}
1574 	if (!nd->nd_repstat)
1575 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1576 	if (nd->nd_flag & ND_NFSV3)
1577 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1578 	if (dirp) {
1579 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
1580 		vrele(dirp);
1581 	}
1582 	if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1583 	    !(nd->nd_flag & ND_NFSV4))
1584 		nfsvno_unlockvfs(mp);
1585 	vrele(vp);
1586 	if (nd->nd_flag & ND_NFSV3) {
1587 		nfsrv_postopattr(nd, getret, &at);
1588 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1589 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1590 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1591 		*tl++ = newnfs_false;
1592 		txdr_hyper(dirfor.na_filerev, tl);
1593 		tl += 2;
1594 		txdr_hyper(diraft.na_filerev, tl);
1595 	}
1596 	return (0);
1597 }
1598 
1599 /*
1600  * nfs symbolic link service
1601  */
1602 APPLESTATIC int
1603 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1604     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1605     struct nfsexstuff *exp)
1606 {
1607 	struct nfsvattr nva, dirfor, diraft;
1608 	struct nameidata named;
1609 	int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1610 	vnode_t dirp = NULL;
1611 	char *bufp, *pathcp = NULL;
1612 	u_long *hashp;
1613 
1614 	if (nd->nd_repstat) {
1615 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1616 		return (0);
1617 	}
1618 	if (vpp)
1619 		*vpp = NULL;
1620 	NFSVNO_ATTRINIT(&nva);
1621 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1622 	    LOCKPARENT | SAVESTART);
1623 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1624 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1625 	if (!error && !nd->nd_repstat)
1626 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1627 	if (error) {
1628 		vrele(dp);
1629 		nfsvno_relpathbuf(&named);
1630 		return (error);
1631 	}
1632 	if (!nd->nd_repstat) {
1633 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1634 	} else {
1635 		vrele(dp);
1636 		nfsvno_relpathbuf(&named);
1637 	}
1638 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1639 		vrele(dirp);
1640 		dirp = NULL;
1641 	}
1642 
1643 	/*
1644 	 * And call nfsrvd_symlinksub() to do the common code. It will
1645 	 * return EBADRPC upon a parsing error, 0 otherwise.
1646 	 */
1647 	if (!nd->nd_repstat) {
1648 		if (dirp != NULL)
1649 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1650 			    p);
1651 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1652 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1653 		    pathcp, pathlen);
1654 	} else if (dirp != NULL) {
1655 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p);
1656 		vrele(dirp);
1657 	}
1658 	if (pathcp)
1659 		FREE(pathcp, M_TEMP);
1660 
1661 	if (nd->nd_flag & ND_NFSV3) {
1662 		if (!nd->nd_repstat) {
1663 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1664 			nfsrv_postopattr(nd, 0, &nva);
1665 		}
1666 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1667 	}
1668 	return (0);
1669 }
1670 
1671 /*
1672  * Common code for creating a symbolic link.
1673  */
1674 static void
1675 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1676     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1677     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1678     int *diraft_retp, nfsattrbit_t *attrbitp,
1679     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1680     int pathlen)
1681 {
1682 	u_int32_t *tl;
1683 
1684 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1685 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1686 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1687 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1688 		if (nd->nd_flag & ND_NFSV3) {
1689 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1690 			if (!nd->nd_repstat)
1691 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1692 				    nvap, nd->nd_cred, p);
1693 		}
1694 		if (vpp) {
1695 			NFSVOPUNLOCK(ndp->ni_vp, 0, p);
1696 			*vpp = ndp->ni_vp;
1697 		} else {
1698 			vput(ndp->ni_vp);
1699 		}
1700 	}
1701 	if (dirp) {
1702 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p);
1703 		vrele(dirp);
1704 	}
1705 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1706 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1707 		*tl++ = newnfs_false;
1708 		txdr_hyper(dirforp->na_filerev, tl);
1709 		tl += 2;
1710 		txdr_hyper(diraftp->na_filerev, tl);
1711 		(void) nfsrv_putattrbit(nd, attrbitp);
1712 	}
1713 }
1714 
1715 /*
1716  * nfs mkdir service
1717  */
1718 APPLESTATIC int
1719 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1720     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1721     struct nfsexstuff *exp)
1722 {
1723 	struct nfsvattr nva, dirfor, diraft;
1724 	struct nameidata named;
1725 	u_int32_t *tl;
1726 	int error, dirfor_ret = 1, diraft_ret = 1;
1727 	vnode_t dirp = NULL;
1728 	char *bufp;
1729 	u_long *hashp;
1730 
1731 	if (nd->nd_repstat) {
1732 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1733 		return (0);
1734 	}
1735 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT);
1736 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1737 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1738 	if (error) {
1739 		vrele(dp);
1740 		nfsvno_relpathbuf(&named);
1741 		return (error);
1742 	}
1743 	if (!nd->nd_repstat) {
1744 		NFSVNO_ATTRINIT(&nva);
1745 		if (nd->nd_flag & ND_NFSV3) {
1746 			error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1747 			if (error) {
1748 				vrele(dp);
1749 				nfsvno_relpathbuf(&named);
1750 				return (error);
1751 			}
1752 		} else {
1753 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1754 			nva.na_mode = nfstov_mode(*tl++);
1755 		}
1756 	}
1757 	if (!nd->nd_repstat) {
1758 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1759 	} else {
1760 		vrele(dp);
1761 		nfsvno_relpathbuf(&named);
1762 	}
1763 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1764 		vrele(dirp);
1765 		dirp = NULL;
1766 	}
1767 	if (nd->nd_repstat) {
1768 		if (dirp != NULL) {
1769 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1770 			    p);
1771 			vrele(dirp);
1772 		}
1773 		if (nd->nd_flag & ND_NFSV3)
1774 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1775 			    &diraft);
1776 		return (0);
1777 	}
1778 	if (dirp != NULL)
1779 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p);
1780 
1781 	/*
1782 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1783 	 */
1784 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1785 	    &diraft_ret, NULL, NULL, p, exp);
1786 
1787 	if (nd->nd_flag & ND_NFSV3) {
1788 		if (!nd->nd_repstat) {
1789 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1790 			nfsrv_postopattr(nd, 0, &nva);
1791 		}
1792 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1793 	} else if (!nd->nd_repstat) {
1794 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1795 		nfsrv_fillattr(nd, &nva);
1796 	}
1797 	return (0);
1798 nfsmout:
1799 	vrele(dp);
1800 	nfsvno_relpathbuf(&named);
1801 	return (error);
1802 }
1803 
1804 /*
1805  * Code common to mkdir for V2,3 and 4.
1806  */
1807 static void
1808 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1809     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1810     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1811     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1812     NFSPROC_T *p, struct nfsexstuff *exp)
1813 {
1814 	vnode_t vp;
1815 	u_int32_t *tl;
1816 
1817 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
1818 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1819 	    nd->nd_cred, p, exp);
1820 	if (!nd->nd_repstat) {
1821 		vp = ndp->ni_vp;
1822 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1823 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1824 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1825 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1826 			    p);
1827 		if (vpp && !nd->nd_repstat) {
1828 			NFSVOPUNLOCK(vp, 0, p);
1829 			*vpp = vp;
1830 		} else {
1831 			vput(vp);
1832 		}
1833 	}
1834 	if (dirp) {
1835 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p);
1836 		vrele(dirp);
1837 	}
1838 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1839 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1840 		*tl++ = newnfs_false;
1841 		txdr_hyper(dirforp->na_filerev, tl);
1842 		tl += 2;
1843 		txdr_hyper(diraftp->na_filerev, tl);
1844 		(void) nfsrv_putattrbit(nd, attrbitp);
1845 	}
1846 }
1847 
1848 /*
1849  * nfs commit service
1850  */
1851 APPLESTATIC int
1852 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1853     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1854 {
1855 	struct nfsvattr bfor, aft;
1856 	u_int32_t *tl;
1857 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
1858 	u_int64_t off;
1859 
1860 	if (nd->nd_repstat) {
1861 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1862 		return (0);
1863 	}
1864 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1865 	/*
1866 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
1867 	 * count parameters, so these arguments are useless (someday maybe).
1868 	 */
1869 	off = fxdr_hyper(tl);
1870 	tl += 2;
1871 	cnt = fxdr_unsigned(int, *tl);
1872 	if (nd->nd_flag & ND_NFSV3)
1873 		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p);
1874 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1875 	if (nd->nd_flag & ND_NFSV3) {
1876 		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p);
1877 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1878 	}
1879 	vput(vp);
1880 	if (!nd->nd_repstat) {
1881 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1882 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
1883 		*tl = txdr_unsigned(nfsboottime.tv_usec);
1884 	}
1885 	return (0);
1886 nfsmout:
1887 	vput(vp);
1888 	return (error);
1889 }
1890 
1891 /*
1892  * nfs statfs service
1893  */
1894 APPLESTATIC int
1895 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1896     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1897 {
1898 	struct statfs *sf;
1899 	u_int32_t *tl;
1900 	int getret = 1;
1901 	struct nfsvattr at;
1902 	struct statfs sfs;
1903 	u_quad_t tval;
1904 
1905 	if (nd->nd_repstat) {
1906 		nfsrv_postopattr(nd, getret, &at);
1907 		return (0);
1908 	}
1909 	sf = &sfs;
1910 	nd->nd_repstat = nfsvno_statfs(vp, sf);
1911 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1912 	vput(vp);
1913 	if (nd->nd_flag & ND_NFSV3)
1914 		nfsrv_postopattr(nd, getret, &at);
1915 	if (nd->nd_repstat)
1916 		return (0);
1917 	if (nd->nd_flag & ND_NFSV2) {
1918 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1919 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
1920 		*tl++ = txdr_unsigned(sf->f_bsize);
1921 		*tl++ = txdr_unsigned(sf->f_blocks);
1922 		*tl++ = txdr_unsigned(sf->f_bfree);
1923 		*tl = txdr_unsigned(sf->f_bavail);
1924 	} else {
1925 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1926 		tval = (u_quad_t)sf->f_blocks;
1927 		tval *= (u_quad_t)sf->f_bsize;
1928 		txdr_hyper(tval, tl); tl += 2;
1929 		tval = (u_quad_t)sf->f_bfree;
1930 		tval *= (u_quad_t)sf->f_bsize;
1931 		txdr_hyper(tval, tl); tl += 2;
1932 		tval = (u_quad_t)sf->f_bavail;
1933 		tval *= (u_quad_t)sf->f_bsize;
1934 		txdr_hyper(tval, tl); tl += 2;
1935 		tval = (u_quad_t)sf->f_files;
1936 		txdr_hyper(tval, tl); tl += 2;
1937 		tval = (u_quad_t)sf->f_ffree;
1938 		txdr_hyper(tval, tl); tl += 2;
1939 		tval = (u_quad_t)sf->f_ffree;
1940 		txdr_hyper(tval, tl); tl += 2;
1941 		*tl = 0;
1942 	}
1943 	return (0);
1944 }
1945 
1946 /*
1947  * nfs fsinfo service
1948  */
1949 APPLESTATIC int
1950 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1951     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1952 {
1953 	u_int32_t *tl;
1954 	struct nfsfsinfo fs;
1955 	int getret = 1;
1956 	struct nfsvattr at;
1957 
1958 	if (nd->nd_repstat) {
1959 		nfsrv_postopattr(nd, getret, &at);
1960 		return (0);
1961 	}
1962 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1963 	nfsvno_getfs(&fs, isdgram);
1964 	vput(vp);
1965 	nfsrv_postopattr(nd, getret, &at);
1966 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1967 	*tl++ = txdr_unsigned(fs.fs_rtmax);
1968 	*tl++ = txdr_unsigned(fs.fs_rtpref);
1969 	*tl++ = txdr_unsigned(fs.fs_rtmult);
1970 	*tl++ = txdr_unsigned(fs.fs_wtmax);
1971 	*tl++ = txdr_unsigned(fs.fs_wtpref);
1972 	*tl++ = txdr_unsigned(fs.fs_wtmult);
1973 	*tl++ = txdr_unsigned(fs.fs_dtpref);
1974 	txdr_hyper(fs.fs_maxfilesize, tl);
1975 	tl += 2;
1976 	txdr_nfsv3time(&fs.fs_timedelta, tl);
1977 	tl += 2;
1978 	*tl = txdr_unsigned(fs.fs_properties);
1979 	return (0);
1980 }
1981 
1982 /*
1983  * nfs pathconf service
1984  */
1985 APPLESTATIC int
1986 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
1987     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1988 {
1989 	struct nfsv3_pathconf *pc;
1990 	int getret = 1;
1991 	register_t linkmax, namemax, chownres, notrunc;
1992 	struct nfsvattr at;
1993 
1994 	if (nd->nd_repstat) {
1995 		nfsrv_postopattr(nd, getret, &at);
1996 		return (0);
1997 	}
1998 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
1999 	    nd->nd_cred, p);
2000 	if (!nd->nd_repstat)
2001 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2002 		    nd->nd_cred, p);
2003 	if (!nd->nd_repstat)
2004 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2005 		    &chownres, nd->nd_cred, p);
2006 	if (!nd->nd_repstat)
2007 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2008 		    nd->nd_cred, p);
2009 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
2010 	vput(vp);
2011 	nfsrv_postopattr(nd, getret, &at);
2012 	if (!nd->nd_repstat) {
2013 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2014 		pc->pc_linkmax = txdr_unsigned(linkmax);
2015 		pc->pc_namemax = txdr_unsigned(namemax);
2016 		pc->pc_notrunc = txdr_unsigned(notrunc);
2017 		pc->pc_chownrestricted = txdr_unsigned(chownres);
2018 
2019 		/*
2020 		 * These should probably be supported by VOP_PATHCONF(), but
2021 		 * until msdosfs is exportable (why would you want to?), the
2022 		 * Unix defaults should be ok.
2023 		 */
2024 		pc->pc_caseinsensitive = newnfs_false;
2025 		pc->pc_casepreserving = newnfs_true;
2026 	}
2027 	return (0);
2028 }
2029 
2030 /*
2031  * nfsv4 lock service
2032  */
2033 APPLESTATIC int
2034 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2035     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2036 {
2037 	u_int32_t *tl;
2038 	int i;
2039 	struct nfsstate *stp = NULL;
2040 	struct nfslock *lop;
2041 	struct nfslockconflict cf;
2042 	int error = 0;
2043 	u_short flags = NFSLCK_LOCK, lflags;
2044 	u_int64_t offset, len;
2045 	nfsv4stateid_t stateid;
2046 	nfsquad_t clientid;
2047 
2048 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2049 	i = fxdr_unsigned(int, *tl++);
2050 	switch (i) {
2051 	case NFSV4LOCKT_READW:
2052 		flags |= NFSLCK_BLOCKING;
2053 	case NFSV4LOCKT_READ:
2054 		lflags = NFSLCK_READ;
2055 		break;
2056 	case NFSV4LOCKT_WRITEW:
2057 		flags |= NFSLCK_BLOCKING;
2058 	case NFSV4LOCKT_WRITE:
2059 		lflags = NFSLCK_WRITE;
2060 		break;
2061 	default:
2062 		nd->nd_repstat = NFSERR_BADXDR;
2063 		goto nfsmout;
2064 	};
2065 	if (*tl++ == newnfs_true)
2066 		flags |= NFSLCK_RECLAIM;
2067 	offset = fxdr_hyper(tl);
2068 	tl += 2;
2069 	len = fxdr_hyper(tl);
2070 	tl += 2;
2071 	if (*tl == newnfs_true)
2072 		flags |= NFSLCK_OPENTOLOCK;
2073 	if (flags & NFSLCK_OPENTOLOCK) {
2074 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2075 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2076 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2077 			M_NFSDSTATE, M_WAITOK);
2078 		stp->ls_ownerlen = i;
2079 		stp->ls_op = nd->nd_rp;
2080 		stp->ls_seq = fxdr_unsigned(int, *tl++);
2081 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2082 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2083 			NFSX_STATEIDOTHER);
2084 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2085 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2086 		clientid.lval[0] = *tl++;
2087 		clientid.lval[1] = *tl++;
2088 		if (nd->nd_flag & ND_IMPLIEDCLID) {
2089 			if (nd->nd_clientid.qval != clientid.qval)
2090 				printf("EEK! multiple clids\n");
2091 		} else {
2092 			nd->nd_flag |= ND_IMPLIEDCLID;
2093 			nd->nd_clientid.qval = clientid.qval;
2094 		}
2095 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2096 		if (error)
2097 			goto nfsmout;
2098 	} else {
2099 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2100 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2101 			M_NFSDSTATE, M_WAITOK);
2102 		stp->ls_ownerlen = 0;
2103 		stp->ls_op = nd->nd_rp;
2104 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2105 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2106 			NFSX_STATEIDOTHER);
2107 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2108 		stp->ls_seq = fxdr_unsigned(int, *tl);
2109 		clientid.lval[0] = stp->ls_stateid.other[0];
2110 		clientid.lval[1] = stp->ls_stateid.other[1];
2111 		if (nd->nd_flag & ND_IMPLIEDCLID) {
2112 			if (nd->nd_clientid.qval != clientid.qval)
2113 				printf("EEK! multiple clids\n");
2114 		} else {
2115 			nd->nd_flag |= ND_IMPLIEDCLID;
2116 			nd->nd_clientid.qval = clientid.qval;
2117 		}
2118 	}
2119 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2120 		M_NFSDLOCK, M_WAITOK);
2121 	lop->lo_first = offset;
2122 	if (len == NFS64BITSSET) {
2123 		lop->lo_end = NFS64BITSSET;
2124 	} else {
2125 		lop->lo_end = offset + len;
2126 		if (lop->lo_end <= lop->lo_first)
2127 			nd->nd_repstat = NFSERR_INVAL;
2128 	}
2129 	lop->lo_flags = lflags;
2130 	stp->ls_flags = flags;
2131 	stp->ls_uid = nd->nd_cred->cr_uid;
2132 
2133 	/*
2134 	 * Do basic access checking.
2135 	 */
2136 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2137 	    if (vnode_vtype(vp) == VDIR)
2138 		nd->nd_repstat = NFSERR_ISDIR;
2139 	    else
2140 		nd->nd_repstat = NFSERR_INVAL;
2141 	}
2142 	if (!nd->nd_repstat) {
2143 	    if (lflags & NFSLCK_WRITE) {
2144 		nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_WRITEDATA,
2145 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2146 		    NFSACCCHK_VPISLOCKED);
2147 	    } else {
2148 		nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_READDATA,
2149 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2150 		    NFSACCCHK_VPISLOCKED);
2151 		if (nd->nd_repstat)
2152 		    nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_EXECUTE,
2153 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2154 			NFSACCCHK_VPISLOCKED);
2155 	    }
2156 	}
2157 
2158 	/*
2159 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2160 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
2161 	 * of nd_repstat, if it gets that far.
2162 	 */
2163 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2164 		&stateid, exp, nd, p);
2165 	if (lop)
2166 		FREE((caddr_t)lop, M_NFSDLOCK);
2167 	if (stp)
2168 		FREE((caddr_t)stp, M_NFSDSTATE);
2169 	if (!nd->nd_repstat) {
2170 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2171 		*tl++ = txdr_unsigned(stateid.seqid);
2172 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2173 	} else if (nd->nd_repstat == NFSERR_DENIED) {
2174 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2175 		txdr_hyper(cf.cl_first, tl);
2176 		tl += 2;
2177 		if (cf.cl_end == NFS64BITSSET)
2178 			len = NFS64BITSSET;
2179 		else
2180 			len = cf.cl_end - cf.cl_first;
2181 		txdr_hyper(len, tl);
2182 		tl += 2;
2183 		if (cf.cl_flags == NFSLCK_WRITE)
2184 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2185 		else
2186 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2187 		*tl++ = stateid.other[0];
2188 		*tl = stateid.other[1];
2189 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2190 	}
2191 	vput(vp);
2192 	return (0);
2193 nfsmout:
2194 	vput(vp);
2195 	if (stp)
2196 		free((caddr_t)stp, M_NFSDSTATE);
2197 	return (error);
2198 }
2199 
2200 /*
2201  * nfsv4 lock test service
2202  */
2203 APPLESTATIC int
2204 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2205     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2206 {
2207 	u_int32_t *tl;
2208 	int i;
2209 	struct nfsstate *stp = NULL;
2210 	struct nfslock lo, *lop = &lo;
2211 	struct nfslockconflict cf;
2212 	int error = 0;
2213 	nfsv4stateid_t stateid;
2214 	nfsquad_t clientid;
2215 	u_int64_t len;
2216 
2217 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2218 	i = fxdr_unsigned(int, *(tl + 7));
2219 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2220 	    M_NFSDSTATE, M_WAITOK);
2221 	stp->ls_ownerlen = i;
2222 	stp->ls_op = NULL;
2223 	stp->ls_flags = NFSLCK_TEST;
2224 	stp->ls_uid = nd->nd_cred->cr_uid;
2225 	i = fxdr_unsigned(int, *tl++);
2226 	switch (i) {
2227 	case NFSV4LOCKT_READW:
2228 		stp->ls_flags |= NFSLCK_BLOCKING;
2229 	case NFSV4LOCKT_READ:
2230 		lo.lo_flags = NFSLCK_READ;
2231 		break;
2232 	case NFSV4LOCKT_WRITEW:
2233 		stp->ls_flags |= NFSLCK_BLOCKING;
2234 	case NFSV4LOCKT_WRITE:
2235 		lo.lo_flags = NFSLCK_WRITE;
2236 		break;
2237 	default:
2238 		nd->nd_repstat = NFSERR_BADXDR;
2239 		goto nfsmout;
2240 	};
2241 	lo.lo_first = fxdr_hyper(tl);
2242 	tl += 2;
2243 	len = fxdr_hyper(tl);
2244 	if (len == NFS64BITSSET) {
2245 		lo.lo_end = NFS64BITSSET;
2246 	} else {
2247 		lo.lo_end = lo.lo_first + len;
2248 		if (lo.lo_end <= lo.lo_first)
2249 			nd->nd_repstat = NFSERR_INVAL;
2250 	}
2251 	tl += 2;
2252 	clientid.lval[0] = *tl++;
2253 	clientid.lval[1] = *tl;
2254 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2255 		if (nd->nd_clientid.qval != clientid.qval)
2256 			printf("EEK! multiple clids\n");
2257 	} else {
2258 		nd->nd_flag |= ND_IMPLIEDCLID;
2259 		nd->nd_clientid.qval = clientid.qval;
2260 	}
2261 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2262 	if (error)
2263 		goto nfsmout;
2264 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2265 	    if (vnode_vtype(vp) == VDIR)
2266 		nd->nd_repstat = NFSERR_ISDIR;
2267 	    else
2268 		nd->nd_repstat = NFSERR_INVAL;
2269 	}
2270 	if (!nd->nd_repstat)
2271 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2272 	    &stateid, exp, nd, p);
2273 	if (stp)
2274 		FREE((caddr_t)stp, M_NFSDSTATE);
2275 	if (nd->nd_repstat) {
2276 	    if (nd->nd_repstat == NFSERR_DENIED) {
2277 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2278 		txdr_hyper(cf.cl_first, tl);
2279 		tl += 2;
2280 		if (cf.cl_end == NFS64BITSSET)
2281 			len = NFS64BITSSET;
2282 		else
2283 			len = cf.cl_end - cf.cl_first;
2284 		txdr_hyper(len, tl);
2285 		tl += 2;
2286 		if (cf.cl_flags == NFSLCK_WRITE)
2287 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2288 		else
2289 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2290 		*tl++ = stp->ls_stateid.other[0];
2291 		*tl = stp->ls_stateid.other[1];
2292 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2293 	    }
2294 	}
2295 	vput(vp);
2296 	return (0);
2297 nfsmout:
2298 	vput(vp);
2299 	if (stp)
2300 		free((caddr_t)stp, M_NFSDSTATE);
2301 	return (error);
2302 }
2303 
2304 /*
2305  * nfsv4 unlock service
2306  */
2307 APPLESTATIC int
2308 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2309     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2310 {
2311 	u_int32_t *tl;
2312 	int i;
2313 	struct nfsstate *stp;
2314 	struct nfslock *lop;
2315 	int error = 0;
2316 	nfsv4stateid_t stateid;
2317 	nfsquad_t clientid;
2318 	u_int64_t len;
2319 
2320 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2321 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2322 	    M_NFSDSTATE, M_WAITOK);
2323 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2324 	    M_NFSDLOCK, M_WAITOK);
2325 	stp->ls_flags = NFSLCK_UNLOCK;
2326 	lop->lo_flags = NFSLCK_UNLOCK;
2327 	stp->ls_op = nd->nd_rp;
2328 	i = fxdr_unsigned(int, *tl++);
2329 	switch (i) {
2330 	case NFSV4LOCKT_READW:
2331 		stp->ls_flags |= NFSLCK_BLOCKING;
2332 	case NFSV4LOCKT_READ:
2333 		break;
2334 	case NFSV4LOCKT_WRITEW:
2335 		stp->ls_flags |= NFSLCK_BLOCKING;
2336 	case NFSV4LOCKT_WRITE:
2337 		break;
2338 	default:
2339 		nd->nd_repstat = NFSERR_BADXDR;
2340 		goto nfsmout;
2341 	};
2342 	stp->ls_ownerlen = 0;
2343 	stp->ls_uid = nd->nd_cred->cr_uid;
2344 	stp->ls_seq = fxdr_unsigned(int, *tl++);
2345 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2346 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2347 	    NFSX_STATEIDOTHER);
2348 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2349 	lop->lo_first = fxdr_hyper(tl);
2350 	tl += 2;
2351 	len = fxdr_hyper(tl);
2352 	if (len == NFS64BITSSET) {
2353 		lop->lo_end = NFS64BITSSET;
2354 	} else {
2355 		lop->lo_end = lop->lo_first + len;
2356 		if (lop->lo_end <= lop->lo_first)
2357 			nd->nd_repstat = NFSERR_INVAL;
2358 	}
2359 	clientid.lval[0] = stp->ls_stateid.other[0];
2360 	clientid.lval[1] = stp->ls_stateid.other[1];
2361 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2362 		if (nd->nd_clientid.qval != clientid.qval)
2363 			printf("EEK! multiple clids\n");
2364 	} else {
2365 		nd->nd_flag |= ND_IMPLIEDCLID;
2366 		nd->nd_clientid.qval = clientid.qval;
2367 	}
2368 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2369 	    if (vnode_vtype(vp) == VDIR)
2370 		nd->nd_repstat = NFSERR_ISDIR;
2371 	    else
2372 		nd->nd_repstat = NFSERR_INVAL;
2373 	}
2374 	/*
2375 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2376 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
2377 	 * value of nd_repstat, if it gets that far.
2378 	 */
2379 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2380 	    &stateid, exp, nd, p);
2381 	if (stp)
2382 		FREE((caddr_t)stp, M_NFSDSTATE);
2383 	if (lop)
2384 		free((caddr_t)lop, M_NFSDLOCK);
2385 	if (!nd->nd_repstat) {
2386 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2387 		*tl++ = txdr_unsigned(stateid.seqid);
2388 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2389 	}
2390 nfsmout:
2391 	vput(vp);
2392 	return (error);
2393 }
2394 
2395 /*
2396  * nfsv4 open service
2397  */
2398 APPLESTATIC int
2399 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2400     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2401     struct nfsexstuff *exp)
2402 {
2403 	u_int32_t *tl;
2404 	int i;
2405 	struct nfsstate *stp = NULL;
2406 	int error = 0, create, claim, exclusive_flag = 0;
2407 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2408 	int how = NFSCREATE_UNCHECKED;
2409 	u_char cverf[NFSX_VERF];
2410 	vnode_t vp = NULL, dirp = NULL;
2411 	struct nfsvattr nva, dirfor, diraft;
2412 	struct nameidata named;
2413 	nfsv4stateid_t stateid, delegstateid;
2414 	nfsattrbit_t attrbits;
2415 	nfsquad_t clientid;
2416 	char *bufp = NULL;
2417 	u_long *hashp;
2418 	NFSACL_T *aclp = NULL;
2419 
2420 #ifdef NFS4_ACL_EXTATTR_NAME
2421 	aclp = acl_alloc(M_WAITOK);
2422 	aclp->acl_cnt = 0;
2423 #endif
2424 	NFSZERO_ATTRBIT(&attrbits);
2425 	named.ni_startdir = NULL;
2426 	named.ni_cnd.cn_nameiop = 0;
2427 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2428 	i = fxdr_unsigned(int, *(tl + 5));
2429 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2430 	    M_NFSDSTATE, M_WAITOK);
2431 	stp->ls_ownerlen = i;
2432 	stp->ls_op = nd->nd_rp;
2433 	stp->ls_flags = NFSLCK_OPEN;
2434 	stp->ls_uid = nd->nd_cred->cr_uid;
2435 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2436 	i = fxdr_unsigned(int, *tl++);
2437 	switch (i) {
2438 	case NFSV4OPEN_ACCESSREAD:
2439 		stp->ls_flags |= NFSLCK_READACCESS;
2440 		break;
2441 	case NFSV4OPEN_ACCESSWRITE:
2442 		stp->ls_flags |= NFSLCK_WRITEACCESS;
2443 		break;
2444 	case NFSV4OPEN_ACCESSBOTH:
2445 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2446 		break;
2447 	default:
2448 		nd->nd_repstat = NFSERR_INVAL;
2449 	};
2450 	i = fxdr_unsigned(int, *tl++);
2451 	switch (i) {
2452 	case NFSV4OPEN_DENYNONE:
2453 		break;
2454 	case NFSV4OPEN_DENYREAD:
2455 		stp->ls_flags |= NFSLCK_READDENY;
2456 		break;
2457 	case NFSV4OPEN_DENYWRITE:
2458 		stp->ls_flags |= NFSLCK_WRITEDENY;
2459 		break;
2460 	case NFSV4OPEN_DENYBOTH:
2461 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2462 		break;
2463 	default:
2464 		nd->nd_repstat = NFSERR_INVAL;
2465 	};
2466 	clientid.lval[0] = *tl++;
2467 	clientid.lval[1] = *tl;
2468 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2469 		if (nd->nd_clientid.qval != clientid.qval)
2470 			printf("EEK! multiple clids\n");
2471 	} else {
2472 		nd->nd_flag |= ND_IMPLIEDCLID;
2473 		nd->nd_clientid.qval = clientid.qval;
2474 	}
2475 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2476 	if (error) {
2477 		vrele(dp);
2478 #ifdef NFS4_ACL_EXTATTR_NAME
2479 		acl_free(aclp);
2480 #endif
2481 		FREE((caddr_t)stp, M_NFSDSTATE);
2482 		return (error);
2483 	}
2484 	NFSVNO_ATTRINIT(&nva);
2485 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2486 	create = fxdr_unsigned(int, *tl);
2487 	if (!nd->nd_repstat)
2488 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p);
2489 	if (create == NFSV4OPEN_CREATE) {
2490 		nva.na_type = VREG;
2491 		nva.na_mode = 0;
2492 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2493 		how = fxdr_unsigned(int, *tl);
2494 		switch (how) {
2495 		case NFSCREATE_UNCHECKED:
2496 		case NFSCREATE_GUARDED:
2497 			error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2498 			if (error) {
2499 				vrele(dp);
2500 #ifdef NFS4_ACL_EXTATTR_NAME
2501 				acl_free(aclp);
2502 #endif
2503 				FREE((caddr_t)stp, M_NFSDSTATE);
2504 				return (error);
2505 			}
2506 			/*
2507 			 * If the na_gid being set is the same as that of
2508 			 * the directory it is going in, clear it, since
2509 			 * that is what will be set by default. This allows
2510 			 * a user that isn't in that group to do the create.
2511 			 */
2512 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2513 			    nva.na_gid == dirfor.na_gid)
2514 				NFSVNO_UNSET(&nva, gid);
2515 			if (!nd->nd_repstat)
2516 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2517 			break;
2518 		case NFSCREATE_EXCLUSIVE:
2519 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2520 			NFSBCOPY((caddr_t)tl, cverf, NFSX_VERF);
2521 			break;
2522 		default:
2523 			nd->nd_repstat = NFSERR_BADXDR;
2524 			vrele(dp);
2525 #ifdef NFS4_ACL_EXTATTR_NAME
2526 			acl_free(aclp);
2527 #endif
2528 			FREE((caddr_t)stp, M_NFSDSTATE);
2529 			return (0);
2530 		};
2531 	} else if (create != NFSV4OPEN_NOCREATE) {
2532 		nd->nd_repstat = NFSERR_BADXDR;
2533 		vrele(dp);
2534 #ifdef NFS4_ACL_EXTATTR_NAME
2535 		acl_free(aclp);
2536 #endif
2537 		FREE((caddr_t)stp, M_NFSDSTATE);
2538 		return (0);
2539 	}
2540 
2541 	/*
2542 	 * Now, handle the claim, which usually includes looking up a
2543 	 * name in the directory referenced by dp. The exception is
2544 	 * NFSV4OPEN_CLAIMPREVIOUS.
2545 	 */
2546 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2547 	claim = fxdr_unsigned(int, *tl);
2548 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2549 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2550 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2551 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2552 		stp->ls_flags |= NFSLCK_DELEGCUR;
2553 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2554 		stp->ls_flags |= NFSLCK_DELEGPREV;
2555 	}
2556 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2557 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2558 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2559 		    claim != NFSV4OPEN_CLAIMNULL)
2560 			nd->nd_repstat = NFSERR_INVAL;
2561 		if (nd->nd_repstat) {
2562 			nd->nd_repstat = nfsrv_opencheck(clientid,
2563 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
2564 			vrele(dp);
2565 #ifdef NFS4_ACL_EXTATTR_NAME
2566 			acl_free(aclp);
2567 #endif
2568 			FREE((caddr_t)stp, M_NFSDSTATE);
2569 			return (0);
2570 		}
2571 		if (create == NFSV4OPEN_CREATE)
2572 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2573 			LOCKPARENT | LOCKLEAF | SAVESTART);
2574 		else
2575 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2576 			LOCKLEAF | SAVESTART);
2577 		nfsvno_setpathbuf(&named, &bufp, &hashp);
2578 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2579 		if (error) {
2580 			vrele(dp);
2581 #ifdef NFS4_ACL_EXTATTR_NAME
2582 			acl_free(aclp);
2583 #endif
2584 			FREE((caddr_t)stp, M_NFSDSTATE);
2585 			nfsvno_relpathbuf(&named);
2586 			return (error);
2587 		}
2588 		if (!nd->nd_repstat) {
2589 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2590 			    p, &dirp);
2591 		} else {
2592 			vrele(dp);
2593 			nfsvno_relpathbuf(&named);
2594 		}
2595 		if (create == NFSV4OPEN_CREATE) {
2596 		    switch (how) {
2597 		    case NFSCREATE_UNCHECKED:
2598 			if (named.ni_vp) {
2599 				/*
2600 				 * Clear the setable attribute bits, except
2601 				 * for Size, if it is being truncated.
2602 				 */
2603 				NFSZERO_ATTRBIT(&attrbits);
2604 				if (NFSVNO_ISSETSIZE(&nva))
2605 					NFSSETBIT_ATTRBIT(&attrbits,
2606 					    NFSATTRBIT_SIZE);
2607 			}
2608 			break;
2609 		    case NFSCREATE_GUARDED:
2610 			if (named.ni_vp && !nd->nd_repstat)
2611 				nd->nd_repstat = EEXIST;
2612 			break;
2613 		    case NFSCREATE_EXCLUSIVE:
2614 			exclusive_flag = 1;
2615 			if (!named.ni_vp)
2616 				nva.na_mode = 0;
2617 		    };
2618 		}
2619 		nfsvno_open(nd, &named, clientid, &stateid, stp,
2620 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2621 		    nd->nd_cred, p, exp, &vp);
2622 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2623 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2624 		i = fxdr_unsigned(int, *tl);
2625 		switch (i) {
2626 		case NFSV4OPEN_DELEGATEREAD:
2627 			stp->ls_flags |= NFSLCK_DELEGREAD;
2628 			break;
2629 		case NFSV4OPEN_DELEGATEWRITE:
2630 			stp->ls_flags |= NFSLCK_DELEGWRITE;
2631 		case NFSV4OPEN_DELEGATENONE:
2632 			break;
2633 		default:
2634 			nd->nd_repstat = NFSERR_BADXDR;
2635 			vrele(dp);
2636 #ifdef NFS4_ACL_EXTATTR_NAME
2637 			acl_free(aclp);
2638 #endif
2639 			FREE((caddr_t)stp, M_NFSDSTATE);
2640 			return (0);
2641 		};
2642 		stp->ls_flags |= NFSLCK_RECLAIM;
2643 		vp = dp;
2644 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
2645 		nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp,
2646 		    nd, p, nd->nd_repstat);
2647 	} else {
2648 		nd->nd_repstat = NFSERR_BADXDR;
2649 		vrele(dp);
2650 #ifdef NFS4_ACL_EXTATTR_NAME
2651 		acl_free(aclp);
2652 #endif
2653 		FREE((caddr_t)stp, M_NFSDSTATE);
2654 		return (0);
2655 	}
2656 
2657 	/*
2658 	 * Do basic access checking.
2659 	 */
2660 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2661 	    if (vnode_vtype(vp) == VDIR)
2662 		nd->nd_repstat = NFSERR_ISDIR;
2663 	    else if (vnode_vtype(vp) == VLNK)
2664 		nd->nd_repstat = NFSERR_SYMLINK;
2665 	    else
2666 		nd->nd_repstat = NFSERR_INVAL;
2667 	}
2668 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2669 	    nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_WRITEDATA, nd->nd_cred,
2670 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED);
2671 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2672 	    nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_READDATA, nd->nd_cred,
2673 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED);
2674 	    if (nd->nd_repstat)
2675 		nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_EXECUTE,
2676 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2677 		    NFSACCCHK_VPISLOCKED);
2678 	}
2679 
2680 	if (!nd->nd_repstat)
2681 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p);
2682 	if (!nd->nd_repstat && exclusive_flag &&
2683 	    NFSBCMP(cverf, (caddr_t)&nva.na_atime, NFSX_VERF))
2684 		nd->nd_repstat = EEXIST;
2685 	/*
2686 	 * Do the open locking/delegation stuff.
2687 	 */
2688 	if (!nd->nd_repstat)
2689 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2690 		&delegstateid, &rflags, exp, p, nva.na_filerev);
2691 
2692 	/*
2693 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2694 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2695 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
2696 	 */
2697 	if (vp)
2698 		NFSVOPUNLOCK(vp, 0, p);
2699 	if (stp)
2700 		FREE((caddr_t)stp, M_NFSDSTATE);
2701 	if (!nd->nd_repstat && dirp)
2702 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
2703 	if (!nd->nd_repstat) {
2704 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2705 		*tl++ = txdr_unsigned(stateid.seqid);
2706 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2707 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2708 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2709 			*tl++ = newnfs_true;
2710 			*tl++ = 0;
2711 			*tl++ = 0;
2712 			*tl++ = 0;
2713 			*tl++ = 0;
2714 		} else {
2715 			*tl++ = newnfs_false;	/* Since dirp is not locked */
2716 			txdr_hyper(dirfor.na_filerev, tl);
2717 			tl += 2;
2718 			txdr_hyper(diraft.na_filerev, tl);
2719 			tl += 2;
2720 		}
2721 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2722 		(void) nfsrv_putattrbit(nd, &attrbits);
2723 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2724 		if (rflags & NFSV4OPEN_READDELEGATE)
2725 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2726 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2727 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2728 		else
2729 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2730 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2731 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2732 			*tl++ = txdr_unsigned(delegstateid.seqid);
2733 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2734 			    NFSX_STATEIDOTHER);
2735 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2736 			if (rflags & NFSV4OPEN_RECALL)
2737 				*tl = newnfs_true;
2738 			else
2739 				*tl = newnfs_false;
2740 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2741 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2742 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2743 				txdr_hyper(nva.na_size, tl);
2744 			}
2745 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2746 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2747 			*tl++ = txdr_unsigned(0x0);
2748 			acemask = NFSV4ACE_ALLFILESMASK;
2749 			if (nva.na_mode & S_IRUSR)
2750 			    acemask |= NFSV4ACE_READMASK;
2751 			if (nva.na_mode & S_IWUSR)
2752 			    acemask |= NFSV4ACE_WRITEMASK;
2753 			if (nva.na_mode & S_IXUSR)
2754 			    acemask |= NFSV4ACE_EXECUTEMASK;
2755 			*tl = txdr_unsigned(acemask);
2756 			(void) nfsm_strtom(nd, "OWNER@", 6);
2757 		}
2758 		*vpp = vp;
2759 	} else if (vp) {
2760 		vrele(vp);
2761 	}
2762 	if (dirp)
2763 		vrele(dirp);
2764 #ifdef NFS4_ACL_EXTATTR_NAME
2765 	acl_free(aclp);
2766 #endif
2767 	return (0);
2768 nfsmout:
2769 	vrele(dp);
2770 #ifdef NFS4_ACL_EXTATTR_NAME
2771 	acl_free(aclp);
2772 #endif
2773 	if (stp)
2774 		FREE((caddr_t)stp, M_NFSDSTATE);
2775 	return (error);
2776 }
2777 
2778 /*
2779  * nfsv4 close service
2780  */
2781 APPLESTATIC int
2782 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2783     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2784 {
2785 	u_int32_t *tl;
2786 	struct nfsstate st, *stp = &st;
2787 	int error = 0;
2788 	nfsv4stateid_t stateid;
2789 	nfsquad_t clientid;
2790 
2791 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2792 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2793 	stp->ls_ownerlen = 0;
2794 	stp->ls_op = nd->nd_rp;
2795 	stp->ls_uid = nd->nd_cred->cr_uid;
2796 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2797 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2798 	    NFSX_STATEIDOTHER);
2799 	stp->ls_flags = NFSLCK_CLOSE;
2800 	clientid.lval[0] = stp->ls_stateid.other[0];
2801 	clientid.lval[1] = stp->ls_stateid.other[1];
2802 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2803 		if (nd->nd_clientid.qval != clientid.qval)
2804 			printf("EEK! multiple clids\n");
2805 	} else {
2806 		nd->nd_flag |= ND_IMPLIEDCLID;
2807 		nd->nd_clientid.qval = clientid.qval;
2808 	}
2809 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2810 	vput(vp);
2811 	if (!nd->nd_repstat) {
2812 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2813 		*tl++ = txdr_unsigned(stateid.seqid);
2814 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2815 	}
2816 	return (0);
2817 nfsmout:
2818 	vput(vp);
2819 	return (error);
2820 }
2821 
2822 /*
2823  * nfsv4 delegpurge service
2824  */
2825 APPLESTATIC int
2826 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2827     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2828 {
2829 	u_int32_t *tl;
2830 	int error = 0;
2831 	nfsquad_t clientid;
2832 
2833 	if ((!nfs_rootfhset && !nfsv4root_set) ||
2834 	    nfsd_checkrootexp(nd)) {
2835 		nd->nd_repstat = NFSERR_WRONGSEC;
2836 		return (0);
2837 	}
2838 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2839 	clientid.lval[0] = *tl++;
2840 	clientid.lval[1] = *tl;
2841 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2842 		if (nd->nd_clientid.qval != clientid.qval)
2843 			printf("EEK! multiple clids\n");
2844 	} else {
2845 		nd->nd_flag |= ND_IMPLIEDCLID;
2846 		nd->nd_clientid.qval = clientid.qval;
2847 	}
2848 	nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2849 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2850 nfsmout:
2851 	return (error);
2852 }
2853 
2854 /*
2855  * nfsv4 delegreturn service
2856  */
2857 APPLESTATIC int
2858 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2859     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2860 {
2861 	u_int32_t *tl;
2862 	int error = 0;
2863 	nfsv4stateid_t stateid;
2864 	nfsquad_t clientid;
2865 
2866 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2867 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2868 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2869 	clientid.lval[0] = stateid.other[0];
2870 	clientid.lval[1] = stateid.other[1];
2871 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2872 		if (nd->nd_clientid.qval != clientid.qval)
2873 			printf("EEK! multiple clids\n");
2874 	} else {
2875 		nd->nd_flag |= ND_IMPLIEDCLID;
2876 		nd->nd_clientid.qval = clientid.qval;
2877 	}
2878 	nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2879 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2880 nfsmout:
2881 	vput(vp);
2882 	return (error);
2883 }
2884 
2885 /*
2886  * nfsv4 get file handle service
2887  */
2888 APPLESTATIC int
2889 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2890     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2891 {
2892 	fhandle_t fh;
2893 
2894 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2895 	vput(vp);
2896 	if (!nd->nd_repstat)
2897 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2898 	return (0);
2899 }
2900 
2901 /*
2902  * nfsv4 open confirm service
2903  */
2904 APPLESTATIC int
2905 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2906     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2907 {
2908 	u_int32_t *tl;
2909 	struct nfsstate st, *stp = &st;
2910 	int error = 0;
2911 	nfsv4stateid_t stateid;
2912 	nfsquad_t clientid;
2913 
2914 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2915 	stp->ls_ownerlen = 0;
2916 	stp->ls_op = nd->nd_rp;
2917 	stp->ls_uid = nd->nd_cred->cr_uid;
2918 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2919 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2920 	    NFSX_STATEIDOTHER);
2921 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2922 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2923 	stp->ls_flags = NFSLCK_CONFIRM;
2924 	clientid.lval[0] = stp->ls_stateid.other[0];
2925 	clientid.lval[1] = stp->ls_stateid.other[1];
2926 	if (nd->nd_flag & ND_IMPLIEDCLID) {
2927 		if (nd->nd_clientid.qval != clientid.qval)
2928 			printf("EEK! multiple clids\n");
2929 	} else {
2930 		nd->nd_flag |= ND_IMPLIEDCLID;
2931 		nd->nd_clientid.qval = clientid.qval;
2932 	}
2933 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2934 	if (!nd->nd_repstat) {
2935 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2936 		*tl++ = txdr_unsigned(stateid.seqid);
2937 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2938 	}
2939 nfsmout:
2940 	vput(vp);
2941 	return (error);
2942 }
2943 
2944 /*
2945  * nfsv4 open downgrade service
2946  */
2947 APPLESTATIC int
2948 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
2949     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2950 {
2951 	u_int32_t *tl;
2952 	int i;
2953 	struct nfsstate st, *stp = &st;
2954 	int error = 0;
2955 	nfsv4stateid_t stateid;
2956 	nfsquad_t clientid;
2957 
2958 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
2959 	stp->ls_ownerlen = 0;
2960 	stp->ls_op = nd->nd_rp;
2961 	stp->ls_uid = nd->nd_cred->cr_uid;
2962 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2963 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2964 	    NFSX_STATEIDOTHER);
2965 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2966 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2967 	i = fxdr_unsigned(int, *tl++);
2968 	switch (i) {
2969 	case NFSV4OPEN_ACCESSREAD:
2970 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
2971 		break;
2972 	case NFSV4OPEN_ACCESSWRITE:
2973 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
2974 		break;
2975 	case NFSV4OPEN_ACCESSBOTH:
2976 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
2977 		    NFSLCK_DOWNGRADE);
2978 		break;
2979 	default:
2980 		nd->nd_repstat = NFSERR_BADXDR;
2981 	};
2982 	i = fxdr_unsigned(int, *tl);
2983 	switch (i) {
2984 	case NFSV4OPEN_DENYNONE:
2985 		break;
2986 	case NFSV4OPEN_DENYREAD:
2987 		stp->ls_flags |= NFSLCK_READDENY;
2988 		break;
2989 	case NFSV4OPEN_DENYWRITE:
2990 		stp->ls_flags |= NFSLCK_WRITEDENY;
2991 		break;
2992 	case NFSV4OPEN_DENYBOTH:
2993 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2994 		break;
2995 	default:
2996 		nd->nd_repstat = NFSERR_BADXDR;
2997 	};
2998 
2999 	clientid.lval[0] = stp->ls_stateid.other[0];
3000 	clientid.lval[1] = stp->ls_stateid.other[1];
3001 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3002 		if (nd->nd_clientid.qval != clientid.qval)
3003 			printf("EEK! multiple clids\n");
3004 	} else {
3005 		nd->nd_flag |= ND_IMPLIEDCLID;
3006 		nd->nd_clientid.qval = clientid.qval;
3007 	}
3008 	if (!nd->nd_repstat)
3009 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3010 		    nd, p);
3011 	if (!nd->nd_repstat) {
3012 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3013 		*tl++ = txdr_unsigned(stateid.seqid);
3014 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3015 	}
3016 nfsmout:
3017 	vput(vp);
3018 	return (error);
3019 }
3020 
3021 /*
3022  * nfsv4 renew lease service
3023  */
3024 APPLESTATIC int
3025 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3026     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3027 {
3028 	u_int32_t *tl;
3029 	int error = 0;
3030 	nfsquad_t clientid;
3031 
3032 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3033 	    nfsd_checkrootexp(nd)) {
3034 		nd->nd_repstat = NFSERR_WRONGSEC;
3035 		return (0);
3036 	}
3037 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3038 	clientid.lval[0] = *tl++;
3039 	clientid.lval[1] = *tl;
3040 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3041 		if (nd->nd_clientid.qval != clientid.qval)
3042 			printf("EEK! multiple clids\n");
3043 	} else {
3044 		nd->nd_flag |= ND_IMPLIEDCLID;
3045 		nd->nd_clientid.qval = clientid.qval;
3046 	}
3047 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3048 	    NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3049 nfsmout:
3050 	return (error);
3051 }
3052 
3053 /*
3054  * nfsv4 security info service
3055  */
3056 APPLESTATIC int
3057 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3058     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3059 {
3060 	u_int32_t *tl;
3061 	int len;
3062 	struct nameidata named;
3063 	vnode_t dirp = NULL, vp;
3064 	struct nfsrvfh fh;
3065 	struct nfsexstuff retnes;
3066 	mount_t mp;
3067 	u_int32_t *sizp;
3068 	int error, savflag, i;
3069 	char *bufp;
3070 	u_long *hashp;
3071 
3072 	/*
3073 	 * All this just to get the export flags for the name.
3074 	 */
3075 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3076 	    LOCKLEAF | SAVESTART);
3077 	nfsvno_setpathbuf(&named, &bufp, &hashp);
3078 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3079 	if (error) {
3080 		vput(dp);
3081 		nfsvno_relpathbuf(&named);
3082 		return (error);
3083 	}
3084 	if (!nd->nd_repstat) {
3085 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3086 	} else {
3087 		vput(dp);
3088 		nfsvno_relpathbuf(&named);
3089 	}
3090 	if (dirp)
3091 		vrele(dirp);
3092 	if (nd->nd_repstat)
3093 		return (0);
3094 	vrele(named.ni_startdir);
3095 	nfsvno_relpathbuf(&named);
3096 	fh.nfsrvfh_len = NFSX_MYFH;
3097 	vp = named.ni_vp;
3098 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3099 	mp = vnode_mount(vp);	/* so it won't try to re-lock filesys */
3100 	retnes.nes_vfslocked = exp->nes_vfslocked;
3101 	vput(vp);
3102 	savflag = nd->nd_flag;
3103 	if (!nd->nd_repstat) {
3104 		nfsd_fhtovp(nd, &fh, &vp, &retnes, &mp, 0, p);
3105 		if (vp)
3106 			vput(vp);
3107 	}
3108 	nd->nd_flag = savflag;
3109 	if (nd->nd_repstat)
3110 		return (0);
3111 
3112 	/*
3113 	 * Finally have the export flags for name, so we can create
3114 	 * the security info.
3115 	 */
3116 	len = 0;
3117 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3118 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
3119 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
3120 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3121 			*tl = txdr_unsigned(RPCAUTH_UNIX);
3122 			len++;
3123 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3124 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3125 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3126 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3127 			    nfsgss_mechlist[KERBV_MECH].len);
3128 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3129 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3130 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3131 			len++;
3132 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3133 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3134 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3135 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3136 			    nfsgss_mechlist[KERBV_MECH].len);
3137 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3138 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3139 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3140 			len++;
3141 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3142 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3143 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3144 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3145 			    nfsgss_mechlist[KERBV_MECH].len);
3146 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3147 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3148 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3149 			len++;
3150 		}
3151 	}
3152 	*sizp = txdr_unsigned(len);
3153 	return (0);
3154 }
3155 
3156 /*
3157  * nfsv4 set client id service
3158  */
3159 APPLESTATIC int
3160 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3161     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3162 {
3163 	u_int32_t *tl;
3164 	int i;
3165 	int error = 0, idlen;
3166 	struct nfsclient *clp = NULL;
3167 	struct sockaddr_in *rad;
3168 	u_char *verf, *ucp, *ucp2, addrbuf[24];
3169 	nfsquad_t clientid, confirm;
3170 
3171 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3172 	    nfsd_checkrootexp(nd)) {
3173 		nd->nd_repstat = NFSERR_WRONGSEC;
3174 		return (0);
3175 	}
3176 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3177 	verf = (u_char *)tl;
3178 	tl += (NFSX_VERF / NFSX_UNSIGNED);
3179 	i = fxdr_unsigned(int, *tl);
3180 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3181 		nd->nd_repstat = NFSERR_BADXDR;
3182 		return (error);
3183 	}
3184 	idlen = i;
3185 	if (nd->nd_flag & ND_GSS)
3186 		i += nd->nd_princlen;
3187 	MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3188 	    M_NFSDCLIENT, M_WAITOK);
3189 	NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3190 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3191 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3192 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3193 	clp->lc_req.nr_cred = NULL;
3194 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3195 	clp->lc_idlen = idlen;
3196 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3197 	if (error)
3198 		goto nfsmout;
3199 	if (nd->nd_flag & ND_GSS) {
3200 		clp->lc_flags = LCL_GSS;
3201 		if (nd->nd_flag & ND_GSSINTEGRITY)
3202 			clp->lc_flags |= LCL_GSSINTEGRITY;
3203 		else if (nd->nd_flag & ND_GSSPRIVACY)
3204 			clp->lc_flags |= LCL_GSSPRIVACY;
3205 	} else {
3206 		clp->lc_flags = 0;
3207 	}
3208 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3209 		clp->lc_flags |= LCL_NAME;
3210 		clp->lc_namelen = nd->nd_princlen;
3211 		clp->lc_name = &clp->lc_id[idlen];
3212 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3213 	} else {
3214 		clp->lc_uid = nd->nd_cred->cr_uid;
3215 		clp->lc_gid = nd->nd_cred->cr_gid;
3216 	}
3217 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3218 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3219 	error = nfsrv_getclientipaddr(nd, clp);
3220 	if (error)
3221 		goto nfsmout;
3222 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3223 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3224 
3225 	/*
3226 	 * nfsrv_setclient() does the actual work of adding it to the
3227 	 * client list. If there is no error, the structure has been
3228 	 * linked into the client list and clp should no longer be used
3229 	 * here. When an error is returned, it has not been linked in,
3230 	 * so it should be free'd.
3231 	 */
3232 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3233 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3234 		if (clp->lc_flags & LCL_TCPCALLBACK)
3235 			(void) nfsm_strtom(nd, "tcp", 3);
3236 		else
3237 			(void) nfsm_strtom(nd, "udp", 3);
3238 		rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3239 		ucp = (u_char *)&rad->sin_addr.s_addr;
3240 		ucp2 = (u_char *)&rad->sin_port;
3241 		sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3242 		    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3243 		    ucp2[0] & 0xff, ucp2[1] & 0xff);
3244 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3245 	}
3246 	if (clp) {
3247 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3248 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3249 		free((caddr_t)clp, M_NFSDCLIENT);
3250 	}
3251 	if (!nd->nd_repstat) {
3252 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3253 		*tl++ = clientid.lval[0];
3254 		*tl++ = clientid.lval[1];
3255 		*tl++ = confirm.lval[0];
3256 		*tl = confirm.lval[1];
3257 	}
3258 	return (0);
3259 nfsmout:
3260 	if (clp) {
3261 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3262 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3263 		free((caddr_t)clp, M_NFSDCLIENT);
3264 	}
3265 	return (error);
3266 }
3267 
3268 /*
3269  * nfsv4 set client id confirm service
3270  */
3271 APPLESTATIC int
3272 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3273     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3274     __unused struct nfsexstuff *exp)
3275 {
3276 	u_int32_t *tl;
3277 	int error = 0;
3278 	nfsquad_t clientid, confirm;
3279 
3280 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3281 	    nfsd_checkrootexp(nd)) {
3282 		nd->nd_repstat = NFSERR_WRONGSEC;
3283 		return (0);
3284 	}
3285 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3286 	clientid.lval[0] = *tl++;
3287 	clientid.lval[1] = *tl++;
3288 	confirm.lval[0] = *tl++;
3289 	confirm.lval[1] = *tl;
3290 
3291 	/*
3292 	 * nfsrv_getclient() searches the client list for a match and
3293 	 * returns the appropriate NFSERR status.
3294 	 */
3295 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3296 	    NULL, confirm, nd, p);
3297 nfsmout:
3298 	return (error);
3299 }
3300 
3301 /*
3302  * nfsv4 verify service
3303  */
3304 APPLESTATIC int
3305 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3306     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3307 {
3308 	int error = 0, ret, fhsize = NFSX_MYFH;
3309 	struct nfsvattr nva;
3310 	struct statfs sf;
3311 	struct nfsfsinfo fs;
3312 	fhandle_t fh;
3313 
3314 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p);
3315 	if (!nd->nd_repstat)
3316 		nd->nd_repstat = nfsvno_statfs(vp, &sf);
3317 	if (!nd->nd_repstat)
3318 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3319 	if (!nd->nd_repstat) {
3320 		nfsvno_getfs(&fs, isdgram);
3321 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3322 		    &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3323 		if (!error) {
3324 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3325 				if (ret == 0)
3326 					nd->nd_repstat = NFSERR_SAME;
3327 				else if (ret != NFSERR_NOTSAME)
3328 					nd->nd_repstat = ret;
3329 			} else if (ret)
3330 				nd->nd_repstat = ret;
3331 		}
3332 	}
3333 	vput(vp);
3334 	return (error);
3335 }
3336 
3337 /*
3338  * nfs openattr rpc
3339  */
3340 APPLESTATIC int
3341 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3342     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3343     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3344 {
3345 	u_int32_t *tl;
3346 	int error = 0, createdir;
3347 
3348 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3349 	createdir = fxdr_unsigned(int, *tl);
3350 	nd->nd_repstat = NFSERR_NOTSUPP;
3351 nfsmout:
3352 	vrele(dp);
3353 	return (error);
3354 }
3355 
3356 /*
3357  * nfsv4 release lock owner service
3358  */
3359 APPLESTATIC int
3360 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3361     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3362 {
3363 	u_int32_t *tl;
3364 	struct nfsstate *stp = NULL;
3365 	int error = 0, len;
3366 	nfsquad_t clientid;
3367 
3368 	if ((!nfs_rootfhset && !nfsv4root_set) ||
3369 	    nfsd_checkrootexp(nd)) {
3370 		nd->nd_repstat = NFSERR_WRONGSEC;
3371 		return (0);
3372 	}
3373 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3374 	len = fxdr_unsigned(int, *(tl + 2));
3375 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3376 	    M_NFSDSTATE, M_WAITOK);
3377 	stp->ls_ownerlen = len;
3378 	stp->ls_op = NULL;
3379 	stp->ls_flags = NFSLCK_RELEASE;
3380 	stp->ls_uid = nd->nd_cred->cr_uid;
3381 	clientid.lval[0] = *tl++;
3382 	clientid.lval[1] = *tl;
3383 	if (nd->nd_flag & ND_IMPLIEDCLID) {
3384 		if (nd->nd_clientid.qval != clientid.qval)
3385 			printf("EEK! multiple clids\n");
3386 	} else {
3387 		nd->nd_flag |= ND_IMPLIEDCLID;
3388 		nd->nd_clientid.qval = clientid.qval;
3389 	}
3390 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
3391 	if (error)
3392 		goto nfsmout;
3393 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3394 	FREE((caddr_t)stp, M_NFSDSTATE);
3395 	return (0);
3396 nfsmout:
3397 	if (stp)
3398 		free((caddr_t)stp, M_NFSDSTATE);
3399 	return (error);
3400 }
3401