2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 #include "opt_inet6.h"
42 * nfs version 2, 3 and 4 server calls to vnode ops
43 * - these routines generally have 3 phases
44 * 1 - break down and validate rpc request in mbuf list
45 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
46 * function in nfsd_port.c
47 * 3 - build the rpc reply in an mbuf list
48 * For nfsv4, these functions are called for each Op within the Compound RPC.
52 #include <fs/nfs/nfsport.h>
55 extern u_int32_t newnfs_false, newnfs_true;
56 extern enum vtype nv34tov_type[8];
57 extern struct timeval nfsboottime;
58 extern int nfs_rootfhset;
59 extern int nfsrv_enable_crossmntpt;
60 extern int nfsrv_statehashsize;
61 extern int nfsrv_layouthashsize;
62 extern time_t nfsdev_time;
63 extern volatile int nfsrv_devidcnt;
64 extern int nfsd_debuglevel;
65 extern u_long sb_max_adj;
66 extern int nfsrv_pnfsatime;
67 extern int nfsrv_maxpnfsmirror;
68 #endif /* !APPLEKEXT */
70 static int nfs_async = 0;
71 SYSCTL_DECL(_vfs_nfsd);
72 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
73 "Tell client that writes were synced even though they were not");
74 extern int nfsrv_doflexfile;
75 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
76 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
79 * This list defines the GSS mechanisms supported.
80 * (Don't ask me how you get these strings from the RFC stuff like
81 * iso(1), org(3)... but someone did it, so I don't need to know.)
83 static struct nfsgss_mechlist nfsgss_mechlist[] = {
84 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
89 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
90 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
91 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
92 int *diraft_retp, nfsattrbit_t *attrbitp,
93 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
95 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
96 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
97 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
98 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
99 NFSPROC_T *p, struct nfsexstuff *exp);
102 * nfs access service (not a part of NFS V2)
105 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
106 vnode_t vp, struct nfsexstuff *exp)
109 int getret, error = 0;
111 u_int32_t testmode, nfsmode, supported = 0;
113 struct thread *p = curthread;
115 if (nd->nd_repstat) {
116 nfsrv_postopattr(nd, 1, &nva);
119 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
120 nfsmode = fxdr_unsigned(u_int32_t, *tl);
121 if ((nd->nd_flag & ND_NFSV4) &&
122 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
123 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
124 NFSACCESS_EXECUTE))) {
125 nd->nd_repstat = NFSERR_INVAL;
129 if (nfsmode & NFSACCESS_READ) {
130 supported |= NFSACCESS_READ;
131 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
132 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
133 nfsmode &= ~NFSACCESS_READ;
135 if (nfsmode & NFSACCESS_MODIFY) {
136 supported |= NFSACCESS_MODIFY;
137 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
138 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
139 nfsmode &= ~NFSACCESS_MODIFY;
141 if (nfsmode & NFSACCESS_EXTEND) {
142 supported |= NFSACCESS_EXTEND;
143 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
144 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
145 nfsmode &= ~NFSACCESS_EXTEND;
147 if (nfsmode & NFSACCESS_DELETE) {
148 supported |= NFSACCESS_DELETE;
149 if (vp->v_type == VDIR)
150 deletebit = VDELETE_CHILD;
153 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
154 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
155 nfsmode &= ~NFSACCESS_DELETE;
157 if (vnode_vtype(vp) == VDIR)
158 testmode = NFSACCESS_LOOKUP;
160 testmode = NFSACCESS_EXECUTE;
161 if (nfsmode & testmode) {
162 supported |= (nfsmode & testmode);
163 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
164 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
165 nfsmode &= ~testmode;
167 nfsmode &= supported;
168 if (nd->nd_flag & ND_NFSV3) {
169 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
170 nfsrv_postopattr(nd, getret, &nva);
173 if (nd->nd_flag & ND_NFSV4) {
174 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
175 *tl++ = txdr_unsigned(supported);
177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
178 *tl = txdr_unsigned(nfsmode);
185 NFSEXITCODE2(error, nd);
190 * nfs getattr service
193 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
194 vnode_t vp, __unused struct nfsexstuff *exp)
198 int at_root = 0, error = 0, supports_nfsv4acls;
199 struct nfsreferral *refp;
200 nfsattrbit_t attrbits, tmpbits;
202 struct vnode *tvp = NULL;
204 uint64_t mounted_on_fileno = 0;
206 struct thread *p = curthread;
210 if (nd->nd_flag & ND_NFSV4) {
211 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
218 * Check for a referral.
220 refp = nfsv4root_getreferral(vp, NULL, 0);
222 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
227 if (nd->nd_repstat == 0) {
229 NFSSET_ATTRBIT(&tmpbits, &attrbits);
232 * GETATTR with write-only attr time_access_set and time_modify_set
233 * should return NFS4ERR_INVAL.
235 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
236 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
237 error = NFSERR_INVAL;
241 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
242 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
243 accmode |= VREAD_ACL;
245 if (NFSNONZERO_ATTRBIT(&tmpbits))
246 accmode |= VREAD_ATTRIBUTES;
248 nd->nd_repstat = nfsvno_accchk(vp, accmode,
249 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
250 NFSACCCHK_VPISLOCKED, NULL);
254 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
255 if (!nd->nd_repstat) {
256 if (nd->nd_flag & ND_NFSV4) {
257 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
258 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
260 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
262 if (nd->nd_repstat == 0) {
263 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
265 if (nfsrv_enable_crossmntpt != 0 &&
266 vp->v_type == VDIR &&
267 (vp->v_vflag & VV_ROOT) != 0 &&
269 tvp = mp->mnt_vnodecovered;
277 if ((nd->nd_repstat =
278 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
279 nd->nd_repstat = VOP_GETATTR(
280 tvp, &va, nd->nd_cred);
284 if (nd->nd_repstat == 0)
285 mounted_on_fileno = (uint64_t)
290 if (nd->nd_repstat == 0)
291 nd->nd_repstat = vfs_busy(mp, 0);
293 if (nd->nd_repstat == 0) {
294 (void)nfsvno_fillattr(nd, mp, vp, &nva,
295 &fh, 0, &attrbits, nd->nd_cred, p,
296 isdgram, 1, supports_nfsv4acls,
297 at_root, mounted_on_fileno);
304 nfsrv_fillattr(nd, &nva);
312 NFSEXITCODE2(error, nd);
317 * nfs setattr service
320 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
321 vnode_t vp, struct nfsexstuff *exp)
323 struct nfsvattr nva, nva2;
325 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
327 struct timespec guard = { 0, 0 };
328 nfsattrbit_t attrbits, retbits;
329 nfsv4stateid_t stateid;
330 NFSACL_T *aclp = NULL;
331 struct thread *p = curthread;
333 if (nd->nd_repstat) {
334 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
337 #ifdef NFS4_ACL_EXTATTR_NAME
338 aclp = acl_alloc(M_WAITOK);
342 NFSVNO_ATTRINIT(&nva);
343 if (nd->nd_flag & ND_NFSV4) {
344 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
345 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
346 stateid.other[0] = *tl++;
347 stateid.other[1] = *tl++;
348 stateid.other[2] = *tl;
349 if (stateid.other[0] == 0x55555555 &&
350 stateid.other[1] == 0x55555555 &&
351 stateid.other[2] == 0x55555555 &&
352 stateid.seqid == 0xffffffff)
355 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
359 /* For NFSv4, only va_uid is used from nva2. */
360 NFSZERO_ATTRBIT(&retbits);
361 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
362 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
364 nd->nd_repstat = preat_ret;
366 NFSZERO_ATTRBIT(&retbits);
367 if (nd->nd_flag & ND_NFSV3) {
368 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
369 gcheck = fxdr_unsigned(int, *tl);
371 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
372 fxdr_nfsv3time(tl, &guard);
374 if (!nd->nd_repstat && gcheck &&
375 (nva2.na_ctime.tv_sec != guard.tv_sec ||
376 nva2.na_ctime.tv_nsec != guard.tv_nsec))
377 nd->nd_repstat = NFSERR_NOT_SYNC;
378 if (nd->nd_repstat) {
380 #ifdef NFS4_ACL_EXTATTR_NAME
383 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
386 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
387 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
390 * Now that we have all the fields, lets do it.
391 * If the size is being changed write access is required, otherwise
392 * just check for a read only file system.
394 if (!nd->nd_repstat) {
395 if (NFSVNO_NOTSETSIZE(&nva)) {
396 if (NFSVNO_EXRDONLY(exp) ||
397 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
398 nd->nd_repstat = EROFS;
400 if (vnode_vtype(vp) != VREG)
401 nd->nd_repstat = EINVAL;
402 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
403 NFSVNO_EXSTRICTACCESS(exp))
404 nd->nd_repstat = nfsvno_accchk(vp,
405 VWRITE, nd->nd_cred, exp, p,
406 NFSACCCHK_NOOVERRIDE,
407 NFSACCCHK_VPISLOCKED, NULL);
411 * Proxy operations from the MDS are allowed via the all 0s special
414 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
415 gotproxystateid == 0)
416 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
417 &nva, &attrbits, exp, p);
419 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
421 * For V4, try setting the attrbutes in sets, so that the
422 * reply bitmap will be correct for an error case.
424 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
425 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
426 NFSVNO_ATTRINIT(&nva2);
427 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
428 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
429 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
431 if (!nd->nd_repstat) {
432 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
433 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
434 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
435 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
438 if (!nd->nd_repstat &&
439 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
440 NFSVNO_ATTRINIT(&nva2);
441 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
442 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
445 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
447 if (!nd->nd_repstat &&
448 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
449 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
450 NFSVNO_ATTRINIT(&nva2);
451 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
452 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
453 if (nva.na_vaflags & VA_UTIMES_NULL) {
454 nva2.na_vaflags |= VA_UTIMES_NULL;
455 NFSVNO_SETACTIVE(&nva2, vaflags);
457 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
459 if (!nd->nd_repstat) {
460 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
461 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
462 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
463 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
466 if (!nd->nd_repstat &&
467 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
468 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
469 NFSVNO_ATTRINIT(&nva2);
470 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
471 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
473 if (!nd->nd_repstat) {
474 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
475 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
476 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
477 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
481 #ifdef NFS4_ACL_EXTATTR_NAME
482 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
483 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
484 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
486 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
489 } else if (!nd->nd_repstat) {
490 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
493 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
494 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
496 nd->nd_repstat = postat_ret;
499 #ifdef NFS4_ACL_EXTATTR_NAME
502 if (nd->nd_flag & ND_NFSV3)
503 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
504 else if (nd->nd_flag & ND_NFSV4)
505 (void) nfsrv_putattrbit(nd, &retbits);
506 else if (!nd->nd_repstat)
507 nfsrv_fillattr(nd, &nva);
514 #ifdef NFS4_ACL_EXTATTR_NAME
517 if (nd->nd_flag & ND_NFSV4) {
519 * For all nd_repstat, the V4 reply includes a bitmap,
520 * even NFSERR_BADXDR, which is what this will end up
523 (void) nfsrv_putattrbit(nd, &retbits);
525 NFSEXITCODE2(error, nd);
531 * (Also performs lookup parent for v4)
534 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
535 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
537 struct nameidata named;
538 vnode_t vp, dirp = NULL;
539 int error = 0, dattr_ret = 1;
540 struct nfsvattr nva, dattr;
543 struct thread *p = curthread;
545 if (nd->nd_repstat) {
546 nfsrv_postopattr(nd, dattr_ret, &dattr);
551 * For some reason, if dp is a symlink, the error
552 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
554 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
555 nd->nd_repstat = NFSERR_SYMLINK;
560 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
561 LOCKLEAF | SAVESTART);
562 nfsvno_setpathbuf(&named, &bufp, &hashp);
563 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
566 nfsvno_relpathbuf(&named);
569 if (!nd->nd_repstat) {
570 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
573 nfsvno_relpathbuf(&named);
575 if (nd->nd_repstat) {
577 if (nd->nd_flag & ND_NFSV3)
578 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
582 if (nd->nd_flag & ND_NFSV3)
583 nfsrv_postopattr(nd, dattr_ret, &dattr);
586 if (named.ni_startdir)
587 vrele(named.ni_startdir);
588 nfsvno_relpathbuf(&named);
590 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
591 vp->v_type != VDIR && vp->v_type != VLNK)
593 * Only allow lookup of VDIR and VLNK for traversal of
594 * non-exported volumes during NFSv4 mounting.
596 nd->nd_repstat = ENOENT;
597 if (nd->nd_repstat == 0)
598 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
599 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
600 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
601 if (vpp != NULL && nd->nd_repstat == 0)
606 if (nd->nd_flag & ND_NFSV3)
607 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
611 if (nd->nd_repstat) {
612 if (nd->nd_flag & ND_NFSV3)
613 nfsrv_postopattr(nd, dattr_ret, &dattr);
616 if (nd->nd_flag & ND_NFSV2) {
617 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
618 nfsrv_fillattr(nd, &nva);
619 } else if (nd->nd_flag & ND_NFSV3) {
620 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
621 nfsrv_postopattr(nd, 0, &nva);
622 nfsrv_postopattr(nd, dattr_ret, &dattr);
626 NFSEXITCODE2(error, nd);
631 * nfs readlink service
634 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
635 vnode_t vp, __unused struct nfsexstuff *exp)
638 mbuf_t mp = NULL, mpend = NULL;
641 struct thread *p = curthread;
643 if (nd->nd_repstat) {
644 nfsrv_postopattr(nd, getret, &nva);
647 if (vnode_vtype(vp) != VLNK) {
648 if (nd->nd_flag & ND_NFSV2)
649 nd->nd_repstat = ENXIO;
651 nd->nd_repstat = EINVAL;
654 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
656 if (nd->nd_flag & ND_NFSV3)
657 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
659 if (nd->nd_flag & ND_NFSV3)
660 nfsrv_postopattr(nd, getret, &nva);
663 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
664 *tl = txdr_unsigned(len);
665 mbuf_setnext(nd->nd_mb, mp);
667 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
678 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
679 vnode_t vp, struct nfsexstuff *exp)
682 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
686 struct nfsstate st, *stp = &st;
687 struct nfslock lo, *lop = &lo;
688 nfsv4stateid_t stateid;
690 struct thread *p = curthread;
692 if (nd->nd_repstat) {
693 nfsrv_postopattr(nd, getret, &nva);
696 if (nd->nd_flag & ND_NFSV2) {
697 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
698 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
699 reqlen = fxdr_unsigned(int, *tl);
700 } else if (nd->nd_flag & ND_NFSV3) {
701 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
702 off = fxdr_hyper(tl);
704 reqlen = fxdr_unsigned(int, *tl);
706 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
707 reqlen = fxdr_unsigned(int, *(tl + 6));
709 if (reqlen > NFS_SRVMAXDATA(nd)) {
710 reqlen = NFS_SRVMAXDATA(nd);
711 } else if (reqlen < 0) {
716 if (nd->nd_flag & ND_NFSV4) {
717 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
718 lop->lo_flags = NFSLCK_READ;
719 stp->ls_ownerlen = 0;
721 stp->ls_uid = nd->nd_cred->cr_uid;
722 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
723 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
724 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
725 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
726 if ((nd->nd_flag & ND_NFSV41) != 0)
727 clientid.qval = nd->nd_clientid.qval;
728 else if (nd->nd_clientid.qval != clientid.qval)
729 printf("EEK1 multiple clids\n");
731 if ((nd->nd_flag & ND_NFSV41) != 0)
732 printf("EEK! no clientid from session\n");
733 nd->nd_flag |= ND_IMPLIEDCLID;
734 nd->nd_clientid.qval = clientid.qval;
736 stp->ls_stateid.other[2] = *tl++;
738 * Don't allow the client to use a special stateid for a DS op.
740 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
741 ((stp->ls_stateid.other[0] == 0x0 &&
742 stp->ls_stateid.other[1] == 0x0 &&
743 stp->ls_stateid.other[2] == 0x0) ||
744 (stp->ls_stateid.other[0] == 0xffffffff &&
745 stp->ls_stateid.other[1] == 0xffffffff &&
746 stp->ls_stateid.other[2] == 0xffffffff) ||
747 stp->ls_stateid.seqid != 0))
748 nd->nd_repstat = NFSERR_BADSTATEID;
749 /* However, allow the proxy stateid. */
750 if (stp->ls_stateid.seqid == 0xffffffff &&
751 stp->ls_stateid.other[0] == 0x55555555 &&
752 stp->ls_stateid.other[1] == 0x55555555 &&
753 stp->ls_stateid.other[2] == 0x55555555)
755 off = fxdr_hyper(tl);
758 lop->lo_end = off + reqlen;
760 * Paranoia, just in case it wraps around.
762 if (lop->lo_end < off)
763 lop->lo_end = NFS64BITSSET;
765 if (vnode_vtype(vp) != VREG) {
766 if (nd->nd_flag & ND_NFSV3)
767 nd->nd_repstat = EINVAL;
769 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
772 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
774 nd->nd_repstat = getret;
775 if (!nd->nd_repstat &&
776 (nva.na_uid != nd->nd_cred->cr_uid ||
777 NFSVNO_EXSTRICTACCESS(exp))) {
778 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
780 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
782 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
783 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
784 NFSACCCHK_VPISLOCKED, NULL);
787 * DS reads are marked by ND_DSSERVER or use the proxy special
790 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
791 ND_NFSV4 && gotproxystateid == 0)
792 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
793 &stateid, exp, nd, p);
794 if (nd->nd_repstat) {
796 if (nd->nd_flag & ND_NFSV3)
797 nfsrv_postopattr(nd, getret, &nva);
800 if (off >= nva.na_size) {
803 } else if (reqlen == 0)
805 else if ((off + reqlen) >= nva.na_size) {
806 cnt = nva.na_size - off;
812 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
814 if (!(nd->nd_flag & ND_NFSV4)) {
815 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
817 nd->nd_repstat = getret;
819 if (nd->nd_repstat) {
823 if (nd->nd_flag & ND_NFSV3)
824 nfsrv_postopattr(nd, getret, &nva);
829 if (nd->nd_flag & ND_NFSV2) {
830 nfsrv_fillattr(nd, &nva);
831 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
833 if (nd->nd_flag & ND_NFSV3) {
834 nfsrv_postopattr(nd, getret, &nva);
835 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
836 *tl++ = txdr_unsigned(cnt);
838 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
842 *tl++ = newnfs_false;
844 *tl = txdr_unsigned(cnt);
846 mbuf_setnext(nd->nd_mb, m3);
848 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
856 NFSEXITCODE2(error, nd);
864 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
865 vnode_t vp, struct nfsexstuff *exp)
870 struct nfsvattr nva, forat;
871 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
872 int gotproxystateid, stable = NFSWRITE_FILESYNC;
874 struct nfsstate st, *stp = &st;
875 struct nfslock lo, *lop = &lo;
876 nfsv4stateid_t stateid;
878 nfsattrbit_t attrbits;
879 struct thread *p = curthread;
881 if (nd->nd_repstat) {
882 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
886 if (nd->nd_flag & ND_NFSV2) {
887 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
888 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
890 retlen = len = fxdr_unsigned(int32_t, *tl);
891 } else if (nd->nd_flag & ND_NFSV3) {
892 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
893 off = fxdr_hyper(tl);
895 stable = fxdr_unsigned(int, *tl++);
896 retlen = len = fxdr_unsigned(int32_t, *tl);
898 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
899 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
900 lop->lo_flags = NFSLCK_WRITE;
901 stp->ls_ownerlen = 0;
903 stp->ls_uid = nd->nd_cred->cr_uid;
904 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
905 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
906 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
907 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
908 if ((nd->nd_flag & ND_NFSV41) != 0)
909 clientid.qval = nd->nd_clientid.qval;
910 else if (nd->nd_clientid.qval != clientid.qval)
911 printf("EEK2 multiple clids\n");
913 if ((nd->nd_flag & ND_NFSV41) != 0)
914 printf("EEK! no clientid from session\n");
915 nd->nd_flag |= ND_IMPLIEDCLID;
916 nd->nd_clientid.qval = clientid.qval;
918 stp->ls_stateid.other[2] = *tl++;
920 * Don't allow the client to use a special stateid for a DS op.
922 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
923 ((stp->ls_stateid.other[0] == 0x0 &&
924 stp->ls_stateid.other[1] == 0x0 &&
925 stp->ls_stateid.other[2] == 0x0) ||
926 (stp->ls_stateid.other[0] == 0xffffffff &&
927 stp->ls_stateid.other[1] == 0xffffffff &&
928 stp->ls_stateid.other[2] == 0xffffffff) ||
929 stp->ls_stateid.seqid != 0))
930 nd->nd_repstat = NFSERR_BADSTATEID;
931 /* However, allow the proxy stateid. */
932 if (stp->ls_stateid.seqid == 0xffffffff &&
933 stp->ls_stateid.other[0] == 0x55555555 &&
934 stp->ls_stateid.other[1] == 0x55555555 &&
935 stp->ls_stateid.other[2] == 0x55555555)
937 off = fxdr_hyper(tl);
940 stable = fxdr_unsigned(int, *tl++);
941 retlen = len = fxdr_unsigned(int32_t, *tl);
942 lop->lo_end = off + len;
944 * Paranoia, just in case it wraps around, which shouldn't
945 * ever happen anyhow.
947 if (lop->lo_end < lop->lo_first)
948 lop->lo_end = NFS64BITSSET;
952 * Loop through the mbuf chain, counting how many mbufs are a
953 * part of this write operation, so the iovec size is known.
957 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
973 if (retlen > NFS_SRVMAXIO || retlen < 0)
974 nd->nd_repstat = EIO;
975 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
976 if (nd->nd_flag & ND_NFSV3)
977 nd->nd_repstat = EINVAL;
979 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
982 NFSZERO_ATTRBIT(&attrbits);
983 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
984 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
986 nd->nd_repstat = forat_ret;
987 if (!nd->nd_repstat &&
988 (forat.na_uid != nd->nd_cred->cr_uid ||
989 NFSVNO_EXSTRICTACCESS(exp)))
990 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
992 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
994 * DS reads are marked by ND_DSSERVER or use the proxy special
997 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
998 ND_NFSV4 && gotproxystateid == 0)
999 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1000 &stateid, exp, nd, p);
1001 if (nd->nd_repstat) {
1003 if (nd->nd_flag & ND_NFSV3)
1004 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1009 * For NFS Version 2, it is not obvious what a write of zero length
1010 * should do, but I might as well be consistent with Version 3,
1011 * which is to return ok so long as there are no permission problems.
1014 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, &stable,
1015 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1016 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1020 if (nd->nd_flag & ND_NFSV4)
1023 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1025 if (!nd->nd_repstat)
1026 nd->nd_repstat = aftat_ret;
1027 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1028 if (nd->nd_flag & ND_NFSV3)
1029 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1032 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1033 *tl++ = txdr_unsigned(retlen);
1035 * If nfs_async is set, then pretend the write was FILESYNC.
1036 * Warning: Doing this violates RFC1813 and runs a risk
1037 * of data written by a client being lost when the server
1040 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1041 *tl++ = txdr_unsigned(stable);
1043 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1045 * Actually, there is no need to txdr these fields,
1046 * but it may make the values more human readable,
1047 * for debugging purposes.
1049 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1050 *tl = txdr_unsigned(nfsboottime.tv_usec);
1051 } else if (!nd->nd_repstat)
1052 nfsrv_fillattr(nd, &nva);
1055 NFSEXITCODE2(0, nd);
1059 NFSEXITCODE2(error, nd);
1064 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1065 * now does a truncate to 0 length via. setattr if it already exists
1066 * The core creation routine has been extracted out into nfsrv_creatsub(),
1067 * so it can also be used by nfsrv_open() for V4.
1070 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1071 vnode_t dp, struct nfsexstuff *exp)
1073 struct nfsvattr nva, dirfor, diraft;
1074 struct nfsv2_sattr *sp;
1075 struct nameidata named;
1077 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1078 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1080 vnode_t vp = NULL, dirp = NULL;
1085 int32_t cverf[2], tverf[2] = { 0, 0 };
1086 struct thread *p = curthread;
1088 if (nd->nd_repstat) {
1089 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1092 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1093 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1094 nfsvno_setpathbuf(&named, &bufp, &hashp);
1095 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1098 if (!nd->nd_repstat) {
1099 NFSVNO_ATTRINIT(&nva);
1100 if (nd->nd_flag & ND_NFSV2) {
1101 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1102 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1105 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1106 NFSVNO_SETATTRVAL(&nva, mode,
1107 nfstov_mode(sp->sa_mode));
1108 switch (nva.na_type) {
1110 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1112 NFSVNO_SETATTRVAL(&nva, size,
1118 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1124 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1125 how = fxdr_unsigned(int, *tl);
1127 case NFSCREATE_GUARDED:
1128 case NFSCREATE_UNCHECKED:
1129 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1133 case NFSCREATE_EXCLUSIVE:
1134 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1140 NFSVNO_SETATTRVAL(&nva, type, VREG);
1143 if (nd->nd_repstat) {
1144 nfsvno_relpathbuf(&named);
1145 if (nd->nd_flag & ND_NFSV3) {
1146 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1148 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1155 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1157 if (nd->nd_flag & ND_NFSV2) {
1161 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1165 if (nd->nd_repstat) {
1166 if (nd->nd_flag & ND_NFSV3)
1167 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1174 if (!(nd->nd_flag & ND_NFSV2)) {
1176 case NFSCREATE_GUARDED:
1178 nd->nd_repstat = EEXIST;
1180 case NFSCREATE_UNCHECKED:
1182 case NFSCREATE_EXCLUSIVE:
1183 if (named.ni_vp == NULL)
1184 NFSVNO_SETATTRVAL(&nva, mode, 0);
1190 * Iff doesn't exist, create it
1191 * otherwise just truncate to 0 length
1192 * should I set the mode too ?
1194 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1195 &exclusive_flag, cverf, rdev, exp);
1197 if (!nd->nd_repstat) {
1198 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1199 if (!nd->nd_repstat)
1200 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1203 if (!nd->nd_repstat) {
1204 tverf[0] = nva.na_atime.tv_sec;
1205 tverf[1] = nva.na_atime.tv_nsec;
1208 if (nd->nd_flag & ND_NFSV2) {
1209 if (!nd->nd_repstat) {
1210 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1211 nfsrv_fillattr(nd, &nva);
1214 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1215 || cverf[1] != tverf[1]))
1216 nd->nd_repstat = EEXIST;
1217 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1219 if (!nd->nd_repstat) {
1220 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1221 nfsrv_postopattr(nd, 0, &nva);
1223 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1227 NFSEXITCODE2(0, nd);
1231 nfsvno_relpathbuf(&named);
1232 NFSEXITCODE2(error, nd);
1237 * nfs v3 mknod service (and v4 create)
1240 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1241 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1243 struct nfsvattr nva, dirfor, diraft;
1245 struct nameidata named;
1246 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1247 u_int32_t major, minor;
1248 enum vtype vtyp = VNON;
1249 nfstype nfs4type = NFNON;
1250 vnode_t vp, dirp = NULL;
1251 nfsattrbit_t attrbits;
1252 char *bufp = NULL, *pathcp = NULL;
1253 u_long *hashp, cnflags;
1254 NFSACL_T *aclp = NULL;
1255 struct thread *p = curthread;
1257 NFSVNO_ATTRINIT(&nva);
1258 cnflags = (LOCKPARENT | SAVESTART);
1259 if (nd->nd_repstat) {
1260 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1263 #ifdef NFS4_ACL_EXTATTR_NAME
1264 aclp = acl_alloc(M_WAITOK);
1269 * For V4, the creation stuff is here, Yuck!
1271 if (nd->nd_flag & ND_NFSV4) {
1272 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1273 vtyp = nfsv34tov_type(*tl);
1274 nfs4type = fxdr_unsigned(nfstype, *tl);
1277 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1284 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1285 major = fxdr_unsigned(u_int32_t, *tl++);
1286 minor = fxdr_unsigned(u_int32_t, *tl);
1287 nva.na_rdev = NFSMAKEDEV(major, minor);
1293 cnflags = (LOCKPARENT | SAVENAME);
1296 nd->nd_repstat = NFSERR_BADTYPE;
1298 #ifdef NFS4_ACL_EXTATTR_NAME
1304 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1305 nfsvno_setpathbuf(&named, &bufp, &hashp);
1306 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1309 if (!nd->nd_repstat) {
1310 if (nd->nd_flag & ND_NFSV3) {
1311 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1312 vtyp = nfsv34tov_type(*tl);
1314 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1318 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1319 (vtyp == VCHR || vtyp == VBLK)) {
1320 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1321 major = fxdr_unsigned(u_int32_t, *tl++);
1322 minor = fxdr_unsigned(u_int32_t, *tl);
1323 nva.na_rdev = NFSMAKEDEV(major, minor);
1327 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1328 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1329 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1330 dirfor.na_gid == nva.na_gid)
1331 NFSVNO_UNSET(&nva, gid);
1332 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1334 if (nd->nd_repstat) {
1336 #ifdef NFS4_ACL_EXTATTR_NAME
1339 nfsvno_relpathbuf(&named);
1341 free(pathcp, M_TEMP);
1342 if (nd->nd_flag & ND_NFSV3)
1343 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1349 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1350 * in va_mode, so we'll have to set a default here.
1352 if (NFSVNO_NOTSETMODE(&nva)) {
1360 named.ni_cnd.cn_flags |= WILLBEDIR;
1361 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1362 if (nd->nd_repstat) {
1364 if (nd->nd_flag & ND_NFSV3)
1365 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1369 #ifdef NFS4_ACL_EXTATTR_NAME
1372 if (nd->nd_flag & ND_NFSV3)
1373 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1378 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1380 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1382 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1383 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1385 #ifdef NFS4_ACL_EXTATTR_NAME
1389 } else if (vtyp == VLNK) {
1390 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1391 &dirfor, &diraft, &diraft_ret, &attrbits,
1392 aclp, p, exp, pathcp, pathlen);
1393 #ifdef NFS4_ACL_EXTATTR_NAME
1396 free(pathcp, M_TEMP);
1401 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1402 if (!nd->nd_repstat) {
1404 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1405 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1406 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1407 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1409 if (vpp != NULL && nd->nd_repstat == 0) {
1410 NFSVOPUNLOCK(vp, 0);
1416 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1418 if (!nd->nd_repstat) {
1419 if (nd->nd_flag & ND_NFSV3) {
1420 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1421 nfsrv_postopattr(nd, 0, &nva);
1423 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1424 *tl++ = newnfs_false;
1425 txdr_hyper(dirfor.na_filerev, tl);
1427 txdr_hyper(diraft.na_filerev, tl);
1428 (void) nfsrv_putattrbit(nd, &attrbits);
1431 if (nd->nd_flag & ND_NFSV3)
1432 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1433 #ifdef NFS4_ACL_EXTATTR_NAME
1438 NFSEXITCODE2(0, nd);
1442 #ifdef NFS4_ACL_EXTATTR_NAME
1446 nfsvno_relpathbuf(&named);
1448 free(pathcp, M_TEMP);
1450 NFSEXITCODE2(error, nd);
1455 * nfs remove service
1458 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1459 vnode_t dp, struct nfsexstuff *exp)
1461 struct nameidata named;
1463 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1464 vnode_t dirp = NULL;
1465 struct nfsvattr dirfor, diraft;
1468 struct thread *p = curthread;
1470 if (nd->nd_repstat) {
1471 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1474 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1475 LOCKPARENT | LOCKLEAF);
1476 nfsvno_setpathbuf(&named, &bufp, &hashp);
1477 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1480 nfsvno_relpathbuf(&named);
1483 if (!nd->nd_repstat) {
1484 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1487 nfsvno_relpathbuf(&named);
1490 if (!(nd->nd_flag & ND_NFSV2)) {
1491 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1498 if (!nd->nd_repstat) {
1499 if (nd->nd_flag & ND_NFSV4) {
1500 if (vnode_vtype(named.ni_vp) == VDIR)
1501 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1502 nd->nd_cred, p, exp);
1504 nd->nd_repstat = nfsvno_removesub(&named, 1,
1505 nd->nd_cred, p, exp);
1506 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1507 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1508 nd->nd_cred, p, exp);
1510 nd->nd_repstat = nfsvno_removesub(&named, 0,
1511 nd->nd_cred, p, exp);
1514 if (!(nd->nd_flag & ND_NFSV2)) {
1516 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1520 if (nd->nd_flag & ND_NFSV3) {
1521 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1523 } else if (!nd->nd_repstat) {
1524 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1525 *tl++ = newnfs_false;
1526 txdr_hyper(dirfor.na_filerev, tl);
1528 txdr_hyper(diraft.na_filerev, tl);
1533 NFSEXITCODE2(error, nd);
1538 * nfs rename service
1541 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1542 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1545 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1546 int tdirfor_ret = 1, tdiraft_ret = 1;
1547 struct nameidata fromnd, tond;
1548 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1549 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1550 struct nfsexstuff tnes;
1552 char *bufp, *tbufp = NULL;
1555 struct thread *p = curthread;
1557 if (nd->nd_repstat) {
1558 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1559 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1562 if (!(nd->nd_flag & ND_NFSV2))
1563 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1564 tond.ni_cnd.cn_nameiop = 0;
1565 tond.ni_startdir = NULL;
1566 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1567 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1568 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1573 nfsvno_relpathbuf(&fromnd);
1577 * Unlock dp in this code section, so it is unlocked before
1578 * tdp gets locked. This avoids a potential LOR if tdp is the
1579 * parent directory of dp.
1581 if (nd->nd_flag & ND_NFSV4) {
1585 NFSVOPUNLOCK(dp, 0);
1586 /* Might lock tdp. */
1587 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1590 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1592 NFSVOPUNLOCK(dp, 0);
1595 tfh.nfsrvfh_len = 0;
1596 error = nfsrv_mtofh(nd, &tfh);
1598 error = nfsvno_getfh(dp, &fh, p);
1601 /* todp is always NULL except NFSv4 */
1602 nfsvno_relpathbuf(&fromnd);
1606 /* If this is the same file handle, just VREF() the vnode. */
1607 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1608 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1612 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1614 NFSVOPUNLOCK(dp, 0);
1616 NFSVOPUNLOCK(dp, 0);
1617 nd->nd_cred->cr_uid = nd->nd_saveduid;
1618 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1619 0); /* Locks tdp. */
1621 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1623 NFSVOPUNLOCK(tdp, 0);
1627 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1628 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1629 if (!nd->nd_repstat) {
1630 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1635 nfsvno_relpathbuf(&fromnd);
1636 nfsvno_relpathbuf(&tond);
1640 if (nd->nd_repstat) {
1641 if (nd->nd_flag & ND_NFSV3) {
1642 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1644 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1650 nfsvno_relpathbuf(&fromnd);
1651 nfsvno_relpathbuf(&tond);
1656 * Done parsing, now down to business.
1658 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1659 if (nd->nd_repstat) {
1660 if (nd->nd_flag & ND_NFSV3) {
1661 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1663 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1670 nfsvno_relpathbuf(&tond);
1673 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1674 tond.ni_cnd.cn_flags |= WILLBEDIR;
1675 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1676 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1677 nd->nd_flag, nd->nd_cred, p);
1679 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1681 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1686 if (nd->nd_flag & ND_NFSV3) {
1687 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1688 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1689 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1690 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1691 *tl++ = newnfs_false;
1692 txdr_hyper(fdirfor.na_filerev, tl);
1694 txdr_hyper(fdiraft.na_filerev, tl);
1696 *tl++ = newnfs_false;
1697 txdr_hyper(tdirfor.na_filerev, tl);
1699 txdr_hyper(tdiraft.na_filerev, tl);
1703 NFSEXITCODE2(error, nd);
1711 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1712 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1714 struct nameidata named;
1716 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1717 vnode_t dirp = NULL, dp = NULL;
1718 struct nfsvattr dirfor, diraft, at;
1719 struct nfsexstuff tnes;
1723 struct thread *p = curthread;
1725 if (nd->nd_repstat) {
1726 nfsrv_postopattr(nd, getret, &at);
1727 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1730 NFSVOPUNLOCK(vp, 0);
1731 if (vnode_vtype(vp) == VDIR) {
1732 if (nd->nd_flag & ND_NFSV4)
1733 nd->nd_repstat = NFSERR_ISDIR;
1735 nd->nd_repstat = NFSERR_INVAL;
1739 if (!nd->nd_repstat) {
1740 if (nd->nd_flag & ND_NFSV4) {
1744 error = nfsrv_mtofh(nd, &dfh);
1747 /* tovp is always NULL unless NFSv4 */
1750 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
1752 NFSVOPUNLOCK(dp, 0);
1755 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1756 LOCKPARENT | SAVENAME | NOCACHE);
1757 if (!nd->nd_repstat) {
1758 nfsvno_setpathbuf(&named, &bufp, &hashp);
1759 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1764 nfsvno_relpathbuf(&named);
1767 if (!nd->nd_repstat) {
1768 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1773 nfsvno_relpathbuf(&named);
1777 if (nd->nd_flag & ND_NFSV2) {
1781 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1785 if (!nd->nd_repstat)
1786 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1787 if (nd->nd_flag & ND_NFSV3)
1788 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1790 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1794 if (nd->nd_flag & ND_NFSV3) {
1795 nfsrv_postopattr(nd, getret, &at);
1796 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1797 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1798 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1799 *tl++ = newnfs_false;
1800 txdr_hyper(dirfor.na_filerev, tl);
1802 txdr_hyper(diraft.na_filerev, tl);
1806 NFSEXITCODE2(error, nd);
1811 * nfs symbolic link service
1814 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1815 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1817 struct nfsvattr nva, dirfor, diraft;
1818 struct nameidata named;
1819 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1820 vnode_t dirp = NULL;
1821 char *bufp, *pathcp = NULL;
1823 struct thread *p = curthread;
1825 if (nd->nd_repstat) {
1826 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1831 NFSVNO_ATTRINIT(&nva);
1832 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1833 LOCKPARENT | SAVESTART | NOCACHE);
1834 nfsvno_setpathbuf(&named, &bufp, &hashp);
1835 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1836 if (!error && !nd->nd_repstat)
1837 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1840 nfsvno_relpathbuf(&named);
1843 if (!nd->nd_repstat) {
1844 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1847 nfsvno_relpathbuf(&named);
1849 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1855 * And call nfsrvd_symlinksub() to do the common code. It will
1856 * return EBADRPC upon a parsing error, 0 otherwise.
1858 if (!nd->nd_repstat) {
1860 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1862 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1863 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1865 } else if (dirp != NULL) {
1866 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1870 free(pathcp, M_TEMP);
1872 if (nd->nd_flag & ND_NFSV3) {
1873 if (!nd->nd_repstat) {
1874 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1875 nfsrv_postopattr(nd, 0, &nva);
1877 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1881 NFSEXITCODE2(error, nd);
1886 * Common code for creating a symbolic link.
1889 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1890 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1891 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1892 int *diraft_retp, nfsattrbit_t *attrbitp,
1893 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1898 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1899 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1900 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1901 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1902 if (nd->nd_flag & ND_NFSV3) {
1903 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1904 if (!nd->nd_repstat)
1905 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1906 nvap, nd, p, 1, NULL);
1908 if (vpp != NULL && nd->nd_repstat == 0) {
1909 NFSVOPUNLOCK(ndp->ni_vp, 0);
1915 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1918 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1919 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1920 *tl++ = newnfs_false;
1921 txdr_hyper(dirforp->na_filerev, tl);
1923 txdr_hyper(diraftp->na_filerev, tl);
1924 (void) nfsrv_putattrbit(nd, attrbitp);
1927 NFSEXITCODE2(0, nd);
1934 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1935 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1937 struct nfsvattr nva, dirfor, diraft;
1938 struct nameidata named;
1940 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1941 vnode_t dirp = NULL;
1944 struct thread *p = curthread;
1946 if (nd->nd_repstat) {
1947 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1950 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1951 LOCKPARENT | SAVENAME | NOCACHE);
1952 nfsvno_setpathbuf(&named, &bufp, &hashp);
1953 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1956 if (!nd->nd_repstat) {
1957 NFSVNO_ATTRINIT(&nva);
1958 if (nd->nd_flag & ND_NFSV3) {
1959 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1963 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1964 nva.na_mode = nfstov_mode(*tl++);
1967 if (!nd->nd_repstat) {
1968 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1971 nfsvno_relpathbuf(&named);
1973 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1977 if (nd->nd_repstat) {
1979 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1983 if (nd->nd_flag & ND_NFSV3)
1984 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1989 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1992 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1994 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1995 &diraft_ret, NULL, NULL, p, exp);
1997 if (nd->nd_flag & ND_NFSV3) {
1998 if (!nd->nd_repstat) {
1999 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
2000 nfsrv_postopattr(nd, 0, &nva);
2002 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2003 } else if (!nd->nd_repstat) {
2004 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2005 nfsrv_fillattr(nd, &nva);
2009 NFSEXITCODE2(0, nd);
2013 nfsvno_relpathbuf(&named);
2014 NFSEXITCODE2(error, nd);
2019 * Code common to mkdir for V2,3 and 4.
2022 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2023 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2024 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2025 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2026 NFSPROC_T *p, struct nfsexstuff *exp)
2031 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2032 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2033 nd->nd_cred, p, exp);
2034 if (!nd->nd_repstat) {
2036 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2037 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2038 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2039 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2041 if (vpp && !nd->nd_repstat) {
2042 NFSVOPUNLOCK(vp, 0);
2049 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2052 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2053 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2054 *tl++ = newnfs_false;
2055 txdr_hyper(dirforp->na_filerev, tl);
2057 txdr_hyper(diraftp->na_filerev, tl);
2058 (void) nfsrv_putattrbit(nd, attrbitp);
2061 NFSEXITCODE2(0, nd);
2065 * nfs commit service
2068 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2069 vnode_t vp, __unused struct nfsexstuff *exp)
2071 struct nfsvattr bfor, aft;
2073 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2075 struct thread *p = curthread;
2077 if (nd->nd_repstat) {
2078 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2082 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2083 if (vp->v_type != VREG) {
2084 if (nd->nd_flag & ND_NFSV3)
2085 error = NFSERR_NOTSUPP;
2087 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2090 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2093 * XXX At this time VOP_FSYNC() does not accept offset and byte
2094 * count parameters, so these arguments are useless (someday maybe).
2096 off = fxdr_hyper(tl);
2098 cnt = fxdr_unsigned(int, *tl);
2099 if (nd->nd_flag & ND_NFSV3)
2100 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2101 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2102 if (nd->nd_flag & ND_NFSV3) {
2103 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2104 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2107 if (!nd->nd_repstat) {
2108 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2109 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2110 *tl = txdr_unsigned(nfsboottime.tv_usec);
2114 NFSEXITCODE2(0, nd);
2118 NFSEXITCODE2(error, nd);
2123 * nfs statfs service
2126 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2127 vnode_t vp, __unused struct nfsexstuff *exp)
2134 struct thread *p = curthread;
2137 if (nd->nd_repstat) {
2138 nfsrv_postopattr(nd, getret, &at);
2141 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2142 nd->nd_repstat = nfsvno_statfs(vp, sf);
2143 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2145 if (nd->nd_flag & ND_NFSV3)
2146 nfsrv_postopattr(nd, getret, &at);
2149 if (nd->nd_flag & ND_NFSV2) {
2150 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2151 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2152 *tl++ = txdr_unsigned(sf->f_bsize);
2153 *tl++ = txdr_unsigned(sf->f_blocks);
2154 *tl++ = txdr_unsigned(sf->f_bfree);
2155 *tl = txdr_unsigned(sf->f_bavail);
2157 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2158 tval = (u_quad_t)sf->f_blocks;
2159 tval *= (u_quad_t)sf->f_bsize;
2160 txdr_hyper(tval, tl); tl += 2;
2161 tval = (u_quad_t)sf->f_bfree;
2162 tval *= (u_quad_t)sf->f_bsize;
2163 txdr_hyper(tval, tl); tl += 2;
2164 tval = (u_quad_t)sf->f_bavail;
2165 tval *= (u_quad_t)sf->f_bsize;
2166 txdr_hyper(tval, tl); tl += 2;
2167 tval = (u_quad_t)sf->f_files;
2168 txdr_hyper(tval, tl); tl += 2;
2169 tval = (u_quad_t)sf->f_ffree;
2170 txdr_hyper(tval, tl); tl += 2;
2171 tval = (u_quad_t)sf->f_ffree;
2172 txdr_hyper(tval, tl); tl += 2;
2178 NFSEXITCODE2(0, nd);
2183 * nfs fsinfo service
2186 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2187 vnode_t vp, __unused struct nfsexstuff *exp)
2190 struct nfsfsinfo fs;
2193 struct thread *p = curthread;
2195 if (nd->nd_repstat) {
2196 nfsrv_postopattr(nd, getret, &at);
2199 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2200 nfsvno_getfs(&fs, isdgram);
2202 nfsrv_postopattr(nd, getret, &at);
2203 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2204 *tl++ = txdr_unsigned(fs.fs_rtmax);
2205 *tl++ = txdr_unsigned(fs.fs_rtpref);
2206 *tl++ = txdr_unsigned(fs.fs_rtmult);
2207 *tl++ = txdr_unsigned(fs.fs_wtmax);
2208 *tl++ = txdr_unsigned(fs.fs_wtpref);
2209 *tl++ = txdr_unsigned(fs.fs_wtmult);
2210 *tl++ = txdr_unsigned(fs.fs_dtpref);
2211 txdr_hyper(fs.fs_maxfilesize, tl);
2213 txdr_nfsv3time(&fs.fs_timedelta, tl);
2215 *tl = txdr_unsigned(fs.fs_properties);
2218 NFSEXITCODE2(0, nd);
2223 * nfs pathconf service
2226 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2227 vnode_t vp, __unused struct nfsexstuff *exp)
2229 struct nfsv3_pathconf *pc;
2231 long linkmax, namemax, chownres, notrunc;
2233 struct thread *p = curthread;
2235 if (nd->nd_repstat) {
2236 nfsrv_postopattr(nd, getret, &at);
2239 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2241 if (!nd->nd_repstat)
2242 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2244 if (!nd->nd_repstat)
2245 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2246 &chownres, nd->nd_cred, p);
2247 if (!nd->nd_repstat)
2248 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2250 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2252 nfsrv_postopattr(nd, getret, &at);
2253 if (!nd->nd_repstat) {
2254 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2255 pc->pc_linkmax = txdr_unsigned(linkmax);
2256 pc->pc_namemax = txdr_unsigned(namemax);
2257 pc->pc_notrunc = txdr_unsigned(notrunc);
2258 pc->pc_chownrestricted = txdr_unsigned(chownres);
2261 * These should probably be supported by VOP_PATHCONF(), but
2262 * until msdosfs is exportable (why would you want to?), the
2263 * Unix defaults should be ok.
2265 pc->pc_caseinsensitive = newnfs_false;
2266 pc->pc_casepreserving = newnfs_true;
2270 NFSEXITCODE2(0, nd);
2275 * nfsv4 lock service
2278 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2279 vnode_t vp, struct nfsexstuff *exp)
2283 struct nfsstate *stp = NULL;
2284 struct nfslock *lop;
2285 struct nfslockconflict cf;
2287 u_short flags = NFSLCK_LOCK, lflags;
2288 u_int64_t offset, len;
2289 nfsv4stateid_t stateid;
2291 struct thread *p = curthread;
2293 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2294 i = fxdr_unsigned(int, *tl++);
2296 case NFSV4LOCKT_READW:
2297 flags |= NFSLCK_BLOCKING;
2298 case NFSV4LOCKT_READ:
2299 lflags = NFSLCK_READ;
2301 case NFSV4LOCKT_WRITEW:
2302 flags |= NFSLCK_BLOCKING;
2303 case NFSV4LOCKT_WRITE:
2304 lflags = NFSLCK_WRITE;
2307 nd->nd_repstat = NFSERR_BADXDR;
2310 if (*tl++ == newnfs_true)
2311 flags |= NFSLCK_RECLAIM;
2312 offset = fxdr_hyper(tl);
2314 len = fxdr_hyper(tl);
2316 if (*tl == newnfs_true)
2317 flags |= NFSLCK_OPENTOLOCK;
2318 if (flags & NFSLCK_OPENTOLOCK) {
2319 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2320 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2321 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2322 nd->nd_repstat = NFSERR_BADXDR;
2325 stp = malloc(sizeof (struct nfsstate) + i,
2326 M_NFSDSTATE, M_WAITOK);
2327 stp->ls_ownerlen = i;
2328 stp->ls_op = nd->nd_rp;
2329 stp->ls_seq = fxdr_unsigned(int, *tl++);
2330 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2331 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2333 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2336 * For the special stateid of other all 0s and seqid == 1, set
2337 * the stateid to the current stateid, if it is set.
2339 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2340 stp->ls_stateid.seqid == 1 &&
2341 stp->ls_stateid.other[0] == 0 &&
2342 stp->ls_stateid.other[1] == 0 &&
2343 stp->ls_stateid.other[2] == 0) {
2344 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2345 stp->ls_stateid = nd->nd_curstateid;
2346 stp->ls_stateid.seqid = 0;
2348 nd->nd_repstat = NFSERR_BADSTATEID;
2353 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2354 clientid.lval[0] = *tl++;
2355 clientid.lval[1] = *tl++;
2356 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2357 if ((nd->nd_flag & ND_NFSV41) != 0)
2358 clientid.qval = nd->nd_clientid.qval;
2359 else if (nd->nd_clientid.qval != clientid.qval)
2360 printf("EEK3 multiple clids\n");
2362 if ((nd->nd_flag & ND_NFSV41) != 0)
2363 printf("EEK! no clientid from session\n");
2364 nd->nd_flag |= ND_IMPLIEDCLID;
2365 nd->nd_clientid.qval = clientid.qval;
2367 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2371 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2372 stp = malloc(sizeof (struct nfsstate),
2373 M_NFSDSTATE, M_WAITOK);
2374 stp->ls_ownerlen = 0;
2375 stp->ls_op = nd->nd_rp;
2376 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2377 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2379 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2382 * For the special stateid of other all 0s and seqid == 1, set
2383 * the stateid to the current stateid, if it is set.
2385 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2386 stp->ls_stateid.seqid == 1 &&
2387 stp->ls_stateid.other[0] == 0 &&
2388 stp->ls_stateid.other[1] == 0 &&
2389 stp->ls_stateid.other[2] == 0) {
2390 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2391 stp->ls_stateid = nd->nd_curstateid;
2392 stp->ls_stateid.seqid = 0;
2394 nd->nd_repstat = NFSERR_BADSTATEID;
2399 stp->ls_seq = fxdr_unsigned(int, *tl);
2400 clientid.lval[0] = stp->ls_stateid.other[0];
2401 clientid.lval[1] = stp->ls_stateid.other[1];
2402 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2403 if ((nd->nd_flag & ND_NFSV41) != 0)
2404 clientid.qval = nd->nd_clientid.qval;
2405 else if (nd->nd_clientid.qval != clientid.qval)
2406 printf("EEK4 multiple clids\n");
2408 if ((nd->nd_flag & ND_NFSV41) != 0)
2409 printf("EEK! no clientid from session\n");
2410 nd->nd_flag |= ND_IMPLIEDCLID;
2411 nd->nd_clientid.qval = clientid.qval;
2414 lop = malloc(sizeof (struct nfslock),
2415 M_NFSDLOCK, M_WAITOK);
2416 lop->lo_first = offset;
2417 if (len == NFS64BITSSET) {
2418 lop->lo_end = NFS64BITSSET;
2420 lop->lo_end = offset + len;
2421 if (lop->lo_end <= lop->lo_first)
2422 nd->nd_repstat = NFSERR_INVAL;
2424 lop->lo_flags = lflags;
2425 stp->ls_flags = flags;
2426 stp->ls_uid = nd->nd_cred->cr_uid;
2429 * Do basic access checking.
2431 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2432 if (vnode_vtype(vp) == VDIR)
2433 nd->nd_repstat = NFSERR_ISDIR;
2435 nd->nd_repstat = NFSERR_INVAL;
2437 if (!nd->nd_repstat) {
2438 if (lflags & NFSLCK_WRITE) {
2439 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2440 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2441 NFSACCCHK_VPISLOCKED, NULL);
2443 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2444 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2445 NFSACCCHK_VPISLOCKED, NULL);
2447 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2448 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2449 NFSACCCHK_VPISLOCKED, NULL);
2454 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2455 * seqid# gets updated. nfsrv_lockctrl() will return the value
2456 * of nd_repstat, if it gets that far.
2458 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2459 &stateid, exp, nd, p);
2461 free(lop, M_NFSDLOCK);
2463 free(stp, M_NFSDSTATE);
2464 if (!nd->nd_repstat) {
2465 /* For NFSv4.1, set the Current StateID. */
2466 if ((nd->nd_flag & ND_NFSV41) != 0) {
2467 nd->nd_curstateid = stateid;
2468 nd->nd_flag |= ND_CURSTATEID;
2470 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2471 *tl++ = txdr_unsigned(stateid.seqid);
2472 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2473 } else if (nd->nd_repstat == NFSERR_DENIED) {
2474 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2475 txdr_hyper(cf.cl_first, tl);
2477 if (cf.cl_end == NFS64BITSSET)
2480 len = cf.cl_end - cf.cl_first;
2481 txdr_hyper(len, tl);
2483 if (cf.cl_flags == NFSLCK_WRITE)
2484 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2486 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2487 *tl++ = stateid.other[0];
2488 *tl = stateid.other[1];
2489 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2492 NFSEXITCODE2(0, nd);
2497 free(stp, M_NFSDSTATE);
2498 NFSEXITCODE2(error, nd);
2503 * nfsv4 lock test service
2506 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2507 vnode_t vp, struct nfsexstuff *exp)
2511 struct nfsstate *stp = NULL;
2512 struct nfslock lo, *lop = &lo;
2513 struct nfslockconflict cf;
2515 nfsv4stateid_t stateid;
2518 struct thread *p = curthread;
2520 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2521 i = fxdr_unsigned(int, *(tl + 7));
2522 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2523 nd->nd_repstat = NFSERR_BADXDR;
2526 stp = malloc(sizeof (struct nfsstate) + i,
2527 M_NFSDSTATE, M_WAITOK);
2528 stp->ls_ownerlen = i;
2530 stp->ls_flags = NFSLCK_TEST;
2531 stp->ls_uid = nd->nd_cred->cr_uid;
2532 i = fxdr_unsigned(int, *tl++);
2534 case NFSV4LOCKT_READW:
2535 stp->ls_flags |= NFSLCK_BLOCKING;
2536 case NFSV4LOCKT_READ:
2537 lo.lo_flags = NFSLCK_READ;
2539 case NFSV4LOCKT_WRITEW:
2540 stp->ls_flags |= NFSLCK_BLOCKING;
2541 case NFSV4LOCKT_WRITE:
2542 lo.lo_flags = NFSLCK_WRITE;
2545 nd->nd_repstat = NFSERR_BADXDR;
2548 lo.lo_first = fxdr_hyper(tl);
2550 len = fxdr_hyper(tl);
2551 if (len == NFS64BITSSET) {
2552 lo.lo_end = NFS64BITSSET;
2554 lo.lo_end = lo.lo_first + len;
2555 if (lo.lo_end <= lo.lo_first)
2556 nd->nd_repstat = NFSERR_INVAL;
2559 clientid.lval[0] = *tl++;
2560 clientid.lval[1] = *tl;
2561 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2562 if ((nd->nd_flag & ND_NFSV41) != 0)
2563 clientid.qval = nd->nd_clientid.qval;
2564 else if (nd->nd_clientid.qval != clientid.qval)
2565 printf("EEK5 multiple clids\n");
2567 if ((nd->nd_flag & ND_NFSV41) != 0)
2568 printf("EEK! no clientid from session\n");
2569 nd->nd_flag |= ND_IMPLIEDCLID;
2570 nd->nd_clientid.qval = clientid.qval;
2572 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2575 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2576 if (vnode_vtype(vp) == VDIR)
2577 nd->nd_repstat = NFSERR_ISDIR;
2579 nd->nd_repstat = NFSERR_INVAL;
2581 if (!nd->nd_repstat)
2582 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2583 &stateid, exp, nd, p);
2584 if (nd->nd_repstat) {
2585 if (nd->nd_repstat == NFSERR_DENIED) {
2586 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2587 txdr_hyper(cf.cl_first, tl);
2589 if (cf.cl_end == NFS64BITSSET)
2592 len = cf.cl_end - cf.cl_first;
2593 txdr_hyper(len, tl);
2595 if (cf.cl_flags == NFSLCK_WRITE)
2596 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2598 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2599 *tl++ = stp->ls_stateid.other[0];
2600 *tl = stp->ls_stateid.other[1];
2601 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2606 free(stp, M_NFSDSTATE);
2607 NFSEXITCODE2(0, nd);
2612 free(stp, M_NFSDSTATE);
2613 NFSEXITCODE2(error, nd);
2618 * nfsv4 unlock service
2621 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2622 vnode_t vp, struct nfsexstuff *exp)
2626 struct nfsstate *stp;
2627 struct nfslock *lop;
2629 nfsv4stateid_t stateid;
2632 struct thread *p = curthread;
2634 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2635 stp = malloc(sizeof (struct nfsstate),
2636 M_NFSDSTATE, M_WAITOK);
2637 lop = malloc(sizeof (struct nfslock),
2638 M_NFSDLOCK, M_WAITOK);
2639 stp->ls_flags = NFSLCK_UNLOCK;
2640 lop->lo_flags = NFSLCK_UNLOCK;
2641 stp->ls_op = nd->nd_rp;
2642 i = fxdr_unsigned(int, *tl++);
2644 case NFSV4LOCKT_READW:
2645 stp->ls_flags |= NFSLCK_BLOCKING;
2646 case NFSV4LOCKT_READ:
2648 case NFSV4LOCKT_WRITEW:
2649 stp->ls_flags |= NFSLCK_BLOCKING;
2650 case NFSV4LOCKT_WRITE:
2653 nd->nd_repstat = NFSERR_BADXDR;
2654 free(stp, M_NFSDSTATE);
2655 free(lop, M_NFSDLOCK);
2658 stp->ls_ownerlen = 0;
2659 stp->ls_uid = nd->nd_cred->cr_uid;
2660 stp->ls_seq = fxdr_unsigned(int, *tl++);
2661 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2662 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2664 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2667 * For the special stateid of other all 0s and seqid == 1, set the
2668 * stateid to the current stateid, if it is set.
2670 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2671 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2672 stp->ls_stateid.other[2] == 0) {
2673 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2674 stp->ls_stateid = nd->nd_curstateid;
2675 stp->ls_stateid.seqid = 0;
2677 nd->nd_repstat = NFSERR_BADSTATEID;
2682 lop->lo_first = fxdr_hyper(tl);
2684 len = fxdr_hyper(tl);
2685 if (len == NFS64BITSSET) {
2686 lop->lo_end = NFS64BITSSET;
2688 lop->lo_end = lop->lo_first + len;
2689 if (lop->lo_end <= lop->lo_first)
2690 nd->nd_repstat = NFSERR_INVAL;
2692 clientid.lval[0] = stp->ls_stateid.other[0];
2693 clientid.lval[1] = stp->ls_stateid.other[1];
2694 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2695 if ((nd->nd_flag & ND_NFSV41) != 0)
2696 clientid.qval = nd->nd_clientid.qval;
2697 else if (nd->nd_clientid.qval != clientid.qval)
2698 printf("EEK6 multiple clids\n");
2700 if ((nd->nd_flag & ND_NFSV41) != 0)
2701 printf("EEK! no clientid from session\n");
2702 nd->nd_flag |= ND_IMPLIEDCLID;
2703 nd->nd_clientid.qval = clientid.qval;
2705 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2706 if (vnode_vtype(vp) == VDIR)
2707 nd->nd_repstat = NFSERR_ISDIR;
2709 nd->nd_repstat = NFSERR_INVAL;
2712 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2713 * seqid# gets incremented. nfsrv_lockctrl() will return the
2714 * value of nd_repstat, if it gets that far.
2716 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2717 &stateid, exp, nd, p);
2719 free(stp, M_NFSDSTATE);
2721 free(lop, M_NFSDLOCK);
2722 if (!nd->nd_repstat) {
2723 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2724 *tl++ = txdr_unsigned(stateid.seqid);
2725 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2729 NFSEXITCODE2(error, nd);
2734 * nfsv4 open service
2737 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2738 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2742 struct nfsstate *stp = NULL;
2743 int error = 0, create, claim, exclusive_flag = 0;
2744 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2745 int how = NFSCREATE_UNCHECKED;
2746 int32_t cverf[2], tverf[2] = { 0, 0 };
2747 vnode_t vp = NULL, dirp = NULL;
2748 struct nfsvattr nva, dirfor, diraft;
2749 struct nameidata named;
2750 nfsv4stateid_t stateid, delegstateid;
2751 nfsattrbit_t attrbits;
2755 NFSACL_T *aclp = NULL;
2756 struct thread *p = curthread;
2758 #ifdef NFS4_ACL_EXTATTR_NAME
2759 aclp = acl_alloc(M_WAITOK);
2762 NFSZERO_ATTRBIT(&attrbits);
2763 named.ni_startdir = NULL;
2764 named.ni_cnd.cn_nameiop = 0;
2765 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2766 i = fxdr_unsigned(int, *(tl + 5));
2767 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2768 nd->nd_repstat = NFSERR_BADXDR;
2771 stp = malloc(sizeof (struct nfsstate) + i,
2772 M_NFSDSTATE, M_WAITOK);
2773 stp->ls_ownerlen = i;
2774 stp->ls_op = nd->nd_rp;
2775 stp->ls_flags = NFSLCK_OPEN;
2776 stp->ls_uid = nd->nd_cred->cr_uid;
2777 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2778 i = fxdr_unsigned(int, *tl++);
2780 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2781 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2783 /* For now, ignore these. */
2784 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2785 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2786 case NFSV4OPEN_WANTANYDELEG:
2787 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2789 i &= ~NFSV4OPEN_WANTDELEGMASK;
2791 case NFSV4OPEN_WANTREADDELEG:
2792 stp->ls_flags |= NFSLCK_WANTRDELEG;
2793 i &= ~NFSV4OPEN_WANTDELEGMASK;
2795 case NFSV4OPEN_WANTWRITEDELEG:
2796 stp->ls_flags |= NFSLCK_WANTWDELEG;
2797 i &= ~NFSV4OPEN_WANTDELEGMASK;
2799 case NFSV4OPEN_WANTNODELEG:
2800 stp->ls_flags |= NFSLCK_WANTNODELEG;
2801 i &= ~NFSV4OPEN_WANTDELEGMASK;
2803 case NFSV4OPEN_WANTCANCEL:
2804 printf("NFSv4: ignore Open WantCancel\n");
2805 i &= ~NFSV4OPEN_WANTDELEGMASK;
2808 /* nd_repstat will be set to NFSERR_INVAL below. */
2813 case NFSV4OPEN_ACCESSREAD:
2814 stp->ls_flags |= NFSLCK_READACCESS;
2816 case NFSV4OPEN_ACCESSWRITE:
2817 stp->ls_flags |= NFSLCK_WRITEACCESS;
2819 case NFSV4OPEN_ACCESSBOTH:
2820 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2823 nd->nd_repstat = NFSERR_INVAL;
2825 i = fxdr_unsigned(int, *tl++);
2827 case NFSV4OPEN_DENYNONE:
2829 case NFSV4OPEN_DENYREAD:
2830 stp->ls_flags |= NFSLCK_READDENY;
2832 case NFSV4OPEN_DENYWRITE:
2833 stp->ls_flags |= NFSLCK_WRITEDENY;
2835 case NFSV4OPEN_DENYBOTH:
2836 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2839 nd->nd_repstat = NFSERR_INVAL;
2841 clientid.lval[0] = *tl++;
2842 clientid.lval[1] = *tl;
2843 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2844 if ((nd->nd_flag & ND_NFSV41) != 0)
2845 clientid.qval = nd->nd_clientid.qval;
2846 else if (nd->nd_clientid.qval != clientid.qval)
2847 printf("EEK7 multiple clids\n");
2849 if ((nd->nd_flag & ND_NFSV41) != 0)
2850 printf("EEK! no clientid from session\n");
2851 nd->nd_flag |= ND_IMPLIEDCLID;
2852 nd->nd_clientid.qval = clientid.qval;
2854 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2857 NFSVNO_ATTRINIT(&nva);
2858 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2859 create = fxdr_unsigned(int, *tl);
2860 if (!nd->nd_repstat)
2861 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2862 if (create == NFSV4OPEN_CREATE) {
2865 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2866 how = fxdr_unsigned(int, *tl);
2868 case NFSCREATE_UNCHECKED:
2869 case NFSCREATE_GUARDED:
2870 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2874 * If the na_gid being set is the same as that of
2875 * the directory it is going in, clear it, since
2876 * that is what will be set by default. This allows
2877 * a user that isn't in that group to do the create.
2879 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2880 nva.na_gid == dirfor.na_gid)
2881 NFSVNO_UNSET(&nva, gid);
2882 if (!nd->nd_repstat)
2883 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2885 case NFSCREATE_EXCLUSIVE:
2886 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2890 case NFSCREATE_EXCLUSIVE41:
2891 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2894 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2897 if (NFSISSET_ATTRBIT(&attrbits,
2898 NFSATTRBIT_TIMEACCESSSET))
2899 nd->nd_repstat = NFSERR_INVAL;
2901 * If the na_gid being set is the same as that of
2902 * the directory it is going in, clear it, since
2903 * that is what will be set by default. This allows
2904 * a user that isn't in that group to do the create.
2906 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2907 nva.na_gid == dirfor.na_gid)
2908 NFSVNO_UNSET(&nva, gid);
2909 if (nd->nd_repstat == 0)
2910 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2913 nd->nd_repstat = NFSERR_BADXDR;
2916 } else if (create != NFSV4OPEN_NOCREATE) {
2917 nd->nd_repstat = NFSERR_BADXDR;
2922 * Now, handle the claim, which usually includes looking up a
2923 * name in the directory referenced by dp. The exception is
2924 * NFSV4OPEN_CLAIMPREVIOUS.
2926 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2927 claim = fxdr_unsigned(int, *tl);
2928 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2929 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2930 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2931 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2932 stp->ls_flags |= NFSLCK_DELEGCUR;
2933 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2934 stp->ls_flags |= NFSLCK_DELEGPREV;
2936 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2937 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2938 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2939 claim != NFSV4OPEN_CLAIMNULL)
2940 nd->nd_repstat = NFSERR_INVAL;
2941 if (nd->nd_repstat) {
2942 nd->nd_repstat = nfsrv_opencheck(clientid,
2943 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2946 if (create == NFSV4OPEN_CREATE)
2947 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2948 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2950 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2951 LOCKLEAF | SAVESTART);
2952 nfsvno_setpathbuf(&named, &bufp, &hashp);
2953 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2956 #ifdef NFS4_ACL_EXTATTR_NAME
2959 free(stp, M_NFSDSTATE);
2960 nfsvno_relpathbuf(&named);
2961 NFSEXITCODE2(error, nd);
2964 if (!nd->nd_repstat) {
2965 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2969 nfsvno_relpathbuf(&named);
2971 if (create == NFSV4OPEN_CREATE) {
2973 case NFSCREATE_UNCHECKED:
2976 * Clear the setable attribute bits, except
2977 * for Size, if it is being truncated.
2979 NFSZERO_ATTRBIT(&attrbits);
2980 if (NFSVNO_ISSETSIZE(&nva))
2981 NFSSETBIT_ATTRBIT(&attrbits,
2985 case NFSCREATE_GUARDED:
2986 if (named.ni_vp && !nd->nd_repstat)
2987 nd->nd_repstat = EEXIST;
2989 case NFSCREATE_EXCLUSIVE:
2994 case NFSCREATE_EXCLUSIVE41:
2999 nfsvno_open(nd, &named, clientid, &stateid, stp,
3000 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3001 nd->nd_cred, exp, &vp);
3002 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3003 NFSV4OPEN_CLAIMFH) {
3004 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3005 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3006 i = fxdr_unsigned(int, *tl);
3008 case NFSV4OPEN_DELEGATEREAD:
3009 stp->ls_flags |= NFSLCK_DELEGREAD;
3011 case NFSV4OPEN_DELEGATEWRITE:
3012 stp->ls_flags |= NFSLCK_DELEGWRITE;
3013 case NFSV4OPEN_DELEGATENONE:
3016 nd->nd_repstat = NFSERR_BADXDR;
3019 stp->ls_flags |= NFSLCK_RECLAIM;
3022 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3023 nd->nd_repstat = NFSERR_INVAL;
3026 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3027 if ((vp->v_iflag & VI_DOOMED) == 0)
3028 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3029 stp, vp, nd, p, nd->nd_repstat);
3031 nd->nd_repstat = NFSERR_PERM;
3033 nd->nd_repstat = NFSERR_BADXDR;
3038 * Do basic access checking.
3040 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3042 * The IETF working group decided that this is the correct
3043 * error return for all non-regular files.
3045 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3047 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3048 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3049 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3050 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3051 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3052 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3054 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3055 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
3056 NFSACCCHK_VPISLOCKED, NULL);
3059 if (!nd->nd_repstat) {
3060 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3061 if (!nd->nd_repstat) {
3062 tverf[0] = nva.na_atime.tv_sec;
3063 tverf[1] = nva.na_atime.tv_nsec;
3066 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3067 cverf[1] != tverf[1]))
3068 nd->nd_repstat = EEXIST;
3070 * Do the open locking/delegation stuff.
3072 if (!nd->nd_repstat)
3073 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3074 &delegstateid, &rflags, exp, p, nva.na_filerev);
3077 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3078 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3079 * (ie: Leave the NFSVOPUNLOCK() about here.)
3082 NFSVOPUNLOCK(vp, 0);
3084 free(stp, M_NFSDSTATE);
3085 if (!nd->nd_repstat && dirp)
3086 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3087 if (!nd->nd_repstat) {
3088 /* For NFSv4.1, set the Current StateID. */
3089 if ((nd->nd_flag & ND_NFSV41) != 0) {
3090 nd->nd_curstateid = stateid;
3091 nd->nd_flag |= ND_CURSTATEID;
3093 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3094 *tl++ = txdr_unsigned(stateid.seqid);
3095 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3096 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3097 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3098 *tl++ = newnfs_true;
3104 *tl++ = newnfs_false; /* Since dirp is not locked */
3105 txdr_hyper(dirfor.na_filerev, tl);
3107 txdr_hyper(diraft.na_filerev, tl);
3110 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3111 (void) nfsrv_putattrbit(nd, &attrbits);
3112 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3113 if (rflags & NFSV4OPEN_READDELEGATE)
3114 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3115 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3116 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3117 else if (retext != 0) {
3118 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3119 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3121 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3122 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3123 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3124 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3125 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3126 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3127 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3129 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3130 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3131 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3134 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3135 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3138 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3139 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3140 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3141 *tl++ = txdr_unsigned(delegstateid.seqid);
3142 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3144 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3145 if (rflags & NFSV4OPEN_RECALL)
3149 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3150 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3151 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3152 txdr_hyper(nva.na_size, tl);
3154 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3155 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3156 *tl++ = txdr_unsigned(0x0);
3157 acemask = NFSV4ACE_ALLFILESMASK;
3158 if (nva.na_mode & S_IRUSR)
3159 acemask |= NFSV4ACE_READMASK;
3160 if (nva.na_mode & S_IWUSR)
3161 acemask |= NFSV4ACE_WRITEMASK;
3162 if (nva.na_mode & S_IXUSR)
3163 acemask |= NFSV4ACE_EXECUTEMASK;
3164 *tl = txdr_unsigned(acemask);
3165 (void) nfsm_strtom(nd, "OWNER@", 6);
3173 #ifdef NFS4_ACL_EXTATTR_NAME
3176 NFSEXITCODE2(0, nd);
3180 #ifdef NFS4_ACL_EXTATTR_NAME
3184 free(stp, M_NFSDSTATE);
3185 NFSEXITCODE2(error, nd);
3190 * nfsv4 close service
3193 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3194 vnode_t vp, __unused struct nfsexstuff *exp)
3197 struct nfsstate st, *stp = &st;
3198 int error = 0, writeacc;
3199 nfsv4stateid_t stateid;
3202 struct thread *p = curthread;
3204 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3205 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3206 stp->ls_ownerlen = 0;
3207 stp->ls_op = nd->nd_rp;
3208 stp->ls_uid = nd->nd_cred->cr_uid;
3209 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3210 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3214 * For the special stateid of other all 0s and seqid == 1, set the
3215 * stateid to the current stateid, if it is set.
3217 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3218 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3219 stp->ls_stateid.other[2] == 0) {
3220 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3221 stp->ls_stateid = nd->nd_curstateid;
3223 nd->nd_repstat = NFSERR_BADSTATEID;
3228 stp->ls_flags = NFSLCK_CLOSE;
3229 clientid.lval[0] = stp->ls_stateid.other[0];
3230 clientid.lval[1] = stp->ls_stateid.other[1];
3231 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3232 if ((nd->nd_flag & ND_NFSV41) != 0)
3233 clientid.qval = nd->nd_clientid.qval;
3234 else if (nd->nd_clientid.qval != clientid.qval)
3235 printf("EEK8 multiple clids\n");
3237 if ((nd->nd_flag & ND_NFSV41) != 0)
3238 printf("EEK! no clientid from session\n");
3239 nd->nd_flag |= ND_IMPLIEDCLID;
3240 nd->nd_clientid.qval = clientid.qval;
3242 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3244 /* For pNFS, update the attributes. */
3245 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3246 nfsrv_updatemdsattr(vp, &na, p);
3248 if (!nd->nd_repstat) {
3250 * If the stateid that has been closed is the current stateid,
3253 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3254 stateid.other[0] == nd->nd_curstateid.other[0] &&
3255 stateid.other[1] == nd->nd_curstateid.other[1] &&
3256 stateid.other[2] == nd->nd_curstateid.other[2])
3257 nd->nd_flag &= ~ND_CURSTATEID;
3258 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3259 *tl++ = txdr_unsigned(stateid.seqid);
3260 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3262 NFSEXITCODE2(0, nd);
3266 NFSEXITCODE2(error, nd);
3271 * nfsv4 delegpurge service
3274 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3275 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3280 struct thread *p = curthread;
3282 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3283 nd->nd_repstat = NFSERR_WRONGSEC;
3286 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3287 clientid.lval[0] = *tl++;
3288 clientid.lval[1] = *tl;
3289 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3290 if ((nd->nd_flag & ND_NFSV41) != 0)
3291 clientid.qval = nd->nd_clientid.qval;
3292 else if (nd->nd_clientid.qval != clientid.qval)
3293 printf("EEK9 multiple clids\n");
3295 if ((nd->nd_flag & ND_NFSV41) != 0)
3296 printf("EEK! no clientid from session\n");
3297 nd->nd_flag |= ND_IMPLIEDCLID;
3298 nd->nd_clientid.qval = clientid.qval;
3300 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3301 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3303 NFSEXITCODE2(error, nd);
3308 * nfsv4 delegreturn service
3311 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3312 vnode_t vp, __unused struct nfsexstuff *exp)
3315 int error = 0, writeacc;
3316 nfsv4stateid_t stateid;
3319 struct thread *p = curthread;
3321 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3322 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3323 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3324 clientid.lval[0] = stateid.other[0];
3325 clientid.lval[1] = stateid.other[1];
3326 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3327 if ((nd->nd_flag & ND_NFSV41) != 0)
3328 clientid.qval = nd->nd_clientid.qval;
3329 else if (nd->nd_clientid.qval != clientid.qval)
3330 printf("EEK10 multiple clids\n");
3332 if ((nd->nd_flag & ND_NFSV41) != 0)
3333 printf("EEK! no clientid from session\n");
3334 nd->nd_flag |= ND_IMPLIEDCLID;
3335 nd->nd_clientid.qval = clientid.qval;
3337 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3338 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3339 /* For pNFS, update the attributes. */
3340 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3341 nfsrv_updatemdsattr(vp, &na, p);
3344 NFSEXITCODE2(error, nd);
3349 * nfsv4 get file handle service
3352 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3353 vnode_t vp, __unused struct nfsexstuff *exp)
3356 struct thread *p = curthread;
3358 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3360 if (!nd->nd_repstat)
3361 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3362 NFSEXITCODE2(0, nd);
3367 * nfsv4 open confirm service
3370 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3371 vnode_t vp, __unused struct nfsexstuff *exp)
3374 struct nfsstate st, *stp = &st;
3376 nfsv4stateid_t stateid;
3378 struct thread *p = curthread;
3380 if ((nd->nd_flag & ND_NFSV41) != 0) {
3381 nd->nd_repstat = NFSERR_NOTSUPP;
3384 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3385 stp->ls_ownerlen = 0;
3386 stp->ls_op = nd->nd_rp;
3387 stp->ls_uid = nd->nd_cred->cr_uid;
3388 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3389 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3391 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3392 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3393 stp->ls_flags = NFSLCK_CONFIRM;
3394 clientid.lval[0] = stp->ls_stateid.other[0];
3395 clientid.lval[1] = stp->ls_stateid.other[1];
3396 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3397 if ((nd->nd_flag & ND_NFSV41) != 0)
3398 clientid.qval = nd->nd_clientid.qval;
3399 else if (nd->nd_clientid.qval != clientid.qval)
3400 printf("EEK11 multiple clids\n");
3402 if ((nd->nd_flag & ND_NFSV41) != 0)
3403 printf("EEK! no clientid from session\n");
3404 nd->nd_flag |= ND_IMPLIEDCLID;
3405 nd->nd_clientid.qval = clientid.qval;
3407 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3409 if (!nd->nd_repstat) {
3410 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3411 *tl++ = txdr_unsigned(stateid.seqid);
3412 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3416 NFSEXITCODE2(error, nd);
3421 * nfsv4 open downgrade service
3424 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3425 vnode_t vp, __unused struct nfsexstuff *exp)
3429 struct nfsstate st, *stp = &st;
3431 nfsv4stateid_t stateid;
3433 struct thread *p = curthread;
3435 /* opendowngrade can only work on a file object.*/
3436 if (vp->v_type != VREG) {
3437 error = NFSERR_INVAL;
3440 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3441 stp->ls_ownerlen = 0;
3442 stp->ls_op = nd->nd_rp;
3443 stp->ls_uid = nd->nd_cred->cr_uid;
3444 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3445 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3447 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3450 * For the special stateid of other all 0s and seqid == 1, set the
3451 * stateid to the current stateid, if it is set.
3453 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3454 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3455 stp->ls_stateid.other[2] == 0) {
3456 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3457 stp->ls_stateid = nd->nd_curstateid;
3459 nd->nd_repstat = NFSERR_BADSTATEID;
3464 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3465 i = fxdr_unsigned(int, *tl++);
3466 if ((nd->nd_flag & ND_NFSV41) != 0)
3467 i &= ~NFSV4OPEN_WANTDELEGMASK;
3469 case NFSV4OPEN_ACCESSREAD:
3470 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3472 case NFSV4OPEN_ACCESSWRITE:
3473 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3475 case NFSV4OPEN_ACCESSBOTH:
3476 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3480 nd->nd_repstat = NFSERR_INVAL;
3482 i = fxdr_unsigned(int, *tl);
3484 case NFSV4OPEN_DENYNONE:
3486 case NFSV4OPEN_DENYREAD:
3487 stp->ls_flags |= NFSLCK_READDENY;
3489 case NFSV4OPEN_DENYWRITE:
3490 stp->ls_flags |= NFSLCK_WRITEDENY;
3492 case NFSV4OPEN_DENYBOTH:
3493 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3496 nd->nd_repstat = NFSERR_INVAL;
3499 clientid.lval[0] = stp->ls_stateid.other[0];
3500 clientid.lval[1] = stp->ls_stateid.other[1];
3501 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3502 if ((nd->nd_flag & ND_NFSV41) != 0)
3503 clientid.qval = nd->nd_clientid.qval;
3504 else if (nd->nd_clientid.qval != clientid.qval)
3505 printf("EEK12 multiple clids\n");
3507 if ((nd->nd_flag & ND_NFSV41) != 0)
3508 printf("EEK! no clientid from session\n");
3509 nd->nd_flag |= ND_IMPLIEDCLID;
3510 nd->nd_clientid.qval = clientid.qval;
3512 if (!nd->nd_repstat)
3513 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3515 if (!nd->nd_repstat) {
3516 /* For NFSv4.1, set the Current StateID. */
3517 if ((nd->nd_flag & ND_NFSV41) != 0) {
3518 nd->nd_curstateid = stateid;
3519 nd->nd_flag |= ND_CURSTATEID;
3521 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3522 *tl++ = txdr_unsigned(stateid.seqid);
3523 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3527 NFSEXITCODE2(error, nd);
3532 * nfsv4 renew lease service
3535 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3536 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3541 struct thread *p = curthread;
3543 if ((nd->nd_flag & ND_NFSV41) != 0) {
3544 nd->nd_repstat = NFSERR_NOTSUPP;
3547 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3548 nd->nd_repstat = NFSERR_WRONGSEC;
3551 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3552 clientid.lval[0] = *tl++;
3553 clientid.lval[1] = *tl;
3554 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3555 if ((nd->nd_flag & ND_NFSV41) != 0)
3556 clientid.qval = nd->nd_clientid.qval;
3557 else if (nd->nd_clientid.qval != clientid.qval)
3558 printf("EEK13 multiple clids\n");
3560 if ((nd->nd_flag & ND_NFSV41) != 0)
3561 printf("EEK! no clientid from session\n");
3562 nd->nd_flag |= ND_IMPLIEDCLID;
3563 nd->nd_clientid.qval = clientid.qval;
3565 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3566 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3568 NFSEXITCODE2(error, nd);
3573 * nfsv4 security info service
3576 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3577 vnode_t dp, struct nfsexstuff *exp)
3581 struct nameidata named;
3582 vnode_t dirp = NULL, vp;
3584 struct nfsexstuff retnes;
3586 int error = 0, savflag, i;
3589 struct thread *p = curthread;
3592 * All this just to get the export flags for the name.
3594 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3595 LOCKLEAF | SAVESTART);
3596 nfsvno_setpathbuf(&named, &bufp, &hashp);
3597 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3600 nfsvno_relpathbuf(&named);
3603 if (!nd->nd_repstat) {
3604 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3607 nfsvno_relpathbuf(&named);
3613 vrele(named.ni_startdir);
3614 nfsvno_relpathbuf(&named);
3615 fh.nfsrvfh_len = NFSX_MYFH;
3617 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3619 savflag = nd->nd_flag;
3620 if (!nd->nd_repstat) {
3621 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
3625 nd->nd_flag = savflag;
3630 * Finally have the export flags for name, so we can create
3631 * the security info.
3634 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3635 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3636 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3637 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3638 *tl = txdr_unsigned(RPCAUTH_UNIX);
3640 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3641 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3642 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3643 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3644 nfsgss_mechlist[KERBV_MECH].len);
3645 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3646 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3647 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3649 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3650 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3651 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3652 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3653 nfsgss_mechlist[KERBV_MECH].len);
3654 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3655 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3656 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3658 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3659 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3660 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3661 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3662 nfsgss_mechlist[KERBV_MECH].len);
3663 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3664 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3665 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3669 *sizp = txdr_unsigned(len);
3672 NFSEXITCODE2(error, nd);
3677 * nfsv4 set client id service
3680 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3681 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3685 int error = 0, idlen;
3686 struct nfsclient *clp = NULL;
3688 struct sockaddr_in *rin;
3691 struct sockaddr_in6 *rin6;
3693 #if defined(INET) || defined(INET6)
3696 u_char *verf, *addrbuf;
3697 nfsquad_t clientid, confirm;
3698 struct thread *p = curthread;
3700 if ((nd->nd_flag & ND_NFSV41) != 0) {
3701 nd->nd_repstat = NFSERR_NOTSUPP;
3704 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3705 nd->nd_repstat = NFSERR_WRONGSEC;
3708 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3709 verf = (u_char *)tl;
3710 tl += (NFSX_VERF / NFSX_UNSIGNED);
3711 i = fxdr_unsigned(int, *tl);
3712 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3713 nd->nd_repstat = NFSERR_BADXDR;
3717 if (nd->nd_flag & ND_GSS)
3718 i += nd->nd_princlen;
3719 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3721 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3722 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3723 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3724 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3725 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3727 clp->lc_req.nr_cred = NULL;
3728 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3729 clp->lc_idlen = idlen;
3730 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3733 if (nd->nd_flag & ND_GSS) {
3734 clp->lc_flags = LCL_GSS;
3735 if (nd->nd_flag & ND_GSSINTEGRITY)
3736 clp->lc_flags |= LCL_GSSINTEGRITY;
3737 else if (nd->nd_flag & ND_GSSPRIVACY)
3738 clp->lc_flags |= LCL_GSSPRIVACY;
3742 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3743 clp->lc_flags |= LCL_NAME;
3744 clp->lc_namelen = nd->nd_princlen;
3745 clp->lc_name = &clp->lc_id[idlen];
3746 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3748 clp->lc_uid = nd->nd_cred->cr_uid;
3749 clp->lc_gid = nd->nd_cred->cr_gid;
3751 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3752 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3753 error = nfsrv_getclientipaddr(nd, clp);
3756 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3757 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3760 * nfsrv_setclient() does the actual work of adding it to the
3761 * client list. If there is no error, the structure has been
3762 * linked into the client list and clp should no longer be used
3763 * here. When an error is returned, it has not been linked in,
3764 * so it should be free'd.
3766 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3767 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3769 * 8 is the maximum length of the port# string.
3771 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3772 switch (clp->lc_req.nr_nam->sa_family) {
3775 if (clp->lc_flags & LCL_TCPCALLBACK)
3776 (void) nfsm_strtom(nd, "tcp", 3);
3778 (void) nfsm_strtom(nd, "udp", 3);
3779 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3780 ucp = (u_char *)&rin->sin_addr.s_addr;
3781 ucp2 = (u_char *)&rin->sin_port;
3782 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3783 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3784 ucp2[0] & 0xff, ucp2[1] & 0xff);
3789 if (clp->lc_flags & LCL_TCPCALLBACK)
3790 (void) nfsm_strtom(nd, "tcp6", 4);
3792 (void) nfsm_strtom(nd, "udp6", 4);
3793 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3794 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3800 ucp2 = (u_char *)&rin6->sin6_port;
3801 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3806 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3807 free(addrbuf, M_TEMP);
3810 free(clp->lc_req.nr_nam, M_SONAME);
3811 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3812 free(clp->lc_stateid, M_NFSDCLIENT);
3813 free(clp, M_NFSDCLIENT);
3815 if (!nd->nd_repstat) {
3816 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3817 *tl++ = clientid.lval[0];
3818 *tl++ = clientid.lval[1];
3819 *tl++ = confirm.lval[0];
3820 *tl = confirm.lval[1];
3824 NFSEXITCODE2(0, nd);
3828 free(clp->lc_req.nr_nam, M_SONAME);
3829 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3830 free(clp->lc_stateid, M_NFSDCLIENT);
3831 free(clp, M_NFSDCLIENT);
3833 NFSEXITCODE2(error, nd);
3838 * nfsv4 set client id confirm service
3841 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3842 __unused int isdgram, __unused vnode_t vp,
3843 __unused struct nfsexstuff *exp)
3847 nfsquad_t clientid, confirm;
3848 struct thread *p = curthread;
3850 if ((nd->nd_flag & ND_NFSV41) != 0) {
3851 nd->nd_repstat = NFSERR_NOTSUPP;
3854 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3855 nd->nd_repstat = NFSERR_WRONGSEC;
3858 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3859 clientid.lval[0] = *tl++;
3860 clientid.lval[1] = *tl++;
3861 confirm.lval[0] = *tl++;
3862 confirm.lval[1] = *tl;
3865 * nfsrv_getclient() searches the client list for a match and
3866 * returns the appropriate NFSERR status.
3868 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3869 NULL, NULL, confirm, 0, nd, p);
3871 NFSEXITCODE2(error, nd);
3876 * nfsv4 verify service
3879 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3880 vnode_t vp, __unused struct nfsexstuff *exp)
3882 int error = 0, ret, fhsize = NFSX_MYFH;
3883 struct nfsvattr nva;
3885 struct nfsfsinfo fs;
3887 struct thread *p = curthread;
3889 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3890 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3891 if (!nd->nd_repstat)
3892 nd->nd_repstat = nfsvno_statfs(vp, sf);
3893 if (!nd->nd_repstat)
3894 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3895 if (!nd->nd_repstat) {
3896 nfsvno_getfs(&fs, isdgram);
3897 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3898 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3900 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3902 nd->nd_repstat = NFSERR_SAME;
3903 else if (ret != NFSERR_NOTSAME)
3904 nd->nd_repstat = ret;
3906 nd->nd_repstat = ret;
3911 NFSEXITCODE2(error, nd);
3919 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3920 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3921 __unused struct nfsexstuff *exp)
3924 int error = 0, createdir __unused;
3926 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3927 createdir = fxdr_unsigned(int, *tl);
3928 nd->nd_repstat = NFSERR_NOTSUPP;
3931 NFSEXITCODE2(error, nd);
3936 * nfsv4 release lock owner service
3939 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3940 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3943 struct nfsstate *stp = NULL;
3946 struct thread *p = curthread;
3948 if ((nd->nd_flag & ND_NFSV41) != 0) {
3949 nd->nd_repstat = NFSERR_NOTSUPP;
3952 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3953 nd->nd_repstat = NFSERR_WRONGSEC;
3956 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3957 len = fxdr_unsigned(int, *(tl + 2));
3958 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3959 nd->nd_repstat = NFSERR_BADXDR;
3962 stp = malloc(sizeof (struct nfsstate) + len,
3963 M_NFSDSTATE, M_WAITOK);
3964 stp->ls_ownerlen = len;
3966 stp->ls_flags = NFSLCK_RELEASE;
3967 stp->ls_uid = nd->nd_cred->cr_uid;
3968 clientid.lval[0] = *tl++;
3969 clientid.lval[1] = *tl;
3970 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3971 if ((nd->nd_flag & ND_NFSV41) != 0)
3972 clientid.qval = nd->nd_clientid.qval;
3973 else if (nd->nd_clientid.qval != clientid.qval)
3974 printf("EEK14 multiple clids\n");
3976 if ((nd->nd_flag & ND_NFSV41) != 0)
3977 printf("EEK! no clientid from session\n");
3978 nd->nd_flag |= ND_IMPLIEDCLID;
3979 nd->nd_clientid.qval = clientid.qval;
3981 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3984 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3985 free(stp, M_NFSDSTATE);
3987 NFSEXITCODE2(0, nd);
3991 free(stp, M_NFSDSTATE);
3992 NFSEXITCODE2(error, nd);
3997 * nfsv4 exchange_id service
4000 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4001 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4004 int error = 0, i, idlen;
4005 struct nfsclient *clp = NULL;
4006 nfsquad_t clientid, confirm;
4008 uint32_t sp4type, v41flags;
4009 uint64_t owner_minor;
4010 struct timespec verstime;
4012 struct sockaddr_in *sin, *rin;
4015 struct sockaddr_in6 *sin6, *rin6;
4017 struct thread *p = curthread;
4019 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4020 nd->nd_repstat = NFSERR_WRONGSEC;
4023 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4024 verf = (uint8_t *)tl;
4025 tl += (NFSX_VERF / NFSX_UNSIGNED);
4026 i = fxdr_unsigned(int, *tl);
4027 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4028 nd->nd_repstat = NFSERR_BADXDR;
4032 if (nd->nd_flag & ND_GSS)
4033 i += nd->nd_princlen;
4034 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4036 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4037 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4038 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4039 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4040 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4042 switch (nd->nd_nam->sa_family) {
4045 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4046 sin = (struct sockaddr_in *)nd->nd_nam;
4047 rin->sin_family = AF_INET;
4048 rin->sin_len = sizeof(struct sockaddr_in);
4050 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4055 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4056 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4057 rin6->sin6_family = AF_INET6;
4058 rin6->sin6_len = sizeof(struct sockaddr_in6);
4059 rin6->sin6_port = 0;
4060 rin6->sin6_addr = sin6->sin6_addr;
4064 clp->lc_req.nr_cred = NULL;
4065 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4066 clp->lc_idlen = idlen;
4067 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4070 if ((nd->nd_flag & ND_GSS) != 0) {
4071 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4072 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4073 clp->lc_flags |= LCL_GSSINTEGRITY;
4074 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4075 clp->lc_flags |= LCL_GSSPRIVACY;
4077 clp->lc_flags = LCL_NFSV41;
4078 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4079 clp->lc_flags |= LCL_NAME;
4080 clp->lc_namelen = nd->nd_princlen;
4081 clp->lc_name = &clp->lc_id[idlen];
4082 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4084 clp->lc_uid = nd->nd_cred->cr_uid;
4085 clp->lc_gid = nd->nd_cred->cr_gid;
4087 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4088 v41flags = fxdr_unsigned(uint32_t, *tl++);
4089 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4090 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4091 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4092 nd->nd_repstat = NFSERR_INVAL;
4095 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4096 confirm.lval[1] = 1;
4098 confirm.lval[1] = 0;
4099 if (nfsrv_devidcnt == 0)
4100 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4102 v41flags = NFSV4EXCH_USEPNFSMDS;
4103 sp4type = fxdr_unsigned(uint32_t, *tl);
4104 if (sp4type != NFSV4EXCH_SP4NONE) {
4105 nd->nd_repstat = NFSERR_NOTSUPP;
4110 * nfsrv_setclient() does the actual work of adding it to the
4111 * client list. If there is no error, the structure has been
4112 * linked into the client list and clp should no longer be used
4113 * here. When an error is returned, it has not been linked in,
4114 * so it should be free'd.
4116 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4118 free(clp->lc_req.nr_nam, M_SONAME);
4119 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4120 free(clp->lc_stateid, M_NFSDCLIENT);
4121 free(clp, M_NFSDCLIENT);
4123 if (nd->nd_repstat == 0) {
4124 if (confirm.lval[1] != 0)
4125 v41flags |= NFSV4EXCH_CONFIRMEDR;
4126 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4127 *tl++ = clientid.lval[0]; /* ClientID */
4128 *tl++ = clientid.lval[1];
4129 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4130 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4131 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
4132 owner_minor = 0; /* Owner */
4133 txdr_hyper(owner_minor, tl); /* Minor */
4134 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4135 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4136 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4137 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4138 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4139 *tl = txdr_unsigned(1);
4140 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4141 (void)nfsm_strtom(nd, version, strlen(version));
4142 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4143 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4144 verstime.tv_nsec = 0;
4145 txdr_nfsv4time(&verstime, tl);
4147 NFSEXITCODE2(0, nd);
4151 free(clp->lc_req.nr_nam, M_SONAME);
4152 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4153 free(clp->lc_stateid, M_NFSDCLIENT);
4154 free(clp, M_NFSDCLIENT);
4156 NFSEXITCODE2(error, nd);
4161 * nfsv4 create session service
4164 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4165 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4169 nfsquad_t clientid, confirm;
4170 struct nfsdsession *sep = NULL;
4172 struct thread *p = curthread;
4174 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4175 nd->nd_repstat = NFSERR_WRONGSEC;
4178 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4179 M_NFSDSESSION, M_WAITOK | M_ZERO);
4180 sep->sess_refcnt = 1;
4181 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4182 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4183 clientid.lval[0] = *tl++;
4184 clientid.lval[1] = *tl++;
4185 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4186 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4187 /* Persistent sessions and RDMA are not supported. */
4188 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4190 /* Fore channel attributes. */
4191 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4192 tl++; /* Header pad always 0. */
4193 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4194 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4195 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4196 printf("Consider increasing kern.ipc.maxsockbuf\n");
4198 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4199 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4200 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4201 printf("Consider increasing kern.ipc.maxsockbuf\n");
4203 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4204 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4205 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4206 if (sep->sess_maxslots > NFSV4_SLOTS)
4207 sep->sess_maxslots = NFSV4_SLOTS;
4208 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4210 nd->nd_repstat = NFSERR_BADXDR;
4212 } else if (rdmacnt == 1)
4213 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4215 /* Back channel attributes. */
4216 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4217 tl++; /* Header pad always 0. */
4218 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4219 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4220 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4221 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4222 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4223 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4225 nd->nd_repstat = NFSERR_BADXDR;
4227 } else if (rdmacnt == 1)
4228 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4230 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4231 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4234 * nfsrv_getclient() searches the client list for a match and
4235 * returns the appropriate NFSERR status.
4237 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4238 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4239 if (nd->nd_repstat == 0) {
4240 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4241 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4242 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4243 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4244 *tl++ = txdr_unsigned(sep->sess_crflags);
4246 /* Fore channel attributes. */
4248 *tl++ = txdr_unsigned(sep->sess_maxreq);
4249 *tl++ = txdr_unsigned(sep->sess_maxresp);
4250 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4251 *tl++ = txdr_unsigned(sep->sess_maxops);
4252 *tl++ = txdr_unsigned(sep->sess_maxslots);
4253 *tl++ = txdr_unsigned(1);
4254 *tl++ = txdr_unsigned(0); /* No RDMA. */
4256 /* Back channel attributes. */
4258 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4259 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4260 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4261 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4262 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4263 *tl++ = txdr_unsigned(1);
4264 *tl = txdr_unsigned(0); /* No RDMA. */
4267 if (nd->nd_repstat != 0 && sep != NULL)
4268 free(sep, M_NFSDSESSION);
4269 NFSEXITCODE2(error, nd);
4274 * nfsv4 sequence service
4277 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4278 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4281 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4282 int cache_this, error = 0;
4283 struct thread *p = curthread;
4285 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4286 nd->nd_repstat = NFSERR_WRONGSEC;
4289 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4290 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4291 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4292 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4293 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4294 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4295 if (*tl == newnfs_true)
4299 nd->nd_flag |= ND_HASSEQUENCE;
4300 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4301 &target_highest_slotid, cache_this, &sflags, p);
4302 if (nd->nd_repstat == 0) {
4303 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4304 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4305 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4306 *tl++ = txdr_unsigned(sequenceid);
4307 *tl++ = txdr_unsigned(nd->nd_slotid);
4308 *tl++ = txdr_unsigned(highest_slotid);
4309 *tl++ = txdr_unsigned(target_highest_slotid);
4310 *tl = txdr_unsigned(sflags);
4313 NFSEXITCODE2(error, nd);
4318 * nfsv4 reclaim complete service
4321 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4322 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4325 int error = 0, onefs;
4327 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4328 nd->nd_repstat = NFSERR_WRONGSEC;
4331 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4333 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4334 * to be used after a file system has been transferred to a different
4335 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4336 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4337 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4338 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4339 * NFS_OK without doing anything.
4342 if (*tl == newnfs_true)
4344 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4346 NFSEXITCODE2(error, nd);
4351 * nfsv4 destroy clientid service
4354 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4355 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4360 struct thread *p = curthread;
4362 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4363 nd->nd_repstat = NFSERR_WRONGSEC;
4366 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4367 clientid.lval[0] = *tl++;
4368 clientid.lval[1] = *tl;
4369 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4371 NFSEXITCODE2(error, nd);
4376 * nfsv4 bind connection to session service
4379 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4380 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4383 uint8_t sessid[NFSX_V4SESSIONID];
4384 int error = 0, foreaft;
4386 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4387 nd->nd_repstat = NFSERR_WRONGSEC;
4390 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4391 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4392 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4393 foreaft = fxdr_unsigned(int, *tl++);
4394 if (*tl == newnfs_true) {
4395 /* RDMA is not supported. */
4396 nd->nd_repstat = NFSERR_NOTSUPP;
4400 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4401 if (nd->nd_repstat == 0) {
4402 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4404 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4405 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4406 *tl++ = txdr_unsigned(foreaft);
4410 NFSEXITCODE2(error, nd);
4415 * nfsv4 destroy session service
4418 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4419 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4421 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4424 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4425 nd->nd_repstat = NFSERR_WRONGSEC;
4428 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4429 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4430 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4432 NFSEXITCODE2(error, nd);
4437 * nfsv4 free stateid service
4440 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4441 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4444 nfsv4stateid_t stateid;
4446 struct thread *p = curthread;
4448 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4449 nd->nd_repstat = NFSERR_WRONGSEC;
4452 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4453 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4454 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4457 * For the special stateid of other all 0s and seqid == 1, set the
4458 * stateid to the current stateid, if it is set.
4460 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4461 stateid.other[1] == 0 && stateid.other[2] == 0) {
4462 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4463 stateid = nd->nd_curstateid;
4466 nd->nd_repstat = NFSERR_BADSTATEID;
4471 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4473 /* If the current stateid has been free'd, unset it. */
4474 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4475 stateid.other[0] == nd->nd_curstateid.other[0] &&
4476 stateid.other[1] == nd->nd_curstateid.other[1] &&
4477 stateid.other[2] == nd->nd_curstateid.other[2])
4478 nd->nd_flag &= ~ND_CURSTATEID;
4480 NFSEXITCODE2(error, nd);
4485 * nfsv4 layoutget service
4488 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4489 vnode_t vp, struct nfsexstuff *exp)
4492 nfsv4stateid_t stateid;
4493 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4494 uint64_t offset, len, minlen;
4496 struct thread *p = curthread;
4498 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4499 nd->nd_repstat = NFSERR_WRONGSEC;
4502 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4504 tl++; /* Signal layout available. Ignore for now. */
4505 layouttype = fxdr_unsigned(int, *tl++);
4506 iomode = fxdr_unsigned(int, *tl++);
4507 offset = fxdr_hyper(tl); tl += 2;
4508 len = fxdr_hyper(tl); tl += 2;
4509 minlen = fxdr_hyper(tl); tl += 2;
4510 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4511 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4512 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4513 maxcnt = fxdr_unsigned(int, *tl);
4514 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4515 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4518 (minlen != UINT64_MAX && offset + minlen < offset) ||
4519 (len != UINT64_MAX && offset + len < offset)) {
4520 nd->nd_repstat = NFSERR_INVAL;
4525 * For the special stateid of other all 0s and seqid == 1, set the
4526 * stateid to the current stateid, if it is set.
4528 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4529 stateid.other[1] == 0 && stateid.other[2] == 0) {
4530 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4531 stateid = nd->nd_curstateid;
4534 nd->nd_repstat = NFSERR_BADSTATEID;
4540 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4541 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4542 else if (layouttype == NFSLAYOUT_FLEXFILE)
4543 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4546 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4548 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4549 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4550 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4551 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4553 if (nd->nd_repstat == 0) {
4554 /* For NFSv4.1, set the Current StateID. */
4555 if ((nd->nd_flag & ND_NFSV41) != 0) {
4556 nd->nd_curstateid = stateid;
4557 nd->nd_flag |= ND_CURSTATEID;
4559 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4561 *tl++ = txdr_unsigned(retonclose);
4562 *tl++ = txdr_unsigned(stateid.seqid);
4563 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4564 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4565 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4566 txdr_hyper(offset, tl); tl += 2;
4567 txdr_hyper(len, tl); tl += 2;
4568 *tl++ = txdr_unsigned(iomode);
4569 *tl = txdr_unsigned(layouttype);
4570 nfsm_strtom(nd, layp, layoutlen);
4571 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4572 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4578 NFSEXITCODE2(error, nd);
4583 * nfsv4 layoutcommit service
4586 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4587 vnode_t vp, struct nfsexstuff *exp)
4590 nfsv4stateid_t stateid;
4591 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4593 uint64_t offset, len, newoff, newsize;
4594 struct timespec newmtime;
4596 struct thread *p = curthread;
4599 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4600 nd->nd_repstat = NFSERR_WRONGSEC;
4603 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4605 offset = fxdr_hyper(tl); tl += 2;
4606 len = fxdr_hyper(tl); tl += 2;
4607 reclaim = fxdr_unsigned(int, *tl++);
4608 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4609 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4610 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4612 * For the special stateid of other all 0s and seqid == 1, set the
4613 * stateid to the current stateid, if it is set.
4615 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4616 stateid.other[1] == 0 && stateid.other[2] == 0) {
4617 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4618 stateid = nd->nd_curstateid;
4621 nd->nd_repstat = NFSERR_BADSTATEID;
4626 hasnewoff = fxdr_unsigned(int, *tl);
4627 if (hasnewoff != 0) {
4628 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4629 newoff = fxdr_hyper(tl); tl += 2;
4631 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4632 hasnewmtime = fxdr_unsigned(int, *tl);
4633 if (hasnewmtime != 0) {
4634 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4635 fxdr_nfsv4time(tl, &newmtime);
4636 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4638 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4639 layouttype = fxdr_unsigned(int, *tl++);
4640 maxcnt = fxdr_unsigned(int, *tl);
4642 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4643 error = nfsrv_mtostr(nd, layp, maxcnt);
4647 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4648 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4649 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4650 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4651 if (nd->nd_repstat == 0) {
4652 if (hasnewsize != 0) {
4653 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4654 *tl++ = newnfs_true;
4655 txdr_hyper(newsize, tl);
4657 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4664 NFSEXITCODE2(error, nd);
4669 * nfsv4 layoutreturn service
4672 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4673 vnode_t vp, struct nfsexstuff *exp)
4675 uint32_t *tl, *layp;
4676 nfsv4stateid_t stateid;
4677 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4678 uint64_t offset, len;
4679 struct thread *p = curthread;
4682 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4683 nd->nd_repstat = NFSERR_WRONGSEC;
4686 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4688 layouttype = fxdr_unsigned(int, *tl++);
4689 iomode = fxdr_unsigned(int, *tl++);
4690 kind = fxdr_unsigned(int, *tl);
4691 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4692 layouttype, iomode, kind);
4693 if (kind == NFSV4LAYOUTRET_FILE) {
4694 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4696 offset = fxdr_hyper(tl); tl += 2;
4697 len = fxdr_hyper(tl); tl += 2;
4698 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4699 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4700 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4703 * For the special stateid of other all 0s and seqid == 1, set
4704 * the stateid to the current stateid, if it is set.
4706 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4707 stateid.other[1] == 0 && stateid.other[2] == 0) {
4708 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4709 stateid = nd->nd_curstateid;
4712 nd->nd_repstat = NFSERR_BADSTATEID;
4717 maxcnt = fxdr_unsigned(int, *tl);
4719 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4720 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4725 if (reclaim == newnfs_true) {
4726 nd->nd_repstat = NFSERR_INVAL;
4732 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4733 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4735 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4737 if (nd->nd_repstat == 0) {
4738 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4741 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4742 *tl++ = txdr_unsigned(stateid.seqid);
4743 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4750 NFSEXITCODE2(error, nd);
4755 * nfsv4 getdeviceinfo service
4758 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
4759 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4761 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
4762 int cnt, devaddrlen, error = 0, i, layouttype;
4763 char devid[NFSX_V4DEVICEID], *devaddr;
4766 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4767 nd->nd_repstat = NFSERR_WRONGSEC;
4770 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4771 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4772 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4773 layouttype = fxdr_unsigned(int, *tl++);
4774 maxcnt = fxdr_unsigned(uint32_t, *tl++);
4775 cnt = fxdr_unsigned(int, *tl);
4776 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
4778 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
4779 nd->nd_repstat = NFSERR_INVAL;
4783 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
4784 for (i = 0; i < cnt; i++)
4785 notify[i] = fxdr_unsigned(uint32_t, *tl++);
4787 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
4791 * Check that the device id is not stale. Device ids are recreated
4792 * each time the nfsd threads are restarted.
4794 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
4795 if (dev_time != nfsdev_time) {
4796 nd->nd_repstat = NFSERR_NOENT;
4800 /* Look for the device id. */
4801 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
4802 notify, &devaddrlen, &devaddr);
4803 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
4804 if (nd->nd_repstat == 0) {
4805 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4806 *tl = txdr_unsigned(layouttype);
4807 nfsm_strtom(nd, devaddr, devaddrlen);
4809 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
4813 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
4814 *tl++ = txdr_unsigned(cnt);
4815 for (i = 0; i < cnt; i++)
4816 *tl++ = txdr_unsigned(notify[i]);
4817 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
4818 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4819 *tl = txdr_unsigned(maxcnt);
4822 NFSEXITCODE2(error, nd);
4827 * nfsv4 test stateid service
4830 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
4831 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4834 nfsv4stateid_t *stateidp = NULL, *tstateidp;
4835 int cnt, error = 0, i, ret;
4836 struct thread *p = curthread;
4838 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4839 nd->nd_repstat = NFSERR_WRONGSEC;
4842 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4843 cnt = fxdr_unsigned(int, *tl);
4844 if (cnt <= 0 || cnt > 1024) {
4845 nd->nd_repstat = NFSERR_BADXDR;
4848 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
4849 tstateidp = stateidp;
4850 for (i = 0; i < cnt; i++) {
4851 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4852 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
4853 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
4856 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4857 *tl = txdr_unsigned(cnt);
4858 tstateidp = stateidp;
4859 for (i = 0; i < cnt; i++) {
4860 ret = nfsrv_teststateid(nd, tstateidp, p);
4861 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4862 *tl = txdr_unsigned(ret);
4866 free(stateidp, M_TEMP);
4867 NFSEXITCODE2(error, nd);
4872 * nfsv4 service not supported
4875 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4876 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4879 nd->nd_repstat = NFSERR_NOTSUPP;
4880 NFSEXITCODE2(0, nd);