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