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