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