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