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