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