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