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