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