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