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