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