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