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>
38 #include "opt_inet6.h"
40 * nfs version 2, 3 and 4 server calls to vnode ops
41 * - these routines generally have 3 phases
42 * 1 - break down and validate rpc request in mbuf list
43 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
44 * function in nfsd_port.c
45 * 3 - build the rpc reply in an mbuf list
46 * For nfsv4, these functions are called for each Op within the Compound RPC.
49 #include <fs/nfs/nfsport.h>
50 #include <sys/extattr.h>
51 #include <sys/filio.h>
54 extern u_int32_t newnfs_false, newnfs_true;
55 extern __enum_uint8(vtype) nv34tov_type[8];
56 extern struct timeval nfsboottime;
57 extern int nfsrv_enable_crossmntpt;
58 extern int nfsrv_statehashsize;
59 extern int nfsrv_layouthashsize;
60 extern time_t nfsdev_time;
61 extern volatile int nfsrv_devidcnt;
62 extern int nfsd_debuglevel;
63 extern u_long sb_max_adj;
64 extern int nfsrv_pnfsatime;
65 extern int nfsrv_maxpnfsmirror;
66 extern uint32_t nfs_srvmaxio;
68 static int nfs_async = 0;
69 SYSCTL_DECL(_vfs_nfsd);
70 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
71 "Tell client that writes were synced even though they were not");
72 extern int nfsrv_doflexfile;
73 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
74 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
75 static int nfsrv_linux42server = 1;
76 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
77 &nfsrv_linux42server, 0,
78 "Enable Linux style NFSv4.2 server (non-RFC compliant)");
79 static bool nfsrv_openaccess = true;
80 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW,
82 "Enable Linux style NFSv4 Open access check");
83 static char nfsrv_scope[NFSV4_OPAQUELIMIT];
84 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN,
85 &nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope");
86 static char nfsrv_owner_major[NFSV4_OPAQUELIMIT];
87 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN,
88 &nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major");
89 static uint64_t nfsrv_owner_minor;
90 SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN,
91 &nfsrv_owner_minor, 0, "Server owner minor");
93 * Only enable this if all your exported file systems
94 * (or pNFS DSs for the pNFS case) support VOP_ALLOCATE.
96 static bool nfsrv_doallocate = false;
97 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW,
99 "Enable NFSv4.2 Allocate operation");
102 * This list defines the GSS mechanisms supported.
103 * (Don't ask me how you get these strings from the RFC stuff like
104 * iso(1), org(3)... but someone did it, so I don't need to know.)
106 static struct nfsgss_mechlist nfsgss_mechlist[] = {
107 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
111 /* local functions */
112 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
113 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
114 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
115 int *diraft_retp, nfsattrbit_t *attrbitp,
116 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
118 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
119 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
120 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
121 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
122 NFSPROC_T *p, struct nfsexstuff *exp);
125 * nfs access service (not a part of NFS V2)
128 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
129 vnode_t vp, struct nfsexstuff *exp)
132 int getret, error = 0;
134 u_int32_t testmode, nfsmode, supported = 0;
136 struct thread *p = curthread;
138 if (nd->nd_repstat) {
139 nfsrv_postopattr(nd, 1, &nva);
142 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
143 nfsmode = fxdr_unsigned(u_int32_t, *tl);
144 if ((nd->nd_flag & ND_NFSV4) &&
145 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
146 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
147 NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
148 NFSACCESS_XALIST))) {
149 nd->nd_repstat = NFSERR_INVAL;
153 if (nfsmode & NFSACCESS_READ) {
154 supported |= NFSACCESS_READ;
155 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
156 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
157 nfsmode &= ~NFSACCESS_READ;
159 if (nfsmode & NFSACCESS_MODIFY) {
160 supported |= NFSACCESS_MODIFY;
161 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
162 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
163 nfsmode &= ~NFSACCESS_MODIFY;
165 if (nfsmode & NFSACCESS_EXTEND) {
166 supported |= NFSACCESS_EXTEND;
167 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
168 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
169 nfsmode &= ~NFSACCESS_EXTEND;
171 if (nfsmode & NFSACCESS_XAREAD) {
172 supported |= NFSACCESS_XAREAD;
173 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
174 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
175 nfsmode &= ~NFSACCESS_XAREAD;
177 if (nfsmode & NFSACCESS_XAWRITE) {
178 supported |= NFSACCESS_XAWRITE;
179 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
180 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
181 nfsmode &= ~NFSACCESS_XAWRITE;
183 if (nfsmode & NFSACCESS_XALIST) {
184 supported |= NFSACCESS_XALIST;
185 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
186 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
187 nfsmode &= ~NFSACCESS_XALIST;
189 if (nfsmode & NFSACCESS_DELETE) {
190 supported |= NFSACCESS_DELETE;
191 if (vp->v_type == VDIR)
192 deletebit = VDELETE_CHILD;
195 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
196 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
197 nfsmode &= ~NFSACCESS_DELETE;
199 if (vp->v_type == VDIR)
200 testmode = NFSACCESS_LOOKUP;
202 testmode = NFSACCESS_EXECUTE;
203 if (nfsmode & testmode) {
204 supported |= (nfsmode & testmode);
205 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
206 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
207 nfsmode &= ~testmode;
209 nfsmode &= supported;
210 if (nd->nd_flag & ND_NFSV3) {
211 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
212 nfsrv_postopattr(nd, getret, &nva);
215 if (nd->nd_flag & ND_NFSV4) {
216 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
217 *tl++ = txdr_unsigned(supported);
219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
220 *tl = txdr_unsigned(nfsmode);
227 NFSEXITCODE2(error, nd);
232 * nfs getattr service
235 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
236 vnode_t vp, __unused struct nfsexstuff *exp)
240 int at_root = 0, error = 0, supports_nfsv4acls;
241 struct nfsreferral *refp;
242 nfsattrbit_t attrbits, tmpbits;
244 struct vnode *tvp = NULL;
246 uint64_t mounted_on_fileno = 0;
248 struct thread *p = curthread;
252 if (nd->nd_flag & ND_NFSV4) {
253 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
260 * Check for a referral.
262 refp = nfsv4root_getreferral(vp, NULL, 0);
264 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
269 if (nd->nd_repstat == 0) {
271 NFSSET_ATTRBIT(&tmpbits, &attrbits);
274 * GETATTR with write-only attr time_access_set and time_modify_set
275 * should return NFS4ERR_INVAL.
277 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
278 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
279 error = NFSERR_INVAL;
283 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
284 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
285 accmode |= VREAD_ACL;
287 if (NFSNONZERO_ATTRBIT(&tmpbits))
288 accmode |= VREAD_ATTRIBUTES;
290 nd->nd_repstat = nfsvno_accchk(vp, accmode,
291 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
292 NFSACCCHK_VPISLOCKED, NULL);
296 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
297 if (!nd->nd_repstat) {
298 if (nd->nd_flag & ND_NFSV4) {
299 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
300 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
302 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
304 if (nd->nd_repstat == 0) {
305 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
307 if (nfsrv_enable_crossmntpt != 0 &&
308 vp->v_type == VDIR &&
309 (vp->v_vflag & VV_ROOT) != 0 &&
311 tvp = mp->mnt_vnodecovered;
319 if ((nd->nd_repstat =
320 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
321 nd->nd_repstat = VOP_GETATTR(
322 tvp, &va, nd->nd_cred);
326 if (nd->nd_repstat == 0)
327 mounted_on_fileno = (uint64_t)
332 if (nd->nd_repstat == 0)
333 nd->nd_repstat = vfs_busy(mp, 0);
335 if (nd->nd_repstat == 0) {
336 (void)nfsvno_fillattr(nd, mp, vp, &nva,
337 &fh, 0, &attrbits, nd->nd_cred, p,
338 isdgram, 1, supports_nfsv4acls,
339 at_root, mounted_on_fileno);
346 nfsrv_fillattr(nd, &nva);
354 NFSEXITCODE2(error, nd);
359 * nfs setattr service
362 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
363 vnode_t vp, struct nfsexstuff *exp)
365 struct nfsvattr nva, nva2;
367 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
369 struct timespec guard = { 0, 0 };
370 nfsattrbit_t attrbits, retbits;
371 nfsv4stateid_t stateid;
372 NFSACL_T *aclp = NULL;
373 struct thread *p = curthread;
375 if (nd->nd_repstat) {
376 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
379 #ifdef NFS4_ACL_EXTATTR_NAME
380 aclp = acl_alloc(M_WAITOK);
384 NFSVNO_ATTRINIT(&nva);
385 if (nd->nd_flag & ND_NFSV4) {
386 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
387 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
388 stateid.other[0] = *tl++;
389 stateid.other[1] = *tl++;
390 stateid.other[2] = *tl;
391 if (stateid.other[0] == 0x55555555 &&
392 stateid.other[1] == 0x55555555 &&
393 stateid.other[2] == 0x55555555 &&
394 stateid.seqid == 0xffffffff)
397 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
401 /* For NFSv4, only va_uid is used from nva2. */
402 NFSZERO_ATTRBIT(&retbits);
403 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
404 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
406 nd->nd_repstat = preat_ret;
408 NFSZERO_ATTRBIT(&retbits);
409 if (nd->nd_flag & ND_NFSV3) {
410 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
411 gcheck = fxdr_unsigned(int, *tl);
413 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
414 fxdr_nfsv3time(tl, &guard);
416 if (!nd->nd_repstat && gcheck &&
417 (nva2.na_ctime.tv_sec != guard.tv_sec ||
418 nva2.na_ctime.tv_nsec != guard.tv_nsec))
419 nd->nd_repstat = NFSERR_NOT_SYNC;
420 if (nd->nd_repstat) {
422 #ifdef NFS4_ACL_EXTATTR_NAME
425 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
428 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
429 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
432 * Now that we have all the fields, lets do it.
433 * If the size is being changed write access is required, otherwise
434 * just check for a read only file system.
436 if (!nd->nd_repstat) {
437 if (NFSVNO_NOTSETSIZE(&nva)) {
438 if (NFSVNO_EXRDONLY(exp) ||
439 (vp->v_mount->mnt_flag & MNT_RDONLY))
440 nd->nd_repstat = EROFS;
442 if (vp->v_type != VREG)
443 nd->nd_repstat = EINVAL;
444 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
445 NFSVNO_EXSTRICTACCESS(exp))
446 nd->nd_repstat = nfsvno_accchk(vp,
447 VWRITE, nd->nd_cred, exp, p,
448 NFSACCCHK_NOOVERRIDE,
449 NFSACCCHK_VPISLOCKED, NULL);
453 * Proxy operations from the MDS are allowed via the all 0s special
456 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
457 gotproxystateid == 0)
458 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
459 &nva, &attrbits, exp, p);
461 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
463 * For V4, try setting the attributes in sets, so that the
464 * reply bitmap will be correct for an error case.
466 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
467 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
468 NFSVNO_ATTRINIT(&nva2);
469 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
470 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
471 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
473 if (!nd->nd_repstat) {
474 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
475 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
476 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
477 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
480 if (!nd->nd_repstat &&
481 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
482 NFSVNO_ATTRINIT(&nva2);
483 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
484 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
487 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
489 if (!nd->nd_repstat &&
490 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
491 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
492 NFSVNO_ATTRINIT(&nva2);
493 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
494 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
495 if (nva.na_vaflags & VA_UTIMES_NULL) {
496 nva2.na_vaflags |= VA_UTIMES_NULL;
497 NFSVNO_SETACTIVE(&nva2, vaflags);
499 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
501 if (!nd->nd_repstat) {
502 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
503 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
504 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
505 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
508 if (!nd->nd_repstat &&
509 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) {
510 NFSVNO_ATTRINIT(&nva2);
511 NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime);
512 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
515 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE);
517 if (!nd->nd_repstat &&
518 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
519 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
520 NFSVNO_ATTRINIT(&nva2);
521 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
522 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
524 if (!nd->nd_repstat) {
525 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
526 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
527 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
528 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
532 #ifdef NFS4_ACL_EXTATTR_NAME
533 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
534 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
535 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
537 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
540 } else if (!nd->nd_repstat) {
541 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
544 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
545 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
547 nd->nd_repstat = postat_ret;
550 #ifdef NFS4_ACL_EXTATTR_NAME
553 if (nd->nd_flag & ND_NFSV3)
554 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
555 else if (nd->nd_flag & ND_NFSV4)
556 (void) nfsrv_putattrbit(nd, &retbits);
557 else if (!nd->nd_repstat)
558 nfsrv_fillattr(nd, &nva);
565 #ifdef NFS4_ACL_EXTATTR_NAME
568 if (nd->nd_flag & ND_NFSV4) {
570 * For all nd_repstat, the V4 reply includes a bitmap,
571 * even NFSERR_BADXDR, which is what this will end up
574 (void) nfsrv_putattrbit(nd, &retbits);
576 NFSEXITCODE2(error, nd);
582 * (Also performs lookup parent for v4)
585 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
586 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
588 struct nameidata named;
589 vnode_t vp, dirp = NULL;
590 int error = 0, dattr_ret = 1;
591 struct nfsvattr nva, dattr;
594 struct thread *p = curthread;
596 if (nd->nd_repstat) {
597 nfsrv_postopattr(nd, dattr_ret, &dattr);
602 * For some reason, if dp is a symlink, the error
603 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
605 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
606 nd->nd_repstat = NFSERR_SYMLINK;
611 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
613 nfsvno_setpathbuf(&named, &bufp, &hashp);
614 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
617 nfsvno_relpathbuf(&named);
620 if (!nd->nd_repstat) {
621 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
624 nfsvno_relpathbuf(&named);
626 if (nd->nd_repstat) {
628 if (nd->nd_flag & ND_NFSV3)
629 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
633 if (nd->nd_flag & ND_NFSV3)
634 nfsrv_postopattr(nd, dattr_ret, &dattr);
637 nfsvno_relpathbuf(&named);
639 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
640 vp->v_type != VDIR && vp->v_type != VLNK)
642 * Only allow lookup of VDIR and VLNK for traversal of
643 * non-exported volumes during NFSv4 mounting.
645 nd->nd_repstat = ENOENT;
646 if (nd->nd_repstat == 0) {
647 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
649 * EOPNOTSUPP indicates the file system cannot be exported,
650 * so just pretend the entry does not exist.
652 if (nd->nd_repstat == EOPNOTSUPP)
653 nd->nd_repstat = ENOENT;
655 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
656 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
657 if (vpp != NULL && nd->nd_repstat == 0)
662 if (nd->nd_flag & ND_NFSV3)
663 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
667 if (nd->nd_repstat) {
668 if (nd->nd_flag & ND_NFSV3)
669 nfsrv_postopattr(nd, dattr_ret, &dattr);
672 if (nd->nd_flag & ND_NFSV2) {
673 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
674 nfsrv_fillattr(nd, &nva);
675 } else if (nd->nd_flag & ND_NFSV3) {
676 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
677 nfsrv_postopattr(nd, 0, &nva);
678 nfsrv_postopattr(nd, dattr_ret, &dattr);
682 NFSEXITCODE2(error, nd);
687 * nfs readlink service
690 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
691 vnode_t vp, __unused struct nfsexstuff *exp)
694 struct mbuf *mp = NULL, *mpend = NULL;
697 struct thread *p = curthread;
700 if (nd->nd_repstat) {
701 nfsrv_postopattr(nd, getret, &nva);
704 if (vp->v_type != VLNK) {
705 if (nd->nd_flag & ND_NFSV2)
706 nd->nd_repstat = ENXIO;
708 nd->nd_repstat = EINVAL;
710 if (nd->nd_repstat == 0) {
711 if ((nd->nd_flag & ND_EXTPG) != 0)
712 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
713 nd->nd_maxextsiz, p, &mp, &mpend, &len);
715 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
716 0, p, &mp, &mpend, &len);
718 if (nd->nd_flag & ND_NFSV3)
719 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
721 if (nd->nd_flag & ND_NFSV3)
722 nfsrv_postopattr(nd, getret, &nva);
725 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
726 *tl = txdr_unsigned(len);
728 nd->nd_mb->m_next = mp;
730 if ((mpend->m_flags & M_EXTPG) != 0) {
731 nd->nd_bextpg = mpend->m_epg_npgs - 1;
732 nd->nd_bpos = (char *)(void *)
733 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
734 off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0;
735 nd->nd_bpos += off + mpend->m_epg_last_len;
736 nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len -
739 nd->nd_bpos = mtod(mpend, char *) + mpend->m_len;
751 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
752 vnode_t vp, struct nfsexstuff *exp)
755 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
756 struct mbuf *m2, *m3;
759 struct nfsstate st, *stp = &st;
760 struct nfslock lo, *lop = &lo;
761 nfsv4stateid_t stateid;
763 struct thread *p = curthread;
766 if (nd->nd_repstat) {
767 nfsrv_postopattr(nd, getret, &nva);
770 if (nd->nd_flag & ND_NFSV2) {
771 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
772 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
773 reqlen = fxdr_unsigned(int, *tl);
774 } else if (nd->nd_flag & ND_NFSV3) {
775 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
776 off = fxdr_hyper(tl);
778 reqlen = fxdr_unsigned(int, *tl);
780 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
781 reqlen = fxdr_unsigned(int, *(tl + 6));
783 if (reqlen > NFS_SRVMAXDATA(nd)) {
784 reqlen = NFS_SRVMAXDATA(nd);
785 } else if (reqlen < 0) {
790 if (nd->nd_flag & ND_NFSV4) {
791 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
792 lop->lo_flags = NFSLCK_READ;
793 stp->ls_ownerlen = 0;
795 stp->ls_uid = nd->nd_cred->cr_uid;
796 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
797 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
798 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
799 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
800 if ((nd->nd_flag & ND_NFSV41) != 0)
801 clientid.qval = nd->nd_clientid.qval;
802 else if (nd->nd_clientid.qval != clientid.qval)
803 printf("EEK1 multiple clids\n");
805 if ((nd->nd_flag & ND_NFSV41) != 0)
806 printf("EEK! no clientid from session\n");
807 nd->nd_flag |= ND_IMPLIEDCLID;
808 nd->nd_clientid.qval = clientid.qval;
810 stp->ls_stateid.other[2] = *tl++;
812 * Don't allow the client to use a special stateid for a DS op.
814 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
815 ((stp->ls_stateid.other[0] == 0x0 &&
816 stp->ls_stateid.other[1] == 0x0 &&
817 stp->ls_stateid.other[2] == 0x0) ||
818 (stp->ls_stateid.other[0] == 0xffffffff &&
819 stp->ls_stateid.other[1] == 0xffffffff &&
820 stp->ls_stateid.other[2] == 0xffffffff) ||
821 stp->ls_stateid.seqid != 0))
822 nd->nd_repstat = NFSERR_BADSTATEID;
823 /* However, allow the proxy stateid. */
824 if (stp->ls_stateid.seqid == 0xffffffff &&
825 stp->ls_stateid.other[0] == 0x55555555 &&
826 stp->ls_stateid.other[1] == 0x55555555 &&
827 stp->ls_stateid.other[2] == 0x55555555)
829 off = fxdr_hyper(tl);
832 lop->lo_end = off + reqlen;
834 * Paranoia, just in case it wraps around.
836 if (lop->lo_end < off)
837 lop->lo_end = NFS64BITSSET;
839 if (vp->v_type != VREG) {
840 if (nd->nd_flag & ND_NFSV3)
841 nd->nd_repstat = EINVAL;
843 nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
846 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
848 nd->nd_repstat = getret;
849 if (!nd->nd_repstat &&
850 (nva.na_uid != nd->nd_cred->cr_uid ||
851 NFSVNO_EXSTRICTACCESS(exp))) {
852 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
854 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
856 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
857 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
858 NFSACCCHK_VPISLOCKED, NULL);
861 * DS reads are marked by ND_DSSERVER or use the proxy special
864 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
865 ND_NFSV4 && gotproxystateid == 0)
866 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
867 &stateid, exp, nd, p);
868 if (nd->nd_repstat) {
870 if (nd->nd_flag & ND_NFSV3)
871 nfsrv_postopattr(nd, getret, &nva);
874 if (off >= nva.na_size) {
877 } else if (reqlen == 0)
879 else if ((off + reqlen) >= nva.na_size) {
880 cnt = nva.na_size - off;
887 * If cnt > MCLBYTES and the reply will not be saved, use
888 * ext_pgs mbufs for TLS.
889 * For NFSv4.0, we do not know for sure if the reply will
890 * be saved, so do not use ext_pgs mbufs for NFSv4.0.
891 * Always use ext_pgs mbufs if ND_EXTPG is set.
893 if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES &&
894 (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
895 (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
896 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
897 nd->nd_maxextsiz, p, &m3, &m2);
899 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
901 if (!(nd->nd_flag & ND_NFSV4)) {
902 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
904 nd->nd_repstat = getret;
906 if (nd->nd_repstat) {
910 if (nd->nd_flag & ND_NFSV3)
911 nfsrv_postopattr(nd, getret, &nva);
916 if (nd->nd_flag & ND_NFSV2) {
917 nfsrv_fillattr(nd, &nva);
918 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
920 if (nd->nd_flag & ND_NFSV3) {
921 nfsrv_postopattr(nd, getret, &nva);
922 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
923 *tl++ = txdr_unsigned(cnt);
925 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
929 *tl++ = newnfs_false;
931 *tl = txdr_unsigned(cnt);
933 nd->nd_mb->m_next = m3;
935 if ((m2->m_flags & M_EXTPG) != 0) {
936 nd->nd_flag |= ND_EXTPG;
937 nd->nd_bextpg = m2->m_epg_npgs - 1;
938 nd->nd_bpos = (char *)(void *)
939 PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]);
940 poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0;
941 nd->nd_bpos += poff + m2->m_epg_last_len;
942 nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len -
945 nd->nd_bpos = mtod(m2, char *) + m2->m_len;
953 NFSEXITCODE2(error, nd);
961 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
962 vnode_t vp, struct nfsexstuff *exp)
965 struct nfsvattr nva, forat;
966 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
967 int gotproxystateid, stable = NFSWRITE_FILESYNC;
969 struct nfsstate st, *stp = &st;
970 struct nfslock lo, *lop = &lo;
971 nfsv4stateid_t stateid;
973 nfsattrbit_t attrbits;
974 struct thread *p = curthread;
976 if (nd->nd_repstat) {
977 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
981 if (nd->nd_flag & ND_NFSV2) {
982 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
983 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
985 retlen = len = fxdr_unsigned(int32_t, *tl);
986 } else if (nd->nd_flag & ND_NFSV3) {
987 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
988 off = fxdr_hyper(tl);
990 stable = fxdr_unsigned(int, *tl++);
991 retlen = len = fxdr_unsigned(int32_t, *tl);
993 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
994 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
995 lop->lo_flags = NFSLCK_WRITE;
996 stp->ls_ownerlen = 0;
998 stp->ls_uid = nd->nd_cred->cr_uid;
999 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
1000 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
1001 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
1002 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
1003 if ((nd->nd_flag & ND_NFSV41) != 0)
1004 clientid.qval = nd->nd_clientid.qval;
1005 else if (nd->nd_clientid.qval != clientid.qval)
1006 printf("EEK2 multiple clids\n");
1008 if ((nd->nd_flag & ND_NFSV41) != 0)
1009 printf("EEK! no clientid from session\n");
1010 nd->nd_flag |= ND_IMPLIEDCLID;
1011 nd->nd_clientid.qval = clientid.qval;
1013 stp->ls_stateid.other[2] = *tl++;
1015 * Don't allow the client to use a special stateid for a DS op.
1017 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
1018 ((stp->ls_stateid.other[0] == 0x0 &&
1019 stp->ls_stateid.other[1] == 0x0 &&
1020 stp->ls_stateid.other[2] == 0x0) ||
1021 (stp->ls_stateid.other[0] == 0xffffffff &&
1022 stp->ls_stateid.other[1] == 0xffffffff &&
1023 stp->ls_stateid.other[2] == 0xffffffff) ||
1024 stp->ls_stateid.seqid != 0))
1025 nd->nd_repstat = NFSERR_BADSTATEID;
1026 /* However, allow the proxy stateid. */
1027 if (stp->ls_stateid.seqid == 0xffffffff &&
1028 stp->ls_stateid.other[0] == 0x55555555 &&
1029 stp->ls_stateid.other[1] == 0x55555555 &&
1030 stp->ls_stateid.other[2] == 0x55555555)
1031 gotproxystateid = 1;
1032 off = fxdr_hyper(tl);
1033 lop->lo_first = off;
1035 stable = fxdr_unsigned(int, *tl++);
1036 retlen = len = fxdr_unsigned(int32_t, *tl);
1037 lop->lo_end = off + len;
1039 * Paranoia, just in case it wraps around, which shouldn't
1040 * ever happen anyhow.
1042 if (lop->lo_end < lop->lo_first)
1043 lop->lo_end = NFS64BITSSET;
1046 if (retlen > nfs_srvmaxio || retlen < 0)
1047 nd->nd_repstat = EIO;
1048 if (vp->v_type != VREG && !nd->nd_repstat) {
1049 if (nd->nd_flag & ND_NFSV3)
1050 nd->nd_repstat = EINVAL;
1052 nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
1055 NFSZERO_ATTRBIT(&attrbits);
1056 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
1057 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
1058 if (!nd->nd_repstat)
1059 nd->nd_repstat = forat_ret;
1060 if (!nd->nd_repstat &&
1061 (forat.na_uid != nd->nd_cred->cr_uid ||
1062 NFSVNO_EXSTRICTACCESS(exp)))
1063 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
1064 nd->nd_cred, exp, p,
1065 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
1067 * DS reads are marked by ND_DSSERVER or use the proxy special
1070 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1071 ND_NFSV4 && gotproxystateid == 0)
1072 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1073 &stateid, exp, nd, p);
1074 if (nd->nd_repstat) {
1076 if (nd->nd_flag & ND_NFSV3)
1077 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1082 * For NFS Version 2, it is not obvious what a write of zero length
1083 * should do, but I might as well be consistent with Version 3,
1084 * which is to return ok so long as there are no permission problems.
1087 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1088 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1089 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1093 if (nd->nd_flag & ND_NFSV4)
1096 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1098 if (!nd->nd_repstat)
1099 nd->nd_repstat = aftat_ret;
1100 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1101 if (nd->nd_flag & ND_NFSV3)
1102 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1105 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1106 *tl++ = txdr_unsigned(retlen);
1108 * If nfs_async is set, then pretend the write was FILESYNC.
1109 * Warning: Doing this violates RFC1813 and runs a risk
1110 * of data written by a client being lost when the server
1113 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1114 *tl++ = txdr_unsigned(stable);
1116 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1118 * Actually, there is no need to txdr these fields,
1119 * but it may make the values more human readable,
1120 * for debugging purposes.
1122 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1123 *tl = txdr_unsigned(nfsboottime.tv_usec);
1124 } else if (!nd->nd_repstat)
1125 nfsrv_fillattr(nd, &nva);
1128 NFSEXITCODE2(0, nd);
1132 NFSEXITCODE2(error, nd);
1137 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1138 * now does a truncate to 0 length via. setattr if it already exists
1139 * The core creation routine has been extracted out into nfsrv_creatsub(),
1140 * so it can also be used by nfsrv_open() for V4.
1143 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1144 vnode_t dp, struct nfsexstuff *exp)
1146 struct nfsvattr nva, dirfor, diraft;
1147 struct nfsv2_sattr *sp;
1148 struct nameidata named;
1150 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1151 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1153 vnode_t vp = NULL, dirp = NULL;
1157 __enum_uint8(vtype) vtyp;
1158 int32_t cverf[2], tverf[2] = { 0, 0 };
1159 struct thread *p = curthread;
1161 if (nd->nd_repstat) {
1162 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1165 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1166 LOCKPARENT | LOCKLEAF | NOCACHE);
1167 nfsvno_setpathbuf(&named, &bufp, &hashp);
1168 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1171 if (!nd->nd_repstat) {
1172 NFSVNO_ATTRINIT(&nva);
1173 if (nd->nd_flag & ND_NFSV2) {
1174 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1175 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1178 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1179 NFSVNO_SETATTRVAL(&nva, mode,
1180 nfstov_mode(sp->sa_mode));
1181 switch (nva.na_type) {
1183 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1185 NFSVNO_SETATTRVAL(&nva, size,
1191 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1197 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1198 how = fxdr_unsigned(int, *tl);
1200 case NFSCREATE_GUARDED:
1201 case NFSCREATE_UNCHECKED:
1202 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1206 case NFSCREATE_EXCLUSIVE:
1207 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1213 NFSVNO_SETATTRVAL(&nva, type, VREG);
1216 if (nd->nd_repstat) {
1217 nfsvno_relpathbuf(&named);
1218 if (nd->nd_flag & ND_NFSV3) {
1219 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1221 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1228 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1230 if (nd->nd_flag & ND_NFSV2) {
1234 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1238 if (nd->nd_repstat) {
1239 if (nd->nd_flag & ND_NFSV3)
1240 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1247 if (!(nd->nd_flag & ND_NFSV2)) {
1249 case NFSCREATE_GUARDED:
1251 nd->nd_repstat = EEXIST;
1253 case NFSCREATE_UNCHECKED:
1255 case NFSCREATE_EXCLUSIVE:
1256 if (named.ni_vp == NULL)
1257 NFSVNO_SETATTRVAL(&nva, mode, 0);
1263 * Iff doesn't exist, create it
1264 * otherwise just truncate to 0 length
1265 * should I set the mode too ?
1267 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1268 &exclusive_flag, cverf, rdev, exp);
1270 if (!nd->nd_repstat) {
1271 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1272 if (!nd->nd_repstat)
1273 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1276 if (!nd->nd_repstat) {
1277 tverf[0] = nva.na_atime.tv_sec;
1278 tverf[1] = nva.na_atime.tv_nsec;
1281 if (nd->nd_flag & ND_NFSV2) {
1282 if (!nd->nd_repstat) {
1283 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
1284 nfsrv_fillattr(nd, &nva);
1287 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1288 || cverf[1] != tverf[1]))
1289 nd->nd_repstat = EEXIST;
1290 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1292 if (!nd->nd_repstat) {
1293 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1);
1294 nfsrv_postopattr(nd, 0, &nva);
1296 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1300 NFSEXITCODE2(0, nd);
1304 nfsvno_relpathbuf(&named);
1305 NFSEXITCODE2(error, nd);
1310 * nfs v3 mknod service (and v4 create)
1313 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1314 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1316 struct nfsvattr nva, dirfor, diraft;
1318 struct nameidata named;
1319 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1320 u_int32_t major, minor;
1321 __enum_uint8(vtype) vtyp = VNON;
1322 nfstype nfs4type = NFNON;
1323 vnode_t vp, dirp = NULL;
1324 nfsattrbit_t attrbits;
1325 char *bufp = NULL, *pathcp = NULL;
1326 u_long *hashp, cnflags;
1327 NFSACL_T *aclp = NULL;
1328 struct thread *p = curthread;
1330 NFSVNO_ATTRINIT(&nva);
1331 cnflags = LOCKPARENT;
1332 if (nd->nd_repstat) {
1333 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1336 #ifdef NFS4_ACL_EXTATTR_NAME
1337 aclp = acl_alloc(M_WAITOK);
1342 * For V4, the creation stuff is here, Yuck!
1344 if (nd->nd_flag & ND_NFSV4) {
1345 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1346 vtyp = nfsv34tov_type(*tl);
1347 nfs4type = fxdr_unsigned(nfstype, *tl);
1350 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1357 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1358 major = fxdr_unsigned(u_int32_t, *tl++);
1359 minor = fxdr_unsigned(u_int32_t, *tl);
1360 nva.na_rdev = NFSMAKEDEV(major, minor);
1366 cnflags = LOCKPARENT;
1369 nd->nd_repstat = NFSERR_BADTYPE;
1371 #ifdef NFS4_ACL_EXTATTR_NAME
1377 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1378 nfsvno_setpathbuf(&named, &bufp, &hashp);
1379 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1382 if (!nd->nd_repstat) {
1383 if (nd->nd_flag & ND_NFSV3) {
1384 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1385 vtyp = nfsv34tov_type(*tl);
1387 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1391 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1392 (vtyp == VCHR || vtyp == VBLK)) {
1393 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1394 major = fxdr_unsigned(u_int32_t, *tl++);
1395 minor = fxdr_unsigned(u_int32_t, *tl);
1396 nva.na_rdev = NFSMAKEDEV(major, minor);
1400 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1401 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1402 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1403 dirfor.na_gid == nva.na_gid)
1404 NFSVNO_UNSET(&nva, gid);
1405 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1407 if (nd->nd_repstat) {
1409 #ifdef NFS4_ACL_EXTATTR_NAME
1412 nfsvno_relpathbuf(&named);
1414 free(pathcp, M_TEMP);
1415 if (nd->nd_flag & ND_NFSV3)
1416 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1422 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1423 * in va_mode, so we'll have to set a default here.
1425 if (NFSVNO_NOTSETMODE(&nva)) {
1433 named.ni_cnd.cn_flags |= WILLBEDIR;
1434 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
1435 if (nd->nd_repstat) {
1437 if (nd->nd_flag & ND_NFSV3)
1438 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1442 #ifdef NFS4_ACL_EXTATTR_NAME
1445 if (nd->nd_flag & ND_NFSV3)
1446 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1451 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1453 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1455 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1456 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1458 #ifdef NFS4_ACL_EXTATTR_NAME
1462 } else if (vtyp == VLNK) {
1463 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1464 &dirfor, &diraft, &diraft_ret, &attrbits,
1465 aclp, p, exp, pathcp, pathlen);
1466 #ifdef NFS4_ACL_EXTATTR_NAME
1469 free(pathcp, M_TEMP);
1474 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1475 if (!nd->nd_repstat) {
1477 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1478 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1479 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1480 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1482 if (vpp != NULL && nd->nd_repstat == 0) {
1489 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1491 if (!nd->nd_repstat) {
1492 if (nd->nd_flag & ND_NFSV3) {
1493 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
1494 nfsrv_postopattr(nd, 0, &nva);
1496 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1497 *tl++ = newnfs_false;
1498 txdr_hyper(dirfor.na_filerev, tl);
1500 txdr_hyper(diraft.na_filerev, tl);
1501 (void) nfsrv_putattrbit(nd, &attrbits);
1504 if (nd->nd_flag & ND_NFSV3)
1505 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1506 #ifdef NFS4_ACL_EXTATTR_NAME
1511 NFSEXITCODE2(0, nd);
1515 #ifdef NFS4_ACL_EXTATTR_NAME
1519 nfsvno_relpathbuf(&named);
1521 free(pathcp, M_TEMP);
1523 NFSEXITCODE2(error, nd);
1528 * nfs remove service
1531 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1532 vnode_t dp, struct nfsexstuff *exp)
1534 struct nameidata named;
1536 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1537 vnode_t dirp = NULL;
1538 struct nfsvattr dirfor, diraft;
1541 struct thread *p = curthread;
1543 if (nd->nd_repstat) {
1544 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1547 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1548 LOCKPARENT | LOCKLEAF);
1549 nfsvno_setpathbuf(&named, &bufp, &hashp);
1550 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1553 nfsvno_relpathbuf(&named);
1556 if (!nd->nd_repstat) {
1557 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1560 nfsvno_relpathbuf(&named);
1563 if (!(nd->nd_flag & ND_NFSV2)) {
1564 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1571 if (!nd->nd_repstat) {
1572 if (nd->nd_flag & ND_NFSV4) {
1573 if (named.ni_vp->v_type == VDIR)
1574 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1575 nd->nd_cred, p, exp);
1577 nd->nd_repstat = nfsvno_removesub(&named, 1,
1578 nd->nd_cred, p, exp);
1579 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1580 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1581 nd->nd_cred, p, exp);
1583 nd->nd_repstat = nfsvno_removesub(&named, 0,
1584 nd->nd_cred, p, exp);
1587 if (!(nd->nd_flag & ND_NFSV2)) {
1589 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1593 if (nd->nd_flag & ND_NFSV3) {
1594 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1596 } else if (!nd->nd_repstat) {
1597 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1598 *tl++ = newnfs_false;
1599 txdr_hyper(dirfor.na_filerev, tl);
1601 txdr_hyper(diraft.na_filerev, tl);
1606 NFSEXITCODE2(error, nd);
1611 * nfs rename service
1614 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1615 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1618 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1619 int tdirfor_ret = 1, tdiraft_ret = 1;
1620 struct nameidata fromnd, tond;
1621 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1622 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1623 struct nfsexstuff tnes;
1625 char *bufp, *tbufp = NULL;
1628 struct thread *p = curthread;
1630 if (nd->nd_repstat) {
1631 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1632 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1635 if (!(nd->nd_flag & ND_NFSV2))
1636 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1637 tond.ni_cnd.cn_nameiop = 0;
1638 tond.ni_startdir = NULL;
1639 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT);
1640 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1641 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1646 nfsvno_relpathbuf(&fromnd);
1650 * Unlock dp in this code section, so it is unlocked before
1651 * tdp gets locked. This avoids a potential LOR if tdp is the
1652 * parent directory of dp.
1654 if (nd->nd_flag & ND_NFSV4) {
1659 /* Might lock tdp. */
1660 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1663 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1668 tfh.nfsrvfh_len = 0;
1669 error = nfsrv_mtofh(nd, &tfh);
1671 error = nfsvno_getfh(dp, &fh, p);
1674 /* todp is always NULL except NFSv4 */
1675 nfsvno_relpathbuf(&fromnd);
1679 /* If this is the same file handle, just VREF() the vnode. */
1680 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1681 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1685 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1690 nd->nd_cred->cr_uid = nd->nd_saveduid;
1691 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1692 0, -1); /* Locks tdp. */
1694 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1700 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE);
1701 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1702 if (!nd->nd_repstat) {
1703 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1708 nfsvno_relpathbuf(&fromnd);
1709 nfsvno_relpathbuf(&tond);
1713 if (nd->nd_repstat) {
1714 if (nd->nd_flag & ND_NFSV3) {
1715 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1717 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1723 nfsvno_relpathbuf(&fromnd);
1724 nfsvno_relpathbuf(&tond);
1729 * Done parsing, now down to business.
1731 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, &fdirp);
1732 if (nd->nd_repstat) {
1733 if (nd->nd_flag & ND_NFSV3) {
1734 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1736 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1743 nfsvno_relpathbuf(&tond);
1746 if (fromnd.ni_vp->v_type == VDIR)
1747 tond.ni_cnd.cn_flags |= WILLBEDIR;
1748 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, &tdirp);
1749 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1750 nd->nd_flag, nd->nd_cred, p);
1752 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1754 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1759 if (nd->nd_flag & ND_NFSV3) {
1760 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1761 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1762 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1763 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1764 *tl++ = newnfs_false;
1765 txdr_hyper(fdirfor.na_filerev, tl);
1767 txdr_hyper(fdiraft.na_filerev, tl);
1769 *tl++ = newnfs_false;
1770 txdr_hyper(tdirfor.na_filerev, tl);
1772 txdr_hyper(tdiraft.na_filerev, tl);
1776 NFSEXITCODE2(error, nd);
1784 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1785 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1787 struct nameidata named;
1789 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1790 vnode_t dirp = NULL, dp = NULL;
1791 struct nfsvattr dirfor, diraft, at;
1792 struct nfsexstuff tnes;
1796 struct thread *p = curthread;
1798 if (nd->nd_repstat) {
1799 nfsrv_postopattr(nd, getret, &at);
1800 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1804 if (vp->v_type == VDIR) {
1805 if (nd->nd_flag & ND_NFSV4)
1806 nd->nd_repstat = NFSERR_ISDIR;
1808 nd->nd_repstat = NFSERR_INVAL;
1812 if (!nd->nd_repstat) {
1813 if (nd->nd_flag & ND_NFSV4) {
1817 error = nfsrv_mtofh(nd, &dfh);
1820 /* tovp is always NULL unless NFSv4 */
1823 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL,
1829 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
1830 if (!nd->nd_repstat) {
1831 nfsvno_setpathbuf(&named, &bufp, &hashp);
1832 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1837 nfsvno_relpathbuf(&named);
1840 if (!nd->nd_repstat) {
1841 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1846 nfsvno_relpathbuf(&named);
1850 if (nd->nd_flag & ND_NFSV2) {
1854 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1858 if (!nd->nd_repstat)
1859 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1860 if (nd->nd_flag & ND_NFSV3)
1861 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1863 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1867 if (nd->nd_flag & ND_NFSV3) {
1868 nfsrv_postopattr(nd, getret, &at);
1869 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1870 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1871 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1872 *tl++ = newnfs_false;
1873 txdr_hyper(dirfor.na_filerev, tl);
1875 txdr_hyper(diraft.na_filerev, tl);
1879 NFSEXITCODE2(error, nd);
1884 * nfs symbolic link service
1887 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1888 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1890 struct nfsvattr nva, dirfor, diraft;
1891 struct nameidata named;
1892 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1893 vnode_t dirp = NULL;
1894 char *bufp, *pathcp = NULL;
1896 struct thread *p = curthread;
1898 if (nd->nd_repstat) {
1899 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1904 NFSVNO_ATTRINIT(&nva);
1905 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1906 LOCKPARENT | NOCACHE);
1907 nfsvno_setpathbuf(&named, &bufp, &hashp);
1908 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1909 if (!error && !nd->nd_repstat)
1910 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1913 nfsvno_relpathbuf(&named);
1916 if (!nd->nd_repstat) {
1917 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
1920 nfsvno_relpathbuf(&named);
1922 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1928 * And call nfsrvd_symlinksub() to do the common code. It will
1929 * return EBADRPC upon a parsing error, 0 otherwise.
1931 if (!nd->nd_repstat) {
1933 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1935 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1936 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1938 } else if (dirp != NULL) {
1939 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1943 free(pathcp, M_TEMP);
1945 if (nd->nd_flag & ND_NFSV3) {
1946 if (!nd->nd_repstat) {
1947 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
1948 nfsrv_postopattr(nd, 0, &nva);
1950 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1954 NFSEXITCODE2(error, nd);
1959 * Common code for creating a symbolic link.
1962 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1963 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1964 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1965 int *diraft_retp, nfsattrbit_t *attrbitp,
1966 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1971 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1972 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1973 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1974 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1975 if (nd->nd_flag & ND_NFSV3) {
1976 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1977 if (!nd->nd_repstat)
1978 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1979 nvap, nd, p, 1, NULL);
1981 if (vpp != NULL && nd->nd_repstat == 0) {
1982 NFSVOPUNLOCK(ndp->ni_vp);
1988 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1991 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1992 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1993 *tl++ = newnfs_false;
1994 txdr_hyper(dirforp->na_filerev, tl);
1996 txdr_hyper(diraftp->na_filerev, tl);
1997 (void) nfsrv_putattrbit(nd, attrbitp);
2000 NFSEXITCODE2(0, nd);
2007 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
2008 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
2010 struct nfsvattr nva, dirfor, diraft;
2011 struct nameidata named;
2013 int error = 0, dirfor_ret = 1, diraft_ret = 1;
2014 vnode_t dirp = NULL;
2017 struct thread *p = curthread;
2019 if (nd->nd_repstat) {
2020 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2023 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
2024 nfsvno_setpathbuf(&named, &bufp, &hashp);
2025 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2028 if (!nd->nd_repstat) {
2029 NFSVNO_ATTRINIT(&nva);
2030 if (nd->nd_flag & ND_NFSV3) {
2031 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
2035 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2036 nva.na_mode = nfstov_mode(*tl++);
2039 if (!nd->nd_repstat) {
2040 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
2043 nfsvno_relpathbuf(&named);
2045 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
2049 if (nd->nd_repstat) {
2051 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
2055 if (nd->nd_flag & ND_NFSV3)
2056 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
2061 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
2064 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
2066 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
2067 &diraft_ret, NULL, NULL, p, exp);
2069 if (nd->nd_flag & ND_NFSV3) {
2070 if (!nd->nd_repstat) {
2071 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
2072 nfsrv_postopattr(nd, 0, &nva);
2074 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2075 } else if (!nd->nd_repstat) {
2076 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
2077 nfsrv_fillattr(nd, &nva);
2081 NFSEXITCODE2(0, nd);
2085 nfsvno_relpathbuf(&named);
2086 NFSEXITCODE2(error, nd);
2091 * Code common to mkdir for V2,3 and 4.
2094 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2095 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2096 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2097 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2098 NFSPROC_T *p, struct nfsexstuff *exp)
2103 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2104 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2105 nd->nd_cred, p, exp);
2106 if (!nd->nd_repstat) {
2108 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2109 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2110 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2111 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2113 if (vpp && !nd->nd_repstat) {
2121 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2124 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2125 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2126 *tl++ = newnfs_false;
2127 txdr_hyper(dirforp->na_filerev, tl);
2129 txdr_hyper(diraftp->na_filerev, tl);
2130 (void) nfsrv_putattrbit(nd, attrbitp);
2133 NFSEXITCODE2(0, nd);
2137 * nfs commit service
2140 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2141 vnode_t vp, __unused struct nfsexstuff *exp)
2143 struct nfsvattr bfor, aft;
2145 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2147 struct thread *p = curthread;
2149 if (nd->nd_repstat) {
2150 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2154 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2155 if (vp->v_type != VREG) {
2156 if (nd->nd_flag & ND_NFSV3)
2157 error = NFSERR_NOTSUPP;
2159 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2162 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2165 * XXX At this time VOP_FSYNC() does not accept offset and byte
2166 * count parameters, so these arguments are useless (someday maybe).
2168 off = fxdr_hyper(tl);
2170 cnt = fxdr_unsigned(int, *tl);
2171 if (nd->nd_flag & ND_NFSV3)
2172 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2173 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2174 if (nd->nd_flag & ND_NFSV3) {
2175 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2176 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2179 if (!nd->nd_repstat) {
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2181 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2182 *tl = txdr_unsigned(nfsboottime.tv_usec);
2186 NFSEXITCODE2(0, nd);
2190 NFSEXITCODE2(error, nd);
2195 * nfs statfs service
2198 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2199 vnode_t vp, __unused struct nfsexstuff *exp)
2206 struct thread *p = curthread;
2209 if (nd->nd_repstat) {
2210 nfsrv_postopattr(nd, getret, &at);
2213 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2214 nd->nd_repstat = nfsvno_statfs(vp, sf);
2215 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2217 if (nd->nd_flag & ND_NFSV3)
2218 nfsrv_postopattr(nd, getret, &at);
2221 if (nd->nd_flag & ND_NFSV2) {
2222 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2223 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2224 *tl++ = txdr_unsigned(sf->f_bsize);
2225 *tl++ = txdr_unsigned(sf->f_blocks);
2226 *tl++ = txdr_unsigned(sf->f_bfree);
2227 *tl = txdr_unsigned(sf->f_bavail);
2229 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2230 tval = (u_quad_t)sf->f_blocks;
2231 tval *= (u_quad_t)sf->f_bsize;
2232 txdr_hyper(tval, tl); tl += 2;
2233 tval = (u_quad_t)sf->f_bfree;
2234 tval *= (u_quad_t)sf->f_bsize;
2235 txdr_hyper(tval, tl); tl += 2;
2236 tval = (u_quad_t)sf->f_bavail;
2237 tval *= (u_quad_t)sf->f_bsize;
2238 txdr_hyper(tval, tl); tl += 2;
2239 tval = (u_quad_t)sf->f_files;
2240 txdr_hyper(tval, tl); tl += 2;
2241 tval = (u_quad_t)sf->f_ffree;
2242 txdr_hyper(tval, tl); tl += 2;
2243 tval = (u_quad_t)sf->f_ffree;
2244 txdr_hyper(tval, tl); tl += 2;
2250 NFSEXITCODE2(0, nd);
2255 * nfs fsinfo service
2258 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2259 vnode_t vp, __unused struct nfsexstuff *exp)
2262 struct nfsfsinfo fs;
2265 struct thread *p = curthread;
2267 if (nd->nd_repstat) {
2268 nfsrv_postopattr(nd, getret, &at);
2271 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2272 nfsvno_getfs(&fs, isdgram);
2274 nfsrv_postopattr(nd, getret, &at);
2275 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2276 *tl++ = txdr_unsigned(fs.fs_rtmax);
2277 *tl++ = txdr_unsigned(fs.fs_rtpref);
2278 *tl++ = txdr_unsigned(fs.fs_rtmult);
2279 *tl++ = txdr_unsigned(fs.fs_wtmax);
2280 *tl++ = txdr_unsigned(fs.fs_wtpref);
2281 *tl++ = txdr_unsigned(fs.fs_wtmult);
2282 *tl++ = txdr_unsigned(fs.fs_dtpref);
2283 txdr_hyper(fs.fs_maxfilesize, tl);
2285 txdr_nfsv3time(&fs.fs_timedelta, tl);
2287 *tl = txdr_unsigned(fs.fs_properties);
2290 NFSEXITCODE2(0, nd);
2295 * nfs pathconf service
2298 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2299 vnode_t vp, __unused struct nfsexstuff *exp)
2301 struct nfsv3_pathconf *pc;
2303 long linkmax, namemax, chownres, notrunc;
2305 struct thread *p = curthread;
2307 if (nd->nd_repstat) {
2308 nfsrv_postopattr(nd, getret, &at);
2311 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2313 if (!nd->nd_repstat)
2314 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2316 if (!nd->nd_repstat)
2317 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2318 &chownres, nd->nd_cred, p);
2319 if (!nd->nd_repstat)
2320 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2322 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2324 nfsrv_postopattr(nd, getret, &at);
2325 if (!nd->nd_repstat) {
2326 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2327 pc->pc_linkmax = txdr_unsigned(linkmax);
2328 pc->pc_namemax = txdr_unsigned(namemax);
2329 pc->pc_notrunc = txdr_unsigned(notrunc);
2330 pc->pc_chownrestricted = txdr_unsigned(chownres);
2333 * These should probably be supported by VOP_PATHCONF(), but
2334 * until msdosfs is exportable (why would you want to?), the
2335 * Unix defaults should be ok.
2337 pc->pc_caseinsensitive = newnfs_false;
2338 pc->pc_casepreserving = newnfs_true;
2342 NFSEXITCODE2(0, nd);
2347 * nfsv4 lock service
2350 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2351 vnode_t vp, struct nfsexstuff *exp)
2355 struct nfsstate *stp = NULL;
2356 struct nfslock *lop;
2357 struct nfslockconflict cf;
2359 u_short flags = NFSLCK_LOCK, lflags;
2360 u_int64_t offset, len;
2361 nfsv4stateid_t stateid;
2363 struct thread *p = curthread;
2365 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2366 i = fxdr_unsigned(int, *tl++);
2368 case NFSV4LOCKT_READW:
2369 flags |= NFSLCK_BLOCKING;
2370 case NFSV4LOCKT_READ:
2371 lflags = NFSLCK_READ;
2373 case NFSV4LOCKT_WRITEW:
2374 flags |= NFSLCK_BLOCKING;
2375 case NFSV4LOCKT_WRITE:
2376 lflags = NFSLCK_WRITE;
2379 nd->nd_repstat = NFSERR_BADXDR;
2382 if (*tl++ == newnfs_true)
2383 flags |= NFSLCK_RECLAIM;
2384 offset = fxdr_hyper(tl);
2386 len = fxdr_hyper(tl);
2388 if (*tl == newnfs_true)
2389 flags |= NFSLCK_OPENTOLOCK;
2390 if (flags & NFSLCK_OPENTOLOCK) {
2391 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2392 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2393 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2394 nd->nd_repstat = NFSERR_BADXDR;
2397 stp = malloc(sizeof (struct nfsstate) + i,
2398 M_NFSDSTATE, M_WAITOK);
2399 stp->ls_ownerlen = i;
2400 stp->ls_op = nd->nd_rp;
2401 stp->ls_seq = fxdr_unsigned(int, *tl++);
2402 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2403 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2405 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2408 * For the special stateid of other all 0s and seqid == 1, set
2409 * the stateid to the current stateid, if it is set.
2411 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2412 stp->ls_stateid.seqid == 1 &&
2413 stp->ls_stateid.other[0] == 0 &&
2414 stp->ls_stateid.other[1] == 0 &&
2415 stp->ls_stateid.other[2] == 0) {
2416 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2417 stp->ls_stateid = nd->nd_curstateid;
2418 stp->ls_stateid.seqid = 0;
2420 nd->nd_repstat = NFSERR_BADSTATEID;
2425 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2426 clientid.lval[0] = *tl++;
2427 clientid.lval[1] = *tl++;
2428 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2429 if ((nd->nd_flag & ND_NFSV41) != 0)
2430 clientid.qval = nd->nd_clientid.qval;
2431 else if (nd->nd_clientid.qval != clientid.qval)
2432 printf("EEK3 multiple clids\n");
2434 if ((nd->nd_flag & ND_NFSV41) != 0)
2435 printf("EEK! no clientid from session\n");
2436 nd->nd_flag |= ND_IMPLIEDCLID;
2437 nd->nd_clientid.qval = clientid.qval;
2439 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2443 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2444 stp = malloc(sizeof (struct nfsstate),
2445 M_NFSDSTATE, M_WAITOK);
2446 stp->ls_ownerlen = 0;
2447 stp->ls_op = nd->nd_rp;
2448 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2449 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2451 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2454 * For the special stateid of other all 0s and seqid == 1, set
2455 * the stateid to the current stateid, if it is set.
2457 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2458 stp->ls_stateid.seqid == 1 &&
2459 stp->ls_stateid.other[0] == 0 &&
2460 stp->ls_stateid.other[1] == 0 &&
2461 stp->ls_stateid.other[2] == 0) {
2462 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2463 stp->ls_stateid = nd->nd_curstateid;
2464 stp->ls_stateid.seqid = 0;
2466 nd->nd_repstat = NFSERR_BADSTATEID;
2471 stp->ls_seq = fxdr_unsigned(int, *tl);
2472 clientid.lval[0] = stp->ls_stateid.other[0];
2473 clientid.lval[1] = stp->ls_stateid.other[1];
2474 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2475 if ((nd->nd_flag & ND_NFSV41) != 0)
2476 clientid.qval = nd->nd_clientid.qval;
2477 else if (nd->nd_clientid.qval != clientid.qval)
2478 printf("EEK4 multiple clids\n");
2480 if ((nd->nd_flag & ND_NFSV41) != 0)
2481 printf("EEK! no clientid from session\n");
2482 nd->nd_flag |= ND_IMPLIEDCLID;
2483 nd->nd_clientid.qval = clientid.qval;
2486 lop = malloc(sizeof (struct nfslock),
2487 M_NFSDLOCK, M_WAITOK);
2488 lop->lo_first = offset;
2489 if (len == NFS64BITSSET) {
2490 lop->lo_end = NFS64BITSSET;
2492 lop->lo_end = offset + len;
2493 if (lop->lo_end <= lop->lo_first)
2494 nd->nd_repstat = NFSERR_INVAL;
2496 lop->lo_flags = lflags;
2497 stp->ls_flags = flags;
2498 stp->ls_uid = nd->nd_cred->cr_uid;
2501 * Do basic access checking.
2503 if (!nd->nd_repstat && vp->v_type != VREG) {
2504 if (vp->v_type == VDIR)
2505 nd->nd_repstat = NFSERR_ISDIR;
2507 nd->nd_repstat = NFSERR_INVAL;
2509 if (!nd->nd_repstat) {
2510 if (lflags & NFSLCK_WRITE) {
2511 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2512 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2513 NFSACCCHK_VPISLOCKED, NULL);
2515 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2516 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2517 NFSACCCHK_VPISLOCKED, NULL);
2519 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2520 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2521 NFSACCCHK_VPISLOCKED, NULL);
2526 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2527 * seqid# gets updated. nfsrv_lockctrl() will return the value
2528 * of nd_repstat, if it gets that far.
2530 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2531 &stateid, exp, nd, p);
2533 free(lop, M_NFSDLOCK);
2535 free(stp, M_NFSDSTATE);
2536 if (!nd->nd_repstat) {
2537 /* For NFSv4.1, set the Current StateID. */
2538 if ((nd->nd_flag & ND_NFSV41) != 0) {
2539 nd->nd_curstateid = stateid;
2540 nd->nd_flag |= ND_CURSTATEID;
2542 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2543 *tl++ = txdr_unsigned(stateid.seqid);
2544 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2545 } else if (nd->nd_repstat == NFSERR_DENIED) {
2546 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2547 txdr_hyper(cf.cl_first, tl);
2549 if (cf.cl_end == NFS64BITSSET)
2552 len = cf.cl_end - cf.cl_first;
2553 txdr_hyper(len, tl);
2555 if (cf.cl_flags == NFSLCK_WRITE)
2556 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2558 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2559 *tl++ = stateid.other[0];
2560 *tl = stateid.other[1];
2561 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2564 NFSEXITCODE2(0, nd);
2569 free(stp, M_NFSDSTATE);
2570 NFSEXITCODE2(error, nd);
2575 * nfsv4 lock test service
2578 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2579 vnode_t vp, struct nfsexstuff *exp)
2583 struct nfsstate *stp = NULL;
2584 struct nfslock lo, *lop = &lo;
2585 struct nfslockconflict cf;
2587 nfsv4stateid_t stateid;
2590 struct thread *p = curthread;
2592 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2593 i = fxdr_unsigned(int, *(tl + 7));
2594 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2595 nd->nd_repstat = NFSERR_BADXDR;
2598 stp = malloc(sizeof (struct nfsstate) + i,
2599 M_NFSDSTATE, M_WAITOK);
2600 stp->ls_ownerlen = i;
2602 stp->ls_flags = NFSLCK_TEST;
2603 stp->ls_uid = nd->nd_cred->cr_uid;
2604 i = fxdr_unsigned(int, *tl++);
2606 case NFSV4LOCKT_READW:
2607 stp->ls_flags |= NFSLCK_BLOCKING;
2608 case NFSV4LOCKT_READ:
2609 lo.lo_flags = NFSLCK_READ;
2611 case NFSV4LOCKT_WRITEW:
2612 stp->ls_flags |= NFSLCK_BLOCKING;
2613 case NFSV4LOCKT_WRITE:
2614 lo.lo_flags = NFSLCK_WRITE;
2617 nd->nd_repstat = NFSERR_BADXDR;
2620 lo.lo_first = fxdr_hyper(tl);
2622 len = fxdr_hyper(tl);
2623 if (len == NFS64BITSSET) {
2624 lo.lo_end = NFS64BITSSET;
2626 lo.lo_end = lo.lo_first + len;
2627 if (lo.lo_end <= lo.lo_first)
2628 nd->nd_repstat = NFSERR_INVAL;
2631 clientid.lval[0] = *tl++;
2632 clientid.lval[1] = *tl;
2633 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2634 if ((nd->nd_flag & ND_NFSV41) != 0)
2635 clientid.qval = nd->nd_clientid.qval;
2636 else if (nd->nd_clientid.qval != clientid.qval)
2637 printf("EEK5 multiple clids\n");
2639 if ((nd->nd_flag & ND_NFSV41) != 0)
2640 printf("EEK! no clientid from session\n");
2641 nd->nd_flag |= ND_IMPLIEDCLID;
2642 nd->nd_clientid.qval = clientid.qval;
2644 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2647 if (!nd->nd_repstat && vp->v_type != VREG) {
2648 if (vp->v_type == VDIR)
2649 nd->nd_repstat = NFSERR_ISDIR;
2651 nd->nd_repstat = NFSERR_INVAL;
2653 if (!nd->nd_repstat)
2654 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2655 &stateid, exp, nd, p);
2656 if (nd->nd_repstat) {
2657 if (nd->nd_repstat == NFSERR_DENIED) {
2658 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2659 txdr_hyper(cf.cl_first, tl);
2661 if (cf.cl_end == NFS64BITSSET)
2664 len = cf.cl_end - cf.cl_first;
2665 txdr_hyper(len, tl);
2667 if (cf.cl_flags == NFSLCK_WRITE)
2668 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2670 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2671 *tl++ = stp->ls_stateid.other[0];
2672 *tl = stp->ls_stateid.other[1];
2673 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2678 free(stp, M_NFSDSTATE);
2679 NFSEXITCODE2(0, nd);
2684 free(stp, M_NFSDSTATE);
2685 NFSEXITCODE2(error, nd);
2690 * nfsv4 unlock service
2693 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2694 vnode_t vp, struct nfsexstuff *exp)
2698 struct nfsstate *stp;
2699 struct nfslock *lop;
2701 nfsv4stateid_t stateid;
2704 struct thread *p = curthread;
2706 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2707 stp = malloc(sizeof (struct nfsstate),
2708 M_NFSDSTATE, M_WAITOK);
2709 lop = malloc(sizeof (struct nfslock),
2710 M_NFSDLOCK, M_WAITOK);
2711 stp->ls_flags = NFSLCK_UNLOCK;
2712 lop->lo_flags = NFSLCK_UNLOCK;
2713 stp->ls_op = nd->nd_rp;
2714 i = fxdr_unsigned(int, *tl++);
2716 case NFSV4LOCKT_READW:
2717 stp->ls_flags |= NFSLCK_BLOCKING;
2718 case NFSV4LOCKT_READ:
2720 case NFSV4LOCKT_WRITEW:
2721 stp->ls_flags |= NFSLCK_BLOCKING;
2722 case NFSV4LOCKT_WRITE:
2725 nd->nd_repstat = NFSERR_BADXDR;
2726 free(stp, M_NFSDSTATE);
2727 free(lop, M_NFSDLOCK);
2730 stp->ls_ownerlen = 0;
2731 stp->ls_uid = nd->nd_cred->cr_uid;
2732 stp->ls_seq = fxdr_unsigned(int, *tl++);
2733 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2734 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2736 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2739 * For the special stateid of other all 0s and seqid == 1, set the
2740 * stateid to the current stateid, if it is set.
2742 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2743 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2744 stp->ls_stateid.other[2] == 0) {
2745 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2746 stp->ls_stateid = nd->nd_curstateid;
2747 stp->ls_stateid.seqid = 0;
2749 nd->nd_repstat = NFSERR_BADSTATEID;
2750 free(stp, M_NFSDSTATE);
2751 free(lop, M_NFSDLOCK);
2756 lop->lo_first = fxdr_hyper(tl);
2758 len = fxdr_hyper(tl);
2759 if (len == NFS64BITSSET) {
2760 lop->lo_end = NFS64BITSSET;
2762 lop->lo_end = lop->lo_first + len;
2763 if (lop->lo_end <= lop->lo_first)
2764 nd->nd_repstat = NFSERR_INVAL;
2766 clientid.lval[0] = stp->ls_stateid.other[0];
2767 clientid.lval[1] = stp->ls_stateid.other[1];
2768 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2769 if ((nd->nd_flag & ND_NFSV41) != 0)
2770 clientid.qval = nd->nd_clientid.qval;
2771 else if (nd->nd_clientid.qval != clientid.qval)
2772 printf("EEK6 multiple clids\n");
2774 if ((nd->nd_flag & ND_NFSV41) != 0)
2775 printf("EEK! no clientid from session\n");
2776 nd->nd_flag |= ND_IMPLIEDCLID;
2777 nd->nd_clientid.qval = clientid.qval;
2779 if (!nd->nd_repstat && vp->v_type != VREG) {
2780 if (vp->v_type == VDIR)
2781 nd->nd_repstat = NFSERR_ISDIR;
2783 nd->nd_repstat = NFSERR_INVAL;
2786 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2787 * seqid# gets incremented. nfsrv_lockctrl() will return the
2788 * value of nd_repstat, if it gets that far.
2790 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2791 &stateid, exp, nd, p);
2793 free(stp, M_NFSDSTATE);
2795 free(lop, M_NFSDLOCK);
2796 if (!nd->nd_repstat) {
2797 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2798 *tl++ = txdr_unsigned(stateid.seqid);
2799 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2803 NFSEXITCODE2(error, nd);
2808 * nfsv4 open service
2811 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2812 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2816 struct nfsstate *stp = NULL;
2817 int error = 0, create, claim, exclusive_flag = 0, override;
2818 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2819 int how = NFSCREATE_UNCHECKED;
2820 int32_t cverf[2], tverf[2] = { 0, 0 };
2821 vnode_t vp = NULL, dirp = NULL;
2822 struct nfsvattr nva, dirfor, diraft;
2823 struct nameidata named;
2824 nfsv4stateid_t stateid, delegstateid;
2825 nfsattrbit_t attrbits;
2829 NFSACL_T *aclp = NULL;
2830 struct thread *p = curthread;
2833 #ifdef NFS4_ACL_EXTATTR_NAME
2834 aclp = acl_alloc(M_WAITOK);
2837 NFSZERO_ATTRBIT(&attrbits);
2839 named.ni_cnd.cn_nameiop = 0;
2840 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2841 i = fxdr_unsigned(int, *(tl + 5));
2842 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2843 nd->nd_repstat = NFSERR_BADXDR;
2846 stp = malloc(sizeof (struct nfsstate) + i,
2847 M_NFSDSTATE, M_WAITOK);
2848 stp->ls_ownerlen = i;
2849 stp->ls_op = nd->nd_rp;
2850 stp->ls_flags = NFSLCK_OPEN;
2851 stp->ls_uid = nd->nd_cred->cr_uid;
2852 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2853 i = fxdr_unsigned(int, *tl++);
2855 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2856 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2858 /* For now, ignore these. */
2859 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2860 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2861 case NFSV4OPEN_WANTANYDELEG:
2862 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2864 i &= ~NFSV4OPEN_WANTDELEGMASK;
2866 case NFSV4OPEN_WANTREADDELEG:
2867 stp->ls_flags |= NFSLCK_WANTRDELEG;
2868 i &= ~NFSV4OPEN_WANTDELEGMASK;
2870 case NFSV4OPEN_WANTWRITEDELEG:
2871 stp->ls_flags |= NFSLCK_WANTWDELEG;
2872 i &= ~NFSV4OPEN_WANTDELEGMASK;
2874 case NFSV4OPEN_WANTNODELEG:
2875 stp->ls_flags |= NFSLCK_WANTNODELEG;
2876 i &= ~NFSV4OPEN_WANTDELEGMASK;
2878 case NFSV4OPEN_WANTCANCEL:
2879 printf("NFSv4: ignore Open WantCancel\n");
2880 i &= ~NFSV4OPEN_WANTDELEGMASK;
2883 /* nd_repstat will be set to NFSERR_INVAL below. */
2888 case NFSV4OPEN_ACCESSREAD:
2889 stp->ls_flags |= NFSLCK_READACCESS;
2891 case NFSV4OPEN_ACCESSWRITE:
2892 stp->ls_flags |= NFSLCK_WRITEACCESS;
2894 case NFSV4OPEN_ACCESSBOTH:
2895 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2898 nd->nd_repstat = NFSERR_INVAL;
2900 i = fxdr_unsigned(int, *tl++);
2902 case NFSV4OPEN_DENYNONE:
2904 case NFSV4OPEN_DENYREAD:
2905 stp->ls_flags |= NFSLCK_READDENY;
2907 case NFSV4OPEN_DENYWRITE:
2908 stp->ls_flags |= NFSLCK_WRITEDENY;
2910 case NFSV4OPEN_DENYBOTH:
2911 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2914 nd->nd_repstat = NFSERR_INVAL;
2916 clientid.lval[0] = *tl++;
2917 clientid.lval[1] = *tl;
2918 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2919 if ((nd->nd_flag & ND_NFSV41) != 0)
2920 clientid.qval = nd->nd_clientid.qval;
2921 else if (nd->nd_clientid.qval != clientid.qval)
2922 printf("EEK7 multiple clids\n");
2924 if ((nd->nd_flag & ND_NFSV41) != 0)
2925 printf("EEK! no clientid from session\n");
2926 nd->nd_flag |= ND_IMPLIEDCLID;
2927 nd->nd_clientid.qval = clientid.qval;
2929 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2932 NFSVNO_ATTRINIT(&nva);
2933 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2934 create = fxdr_unsigned(int, *tl);
2935 if (!nd->nd_repstat)
2936 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2937 if (create == NFSV4OPEN_CREATE) {
2940 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2941 how = fxdr_unsigned(int, *tl);
2943 case NFSCREATE_UNCHECKED:
2944 case NFSCREATE_GUARDED:
2945 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2949 * If the na_gid being set is the same as that of
2950 * the directory it is going in, clear it, since
2951 * that is what will be set by default. This allows
2952 * a user that isn't in that group to do the create.
2954 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2955 nva.na_gid == dirfor.na_gid)
2956 NFSVNO_UNSET(&nva, gid);
2957 if (!nd->nd_repstat)
2958 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2960 case NFSCREATE_EXCLUSIVE:
2961 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2965 case NFSCREATE_EXCLUSIVE41:
2966 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2969 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2972 if (NFSISSET_ATTRBIT(&attrbits,
2973 NFSATTRBIT_TIMEACCESSSET))
2974 nd->nd_repstat = NFSERR_INVAL;
2976 * If the na_gid being set is the same as that of
2977 * the directory it is going in, clear it, since
2978 * that is what will be set by default. This allows
2979 * a user that isn't in that group to do the create.
2981 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2982 nva.na_gid == dirfor.na_gid)
2983 NFSVNO_UNSET(&nva, gid);
2984 if (nd->nd_repstat == 0)
2985 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2988 nd->nd_repstat = NFSERR_BADXDR;
2991 } else if (create != NFSV4OPEN_NOCREATE) {
2992 nd->nd_repstat = NFSERR_BADXDR;
2997 * Now, handle the claim, which usually includes looking up a
2998 * name in the directory referenced by dp. The exception is
2999 * NFSV4OPEN_CLAIMPREVIOUS.
3001 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3002 claim = fxdr_unsigned(int, *tl);
3003 if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim ==
3004 NFSV4OPEN_CLAIMDELEGATECURFH) {
3005 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3006 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3007 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
3008 stp->ls_flags |= NFSLCK_DELEGCUR;
3009 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim ==
3010 NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3011 stp->ls_flags |= NFSLCK_DELEGPREV;
3013 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
3014 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
3015 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
3016 claim != NFSV4OPEN_CLAIMNULL)
3017 nd->nd_repstat = NFSERR_INVAL;
3018 if (nd->nd_repstat) {
3019 nd->nd_repstat = nfsrv_opencheck(clientid,
3020 &stateid, stp, NULL, nd, p, nd->nd_repstat);
3023 if (create == NFSV4OPEN_CREATE)
3024 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
3025 LOCKPARENT | LOCKLEAF | NOCACHE);
3027 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3029 nfsvno_setpathbuf(&named, &bufp, &hashp);
3030 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3033 #ifdef NFS4_ACL_EXTATTR_NAME
3036 free(stp, M_NFSDSTATE);
3037 nfsvno_relpathbuf(&named);
3038 NFSEXITCODE2(error, nd);
3041 if (!nd->nd_repstat) {
3042 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
3046 nfsvno_relpathbuf(&named);
3048 if (create == NFSV4OPEN_CREATE) {
3050 case NFSCREATE_UNCHECKED:
3051 if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3053 * Clear the setable attribute bits, except
3054 * for Size, if it is being truncated.
3056 NFSZERO_ATTRBIT(&attrbits);
3057 if (NFSVNO_ISSETSIZE(&nva))
3058 NFSSETBIT_ATTRBIT(&attrbits,
3062 case NFSCREATE_GUARDED:
3063 if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3064 nd->nd_repstat = EEXIST;
3068 case NFSCREATE_EXCLUSIVE:
3070 if (nd->nd_repstat == 0 && named.ni_vp == NULL)
3073 case NFSCREATE_EXCLUSIVE41:
3078 nfsvno_open(nd, &named, clientid, &stateid, stp,
3079 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3080 nd->nd_cred, done_namei, exp, &vp);
3081 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3082 NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH ||
3083 claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3084 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3085 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3086 i = fxdr_unsigned(int, *tl);
3088 case NFSV4OPEN_DELEGATEREAD:
3089 stp->ls_flags |= NFSLCK_DELEGREAD;
3091 case NFSV4OPEN_DELEGATEWRITE:
3092 stp->ls_flags |= NFSLCK_DELEGWRITE;
3093 case NFSV4OPEN_DELEGATENONE:
3096 nd->nd_repstat = NFSERR_BADXDR;
3099 stp->ls_flags |= NFSLCK_RECLAIM;
3101 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3102 nd->nd_repstat = NFSERR_INVAL;
3105 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3106 if (!VN_IS_DOOMED(vp))
3107 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3108 stp, vp, nd, p, nd->nd_repstat);
3110 nd->nd_repstat = NFSERR_PERM;
3112 nd->nd_repstat = NFSERR_BADXDR;
3117 * Do basic access checking.
3119 if (!nd->nd_repstat && vp->v_type != VREG) {
3121 * The IETF working group decided that this is the correct
3122 * error return for all non-regular files.
3124 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3128 * If the Open is being done for a file that already exists, apply
3129 * normal permission checking including for the file owner, if
3130 * vfs.nfsd.v4openaccess is set.
3131 * Previously, the owner was always allowed to open the file to
3132 * be consistent with the NFS tradition of always allowing the
3133 * owner of the file to write to the file regardless of permissions.
3134 * It now appears that the Linux client expects the owner
3135 * permissions to be checked for opens that are not creating the
3136 * file. I believe the correct approach is to use the Access
3137 * operation's results to be consistent with NFSv3, but that is
3138 * not what the current Linux client appears to be doing.
3139 * Since both the Linux and OpenSolaris NFSv4 servers do this check,
3140 * I have enabled it by default. Since Linux does not apply this
3141 * check for claim_delegate_cur, this code does the same.
3142 * If this semantic change causes a problem, it can be disabled by
3143 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3144 * previous semantics.
3146 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE &&
3147 (stp->ls_flags & NFSLCK_DELEGCUR) == 0)
3148 override = NFSACCCHK_NOOVERRIDE;
3150 override = NFSACCCHK_ALLOWOWNER;
3151 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3152 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3153 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3154 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3155 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3156 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3158 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3159 nd->nd_cred, exp, p, override,
3160 NFSACCCHK_VPISLOCKED, NULL);
3163 if (!nd->nd_repstat) {
3164 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3165 if (!nd->nd_repstat) {
3166 tverf[0] = nva.na_atime.tv_sec;
3167 tverf[1] = nva.na_atime.tv_nsec;
3170 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3171 cverf[1] != tverf[1]))
3172 nd->nd_repstat = EEXIST;
3174 * Do the open locking/delegation stuff.
3176 if (!nd->nd_repstat)
3177 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3178 &delegstateid, &rflags, exp, p, nva.na_filerev);
3181 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3182 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3183 * (ie: Leave the NFSVOPUNLOCK() about here.)
3188 free(stp, M_NFSDSTATE);
3189 if (!nd->nd_repstat && dirp)
3190 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3191 if (!nd->nd_repstat) {
3192 /* For NFSv4.1, set the Current StateID. */
3193 if ((nd->nd_flag & ND_NFSV41) != 0) {
3194 nd->nd_curstateid = stateid;
3195 nd->nd_flag |= ND_CURSTATEID;
3197 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3198 *tl++ = txdr_unsigned(stateid.seqid);
3199 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3200 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3201 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3202 *tl++ = newnfs_true;
3208 *tl++ = newnfs_false; /* Since dirp is not locked */
3209 txdr_hyper(dirfor.na_filerev, tl);
3211 txdr_hyper(diraft.na_filerev, tl);
3214 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3215 (void) nfsrv_putattrbit(nd, &attrbits);
3216 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3217 if (rflags & NFSV4OPEN_READDELEGATE)
3218 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3219 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3220 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3221 else if (retext != 0) {
3222 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3223 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3225 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3226 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3227 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3228 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3229 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3230 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3231 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3233 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3234 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3235 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3238 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3239 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3242 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3243 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3244 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3245 *tl++ = txdr_unsigned(delegstateid.seqid);
3246 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3248 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3249 if (rflags & NFSV4OPEN_RECALL)
3253 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3254 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3255 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3256 txdr_hyper(nva.na_size, tl);
3258 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3259 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3260 *tl++ = txdr_unsigned(0x0);
3261 acemask = NFSV4ACE_ALLFILESMASK;
3262 if (nva.na_mode & S_IRUSR)
3263 acemask |= NFSV4ACE_READMASK;
3264 if (nva.na_mode & S_IWUSR)
3265 acemask |= NFSV4ACE_WRITEMASK;
3266 if (nva.na_mode & S_IXUSR)
3267 acemask |= NFSV4ACE_EXECUTEMASK;
3268 *tl = txdr_unsigned(acemask);
3269 (void) nfsm_strtom(nd, "OWNER@", 6);
3277 #ifdef NFS4_ACL_EXTATTR_NAME
3280 NFSEXITCODE2(0, nd);
3284 #ifdef NFS4_ACL_EXTATTR_NAME
3288 free(stp, M_NFSDSTATE);
3289 NFSEXITCODE2(error, nd);
3294 * nfsv4 close service
3297 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3298 vnode_t vp, __unused struct nfsexstuff *exp)
3301 struct nfsstate st, *stp = &st;
3302 int error = 0, writeacc;
3303 nfsv4stateid_t stateid;
3306 struct thread *p = curthread;
3308 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3309 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3310 stp->ls_ownerlen = 0;
3311 stp->ls_op = nd->nd_rp;
3312 stp->ls_uid = nd->nd_cred->cr_uid;
3313 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3314 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3318 * For the special stateid of other all 0s and seqid == 1, set the
3319 * stateid to the current stateid, if it is set.
3321 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3322 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3323 stp->ls_stateid.other[2] == 0) {
3324 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3325 stp->ls_stateid = nd->nd_curstateid;
3327 nd->nd_repstat = NFSERR_BADSTATEID;
3332 stp->ls_flags = NFSLCK_CLOSE;
3333 clientid.lval[0] = stp->ls_stateid.other[0];
3334 clientid.lval[1] = stp->ls_stateid.other[1];
3335 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3336 if ((nd->nd_flag & ND_NFSV41) != 0)
3337 clientid.qval = nd->nd_clientid.qval;
3338 else if (nd->nd_clientid.qval != clientid.qval)
3339 printf("EEK8 multiple clids\n");
3341 if ((nd->nd_flag & ND_NFSV41) != 0)
3342 printf("EEK! no clientid from session\n");
3343 nd->nd_flag |= ND_IMPLIEDCLID;
3344 nd->nd_clientid.qval = clientid.qval;
3346 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3348 /* For pNFS, update the attributes. */
3349 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3350 nfsrv_updatemdsattr(vp, &na, p);
3352 if (!nd->nd_repstat) {
3354 * If the stateid that has been closed is the current stateid,
3357 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3358 stateid.other[0] == nd->nd_curstateid.other[0] &&
3359 stateid.other[1] == nd->nd_curstateid.other[1] &&
3360 stateid.other[2] == nd->nd_curstateid.other[2])
3361 nd->nd_flag &= ~ND_CURSTATEID;
3362 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3363 *tl++ = txdr_unsigned(stateid.seqid);
3364 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3366 NFSEXITCODE2(0, nd);
3370 NFSEXITCODE2(error, nd);
3375 * nfsv4 delegpurge service
3378 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3379 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3384 struct thread *p = curthread;
3386 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3388 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3389 clientid.lval[0] = *tl++;
3390 clientid.lval[1] = *tl;
3391 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3392 if ((nd->nd_flag & ND_NFSV41) != 0)
3393 clientid.qval = nd->nd_clientid.qval;
3394 else if (nd->nd_clientid.qval != clientid.qval)
3395 printf("EEK9 multiple clids\n");
3397 if ((nd->nd_flag & ND_NFSV41) != 0)
3398 printf("EEK! no clientid from session\n");
3399 nd->nd_flag |= ND_IMPLIEDCLID;
3400 nd->nd_clientid.qval = clientid.qval;
3402 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3403 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3405 NFSEXITCODE2(error, nd);
3410 * nfsv4 delegreturn service
3413 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3414 vnode_t vp, __unused struct nfsexstuff *exp)
3417 int error = 0, writeacc;
3418 nfsv4stateid_t stateid;
3421 struct thread *p = curthread;
3423 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3424 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3425 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3426 clientid.lval[0] = stateid.other[0];
3427 clientid.lval[1] = stateid.other[1];
3428 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3429 if ((nd->nd_flag & ND_NFSV41) != 0)
3430 clientid.qval = nd->nd_clientid.qval;
3431 else if (nd->nd_clientid.qval != clientid.qval)
3432 printf("EEK10 multiple clids\n");
3434 if ((nd->nd_flag & ND_NFSV41) != 0)
3435 printf("EEK! no clientid from session\n");
3436 nd->nd_flag |= ND_IMPLIEDCLID;
3437 nd->nd_clientid.qval = clientid.qval;
3439 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3440 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3441 /* For pNFS, update the attributes. */
3442 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3443 nfsrv_updatemdsattr(vp, &na, p);
3446 NFSEXITCODE2(error, nd);
3451 * nfsv4 get file handle service
3454 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3455 vnode_t vp, __unused struct nfsexstuff *exp)
3458 struct thread *p = curthread;
3460 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3462 if (!nd->nd_repstat)
3463 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
3464 NFSEXITCODE2(0, nd);
3469 * nfsv4 open confirm service
3472 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3473 vnode_t vp, __unused struct nfsexstuff *exp)
3476 struct nfsstate st, *stp = &st;
3478 nfsv4stateid_t stateid;
3480 struct thread *p = curthread;
3482 if ((nd->nd_flag & ND_NFSV41) != 0) {
3483 nd->nd_repstat = NFSERR_NOTSUPP;
3486 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3487 stp->ls_ownerlen = 0;
3488 stp->ls_op = nd->nd_rp;
3489 stp->ls_uid = nd->nd_cred->cr_uid;
3490 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3491 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3493 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3494 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3495 stp->ls_flags = NFSLCK_CONFIRM;
3496 clientid.lval[0] = stp->ls_stateid.other[0];
3497 clientid.lval[1] = stp->ls_stateid.other[1];
3498 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3499 if ((nd->nd_flag & ND_NFSV41) != 0)
3500 clientid.qval = nd->nd_clientid.qval;
3501 else if (nd->nd_clientid.qval != clientid.qval)
3502 printf("EEK11 multiple clids\n");
3504 if ((nd->nd_flag & ND_NFSV41) != 0)
3505 printf("EEK! no clientid from session\n");
3506 nd->nd_flag |= ND_IMPLIEDCLID;
3507 nd->nd_clientid.qval = clientid.qval;
3509 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3511 if (!nd->nd_repstat) {
3512 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3513 *tl++ = txdr_unsigned(stateid.seqid);
3514 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3518 NFSEXITCODE2(error, nd);
3523 * nfsv4 open downgrade service
3526 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3527 vnode_t vp, __unused struct nfsexstuff *exp)
3531 struct nfsstate st, *stp = &st;
3533 nfsv4stateid_t stateid;
3535 struct thread *p = curthread;
3537 /* opendowngrade can only work on a file object.*/
3538 if (vp->v_type != VREG) {
3539 error = NFSERR_INVAL;
3542 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3543 stp->ls_ownerlen = 0;
3544 stp->ls_op = nd->nd_rp;
3545 stp->ls_uid = nd->nd_cred->cr_uid;
3546 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3547 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3549 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3552 * For the special stateid of other all 0s and seqid == 1, set the
3553 * stateid to the current stateid, if it is set.
3555 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3556 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3557 stp->ls_stateid.other[2] == 0) {
3558 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3559 stp->ls_stateid = nd->nd_curstateid;
3561 nd->nd_repstat = NFSERR_BADSTATEID;
3566 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3567 i = fxdr_unsigned(int, *tl++);
3568 if ((nd->nd_flag & ND_NFSV41) != 0)
3569 i &= ~NFSV4OPEN_WANTDELEGMASK;
3571 case NFSV4OPEN_ACCESSREAD:
3572 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3574 case NFSV4OPEN_ACCESSWRITE:
3575 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3577 case NFSV4OPEN_ACCESSBOTH:
3578 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3582 nd->nd_repstat = NFSERR_INVAL;
3584 i = fxdr_unsigned(int, *tl);
3586 case NFSV4OPEN_DENYNONE:
3588 case NFSV4OPEN_DENYREAD:
3589 stp->ls_flags |= NFSLCK_READDENY;
3591 case NFSV4OPEN_DENYWRITE:
3592 stp->ls_flags |= NFSLCK_WRITEDENY;
3594 case NFSV4OPEN_DENYBOTH:
3595 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3598 nd->nd_repstat = NFSERR_INVAL;
3601 clientid.lval[0] = stp->ls_stateid.other[0];
3602 clientid.lval[1] = stp->ls_stateid.other[1];
3603 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3604 if ((nd->nd_flag & ND_NFSV41) != 0)
3605 clientid.qval = nd->nd_clientid.qval;
3606 else if (nd->nd_clientid.qval != clientid.qval)
3607 printf("EEK12 multiple clids\n");
3609 if ((nd->nd_flag & ND_NFSV41) != 0)
3610 printf("EEK! no clientid from session\n");
3611 nd->nd_flag |= ND_IMPLIEDCLID;
3612 nd->nd_clientid.qval = clientid.qval;
3614 if (!nd->nd_repstat)
3615 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3617 if (!nd->nd_repstat) {
3618 /* For NFSv4.1, set the Current StateID. */
3619 if ((nd->nd_flag & ND_NFSV41) != 0) {
3620 nd->nd_curstateid = stateid;
3621 nd->nd_flag |= ND_CURSTATEID;
3623 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3624 *tl++ = txdr_unsigned(stateid.seqid);
3625 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3629 NFSEXITCODE2(error, nd);
3634 * nfsv4 renew lease service
3637 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3638 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3643 struct thread *p = curthread;
3645 if ((nd->nd_flag & ND_NFSV41) != 0) {
3646 nd->nd_repstat = NFSERR_NOTSUPP;
3649 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3651 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3652 clientid.lval[0] = *tl++;
3653 clientid.lval[1] = *tl;
3654 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3655 if ((nd->nd_flag & ND_NFSV41) != 0)
3656 clientid.qval = nd->nd_clientid.qval;
3657 else if (nd->nd_clientid.qval != clientid.qval)
3658 printf("EEK13 multiple clids\n");
3660 if ((nd->nd_flag & ND_NFSV41) != 0)
3661 printf("EEK! no clientid from session\n");
3662 nd->nd_flag |= ND_IMPLIEDCLID;
3663 nd->nd_clientid.qval = clientid.qval;
3665 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3666 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3668 NFSEXITCODE2(error, nd);
3673 * nfsv4 security info service
3676 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3677 vnode_t dp, struct nfsexstuff *exp)
3681 struct nameidata named;
3682 vnode_t dirp = NULL, vp;
3684 struct nfsexstuff retnes;
3690 struct thread *p = curthread;
3693 * All this just to get the export flags for the name.
3695 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3697 nfsvno_setpathbuf(&named, &bufp, &hashp);
3698 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3701 nfsvno_relpathbuf(&named);
3704 if (!nd->nd_repstat) {
3705 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3708 nfsvno_relpathbuf(&named);
3714 nfsvno_relpathbuf(&named);
3715 fh.nfsrvfh_len = NFSX_MYFH;
3717 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3719 savflag = nd->nd_flag;
3720 if (!nd->nd_repstat) {
3722 * Pretend the next op is Secinfo, so that no wrongsec
3723 * test will be done.
3725 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3730 nd->nd_flag = savflag;
3735 * Finally have the export flags for name, so we can create
3736 * the security info.
3739 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3741 /* If nes_numsecflavor == 0, all are allowed. */
3742 if (retnes.nes_numsecflavor == 0) {
3743 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3744 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
3745 *tl = txdr_unsigned(RPCAUTH_GSS);
3746 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3747 nfsgss_mechlist[KERBV_MECH].len);
3748 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3749 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3750 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3751 *tl = txdr_unsigned(RPCAUTH_GSS);
3752 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3753 nfsgss_mechlist[KERBV_MECH].len);
3754 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3755 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3756 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3757 *tl = txdr_unsigned(RPCAUTH_GSS);
3758 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3759 nfsgss_mechlist[KERBV_MECH].len);
3760 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3761 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3762 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3765 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3766 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3767 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3768 *tl = txdr_unsigned(RPCAUTH_UNIX);
3770 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3771 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3772 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3773 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3774 nfsgss_mechlist[KERBV_MECH].len);
3775 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3776 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3777 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3779 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3780 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3781 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3782 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3783 nfsgss_mechlist[KERBV_MECH].len);
3784 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3785 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3786 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3788 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3789 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3790 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3791 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3792 nfsgss_mechlist[KERBV_MECH].len);
3793 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3794 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3795 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3799 *sizp = txdr_unsigned(len);
3802 NFSEXITCODE2(error, nd);
3807 * nfsv4 security info no name service
3810 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
3811 vnode_t dp, struct nfsexstuff *exp)
3813 uint32_t *tl, *sizp;
3814 struct nameidata named;
3815 vnode_t dirp = NULL, vp;
3817 struct nfsexstuff retnes;
3818 int error = 0, fhstyle, i, len;
3822 struct thread *p = curthread;
3824 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3825 fhstyle = fxdr_unsigned(int, *tl);
3827 case NFSSECINFONONAME_PARENT:
3828 if (dp->v_type != VDIR) {
3830 nd->nd_repstat = NFSERR_NOTDIR;
3833 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3835 nfsvno_setpathbuf(&named, &bufp, &hashp);
3836 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3839 nfsvno_relpathbuf(&named);
3842 if (nd->nd_repstat == 0)
3843 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3848 nfsvno_relpathbuf(&named);
3851 case NFSSECINFONONAME_CURFH:
3855 nd->nd_repstat = NFSERR_INVAL;
3858 if (nd->nd_repstat != 0)
3860 fh.nfsrvfh_len = NFSX_MYFH;
3861 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3863 savflag = nd->nd_flag;
3864 if (nd->nd_repstat == 0) {
3866 * Pretend the next op is Secinfo, so that no wrongsec
3867 * test will be done.
3869 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3874 nd->nd_flag = savflag;
3875 if (nd->nd_repstat != 0)
3879 * Finally have the export flags for fh/parent, so we can create
3880 * the security info.
3883 NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
3885 /* If nes_numsecflavor == 0, all are allowed. */
3886 if (retnes.nes_numsecflavor == 0) {
3887 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3888 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
3889 *tl = txdr_unsigned(RPCAUTH_GSS);
3890 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3891 nfsgss_mechlist[KERBV_MECH].len);
3892 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3893 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3894 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3895 *tl = txdr_unsigned(RPCAUTH_GSS);
3896 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3897 nfsgss_mechlist[KERBV_MECH].len);
3898 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3899 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3900 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3901 *tl = txdr_unsigned(RPCAUTH_GSS);
3902 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3903 nfsgss_mechlist[KERBV_MECH].len);
3904 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3905 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3906 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3909 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3910 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3911 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3912 *tl = txdr_unsigned(RPCAUTH_UNIX);
3914 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3915 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3916 *tl = txdr_unsigned(RPCAUTH_GSS);
3917 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3918 nfsgss_mechlist[KERBV_MECH].len);
3919 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3920 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3921 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3923 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3924 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3925 *tl = txdr_unsigned(RPCAUTH_GSS);
3926 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3927 nfsgss_mechlist[KERBV_MECH].len);
3928 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3929 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3930 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3932 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3933 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3934 *tl = txdr_unsigned(RPCAUTH_GSS);
3935 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3936 nfsgss_mechlist[KERBV_MECH].len);
3937 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3938 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3939 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3943 *sizp = txdr_unsigned(len);
3946 NFSEXITCODE2(error, nd);
3951 * nfsv4 set client id service
3954 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3955 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3959 int error = 0, idlen;
3960 struct nfsclient *clp = NULL;
3962 struct sockaddr_in *rin;
3965 struct sockaddr_in6 *rin6;
3967 #if defined(INET) || defined(INET6)
3970 u_char *verf, *addrbuf;
3971 nfsquad_t clientid, confirm;
3972 struct thread *p = curthread;
3974 if ((nd->nd_flag & ND_NFSV41) != 0) {
3975 nd->nd_repstat = NFSERR_NOTSUPP;
3978 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3980 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3981 verf = (u_char *)tl;
3982 tl += (NFSX_VERF / NFSX_UNSIGNED);
3983 i = fxdr_unsigned(int, *tl);
3984 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3985 nd->nd_repstat = NFSERR_BADXDR;
3989 if (nd->nd_flag & ND_GSS)
3990 i += nd->nd_princlen;
3991 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3993 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3994 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3995 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3996 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3997 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3999 clp->lc_req.nr_cred = NULL;
4000 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4001 clp->lc_idlen = idlen;
4002 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4005 if (nd->nd_flag & ND_GSS) {
4006 clp->lc_flags = LCL_GSS;
4007 if (nd->nd_flag & ND_GSSINTEGRITY)
4008 clp->lc_flags |= LCL_GSSINTEGRITY;
4009 else if (nd->nd_flag & ND_GSSPRIVACY)
4010 clp->lc_flags |= LCL_GSSPRIVACY;
4014 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
4015 clp->lc_flags |= LCL_NAME;
4016 clp->lc_namelen = nd->nd_princlen;
4017 clp->lc_name = &clp->lc_id[idlen];
4018 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4020 clp->lc_uid = nd->nd_cred->cr_uid;
4021 clp->lc_gid = nd->nd_cred->cr_gid;
4024 /* If the client is using TLS, do so for the callback connection. */
4025 if (nd->nd_flag & ND_TLS)
4026 clp->lc_flags |= LCL_TLSCB;
4028 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4029 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
4030 error = nfsrv_getclientipaddr(nd, clp);
4033 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4034 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
4037 * nfsrv_setclient() does the actual work of adding it to the
4038 * client list. If there is no error, the structure has been
4039 * linked into the client list and clp should no longer be used
4040 * here. When an error is returned, it has not been linked in,
4041 * so it should be free'd.
4043 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4044 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
4046 * 8 is the maximum length of the port# string.
4048 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
4049 switch (clp->lc_req.nr_nam->sa_family) {
4052 if (clp->lc_flags & LCL_TCPCALLBACK)
4053 (void) nfsm_strtom(nd, "tcp", 3);
4055 (void) nfsm_strtom(nd, "udp", 3);
4056 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4057 ucp = (u_char *)&rin->sin_addr.s_addr;
4058 ucp2 = (u_char *)&rin->sin_port;
4059 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
4060 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
4061 ucp2[0] & 0xff, ucp2[1] & 0xff);
4066 if (clp->lc_flags & LCL_TCPCALLBACK)
4067 (void) nfsm_strtom(nd, "tcp6", 4);
4069 (void) nfsm_strtom(nd, "udp6", 4);
4070 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4071 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
4077 ucp2 = (u_char *)&rin6->sin6_port;
4078 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
4083 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
4084 free(addrbuf, M_TEMP);
4087 free(clp->lc_req.nr_nam, M_SONAME);
4088 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4089 free(clp->lc_stateid, M_NFSDCLIENT);
4090 free(clp, M_NFSDCLIENT);
4092 if (!nd->nd_repstat) {
4093 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
4094 *tl++ = clientid.lval[0];
4095 *tl++ = clientid.lval[1];
4096 *tl++ = confirm.lval[0];
4097 *tl = confirm.lval[1];
4101 NFSEXITCODE2(0, nd);
4105 free(clp->lc_req.nr_nam, M_SONAME);
4106 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4107 free(clp->lc_stateid, M_NFSDCLIENT);
4108 free(clp, M_NFSDCLIENT);
4110 NFSEXITCODE2(error, nd);
4115 * nfsv4 set client id confirm service
4118 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
4119 __unused int isdgram, __unused vnode_t vp,
4120 __unused struct nfsexstuff *exp)
4124 nfsquad_t clientid, confirm;
4125 struct thread *p = curthread;
4127 if ((nd->nd_flag & ND_NFSV41) != 0) {
4128 nd->nd_repstat = NFSERR_NOTSUPP;
4131 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4133 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
4134 clientid.lval[0] = *tl++;
4135 clientid.lval[1] = *tl++;
4136 confirm.lval[0] = *tl++;
4137 confirm.lval[1] = *tl;
4140 * nfsrv_getclient() searches the client list for a match and
4141 * returns the appropriate NFSERR status.
4143 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
4144 NULL, NULL, confirm, 0, nd, p);
4146 NFSEXITCODE2(error, nd);
4151 * nfsv4 verify service
4154 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
4155 vnode_t vp, __unused struct nfsexstuff *exp)
4157 int error = 0, ret, fhsize = NFSX_MYFH;
4158 struct nfsvattr nva;
4160 struct nfsfsinfo fs;
4162 struct thread *p = curthread;
4164 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4165 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
4166 if (!nd->nd_repstat)
4167 nd->nd_repstat = nfsvno_statfs(vp, sf);
4168 if (!nd->nd_repstat)
4169 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
4170 if (!nd->nd_repstat) {
4171 nfsvno_getfs(&fs, isdgram);
4172 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
4173 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
4175 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
4177 nd->nd_repstat = NFSERR_SAME;
4178 else if (ret != NFSERR_NOTSAME)
4179 nd->nd_repstat = ret;
4181 nd->nd_repstat = ret;
4186 NFSEXITCODE2(error, nd);
4194 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
4195 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
4196 __unused struct nfsexstuff *exp)
4199 int error = 0, createdir __unused;
4201 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4202 createdir = fxdr_unsigned(int, *tl);
4203 nd->nd_repstat = NFSERR_NOTSUPP;
4206 NFSEXITCODE2(error, nd);
4211 * nfsv4 release lock owner service
4214 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
4215 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4218 struct nfsstate *stp = NULL;
4221 struct thread *p = curthread;
4223 if ((nd->nd_flag & ND_NFSV41) != 0) {
4224 nd->nd_repstat = NFSERR_NOTSUPP;
4227 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4229 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4230 len = fxdr_unsigned(int, *(tl + 2));
4231 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
4232 nd->nd_repstat = NFSERR_BADXDR;
4235 stp = malloc(sizeof (struct nfsstate) + len,
4236 M_NFSDSTATE, M_WAITOK);
4237 stp->ls_ownerlen = len;
4239 stp->ls_flags = NFSLCK_RELEASE;
4240 stp->ls_uid = nd->nd_cred->cr_uid;
4241 clientid.lval[0] = *tl++;
4242 clientid.lval[1] = *tl;
4243 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4244 if ((nd->nd_flag & ND_NFSV41) != 0)
4245 clientid.qval = nd->nd_clientid.qval;
4246 else if (nd->nd_clientid.qval != clientid.qval)
4247 printf("EEK14 multiple clids\n");
4249 if ((nd->nd_flag & ND_NFSV41) != 0)
4250 printf("EEK! no clientid from session\n");
4251 nd->nd_flag |= ND_IMPLIEDCLID;
4252 nd->nd_clientid.qval = clientid.qval;
4254 error = nfsrv_mtostr(nd, stp->ls_owner, len);
4257 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4258 free(stp, M_NFSDSTATE);
4260 NFSEXITCODE2(0, nd);
4264 free(stp, M_NFSDSTATE);
4265 NFSEXITCODE2(error, nd);
4270 * nfsv4 exchange_id service
4273 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4274 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4277 int error = 0, i, idlen;
4278 struct nfsclient *clp = NULL;
4279 nfsquad_t clientid, confirm;
4281 uint32_t sp4type, v41flags;
4282 struct timespec verstime;
4283 nfsopbit_t mustops, allowops;
4285 struct sockaddr_in *sin, *rin;
4288 struct sockaddr_in6 *sin6, *rin6;
4290 struct thread *p = curthread;
4293 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4295 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4296 verf = (uint8_t *)tl;
4297 tl += (NFSX_VERF / NFSX_UNSIGNED);
4298 i = fxdr_unsigned(int, *tl);
4299 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4300 nd->nd_repstat = NFSERR_BADXDR;
4304 if (nd->nd_flag & ND_GSS)
4305 i += nd->nd_princlen;
4306 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4308 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4309 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4310 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4311 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4312 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4314 switch (nd->nd_nam->sa_family) {
4317 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4318 sin = (struct sockaddr_in *)nd->nd_nam;
4319 rin->sin_family = AF_INET;
4320 rin->sin_len = sizeof(struct sockaddr_in);
4322 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4327 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4328 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4329 rin6->sin6_family = AF_INET6;
4330 rin6->sin6_len = sizeof(struct sockaddr_in6);
4331 rin6->sin6_port = 0;
4332 rin6->sin6_addr = sin6->sin6_addr;
4336 clp->lc_req.nr_cred = NULL;
4337 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4338 clp->lc_idlen = idlen;
4339 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4342 if ((nd->nd_flag & ND_GSS) != 0) {
4343 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4344 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4345 clp->lc_flags |= LCL_GSSINTEGRITY;
4346 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4347 clp->lc_flags |= LCL_GSSPRIVACY;
4349 clp->lc_flags = LCL_NFSV41;
4350 if ((nd->nd_flag & ND_NFSV42) != 0)
4351 clp->lc_flags |= LCL_NFSV42;
4352 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4353 clp->lc_flags |= LCL_NAME;
4354 clp->lc_namelen = nd->nd_princlen;
4355 clp->lc_name = &clp->lc_id[idlen];
4356 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4358 clp->lc_uid = nd->nd_cred->cr_uid;
4359 clp->lc_gid = nd->nd_cred->cr_gid;
4361 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4362 v41flags = fxdr_unsigned(uint32_t, *tl++);
4363 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4364 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4365 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4366 nd->nd_repstat = NFSERR_INVAL;
4369 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4370 confirm.lval[1] = 1;
4372 confirm.lval[1] = 0;
4373 if (nfsrv_devidcnt == 0)
4374 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4376 v41flags = NFSV4EXCH_USEPNFSMDS;
4377 sp4type = fxdr_unsigned(uint32_t, *tl);
4378 if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4379 if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 ||
4380 nd->nd_princlen == 0)
4381 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
4382 if (nd->nd_repstat == 0)
4383 nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL);
4384 if (nd->nd_repstat == 0)
4385 nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL);
4386 if (nd->nd_repstat != 0)
4388 NFSOPBIT_CLRNOTMUST(&mustops);
4389 NFSSET_OPBIT(&clp->lc_mustops, &mustops);
4390 NFSOPBIT_CLRNOTALLOWED(&allowops);
4391 NFSSET_OPBIT(&clp->lc_allowops, &allowops);
4392 clp->lc_flags |= LCL_MACHCRED;
4393 } else if (sp4type != NFSV4EXCH_SP4NONE) {
4394 nd->nd_repstat = NFSERR_NOTSUPP;
4399 * nfsrv_setclient() does the actual work of adding it to the
4400 * client list. If there is no error, the structure has been
4401 * linked into the client list and clp should no longer be used
4402 * here. When an error is returned, it has not been linked in,
4403 * so it should be free'd.
4405 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4407 free(clp->lc_req.nr_nam, M_SONAME);
4408 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4409 free(clp->lc_stateid, M_NFSDCLIENT);
4410 free(clp, M_NFSDCLIENT);
4412 if (nd->nd_repstat == 0) {
4413 if (confirm.lval[1] != 0)
4414 v41flags |= NFSV4EXCH_CONFIRMEDR;
4415 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
4416 *tl++ = clientid.lval[0]; /* ClientID */
4417 *tl++ = clientid.lval[1];
4418 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4419 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4420 *tl = txdr_unsigned(sp4type); /* No SSV */
4421 if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4422 nfsrv_putopbit(nd, &mustops);
4423 nfsrv_putopbit(nd, &allowops);
4425 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER);
4426 txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */
4427 if (nfsrv_owner_major[0] != 0)
4428 s = nfsrv_owner_major;
4430 s = nd->nd_cred->cr_prison->pr_hostuuid;
4431 nfsm_strtom(nd, s, strlen(s)); /* Owner Major */
4432 if (nfsrv_scope[0] != 0)
4435 s = nd->nd_cred->cr_prison->pr_hostuuid;
4436 nfsm_strtom(nd, s, strlen(s) ); /* Scope */
4437 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4438 *tl = txdr_unsigned(1);
4439 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4440 (void)nfsm_strtom(nd, version, strlen(version));
4441 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4442 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4443 verstime.tv_nsec = 0;
4444 txdr_nfsv4time(&verstime, tl);
4446 NFSEXITCODE2(0, nd);
4450 free(clp->lc_req.nr_nam, M_SONAME);
4451 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4452 free(clp->lc_stateid, M_NFSDCLIENT);
4453 free(clp, M_NFSDCLIENT);
4455 NFSEXITCODE2(error, nd);
4460 * nfsv4 create session service
4463 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4464 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4468 nfsquad_t clientid, confirm;
4469 struct nfsdsession *sep = NULL;
4471 struct thread *p = curthread;
4472 static bool do_printf = true;
4474 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4476 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4477 M_NFSDSESSION, M_WAITOK | M_ZERO);
4478 sep->sess_refcnt = 1;
4479 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4480 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4481 clientid.lval[0] = *tl++;
4482 clientid.lval[1] = *tl++;
4483 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4484 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4485 /* Persistent sessions and RDMA are not supported. */
4486 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4488 /* Fore channel attributes. */
4489 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4490 tl++; /* Header pad always 0. */
4491 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4492 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4493 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4495 printf("Consider increasing kern.ipc.maxsockbuf\n");
4498 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4499 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4500 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4502 printf("Consider increasing kern.ipc.maxsockbuf\n");
4505 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4506 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4507 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4508 if (sep->sess_maxslots > NFSV4_SLOTS)
4509 sep->sess_maxslots = NFSV4_SLOTS;
4510 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4512 nd->nd_repstat = NFSERR_BADXDR;
4514 } else if (rdmacnt == 1)
4515 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4517 /* Back channel attributes. */
4518 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4519 tl++; /* Header pad always 0. */
4520 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4521 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4522 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4523 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4524 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4525 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4527 nd->nd_repstat = NFSERR_BADXDR;
4529 } else if (rdmacnt == 1)
4530 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4532 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4533 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4536 * nfsrv_getclient() searches the client list for a match and
4537 * returns the appropriate NFSERR status.
4539 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4540 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4541 if (nd->nd_repstat == 0) {
4542 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4543 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4544 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4545 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4546 *tl++ = txdr_unsigned(sep->sess_crflags);
4548 /* Fore channel attributes. */
4550 *tl++ = txdr_unsigned(sep->sess_maxreq);
4551 *tl++ = txdr_unsigned(sep->sess_maxresp);
4552 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4553 *tl++ = txdr_unsigned(sep->sess_maxops);
4554 *tl++ = txdr_unsigned(sep->sess_maxslots);
4555 *tl++ = txdr_unsigned(1);
4556 *tl++ = txdr_unsigned(0); /* No RDMA. */
4558 /* Back channel attributes. */
4560 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4561 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4562 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4563 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4564 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4565 *tl++ = txdr_unsigned(1);
4566 *tl = txdr_unsigned(0); /* No RDMA. */
4569 if (nd->nd_repstat != 0 && sep != NULL)
4570 free(sep, M_NFSDSESSION);
4571 NFSEXITCODE2(error, nd);
4576 * nfsv4 sequence service
4579 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4580 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4583 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4584 int cache_this, error = 0;
4585 struct thread *p = curthread;
4587 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4589 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4590 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4591 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4592 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4593 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4594 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4595 if (*tl == newnfs_true)
4599 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4600 &target_highest_slotid, cache_this, &sflags, p);
4601 if (nd->nd_repstat != NFSERR_BADSLOT)
4602 nd->nd_flag |= ND_HASSEQUENCE;
4603 if (nd->nd_repstat == 0) {
4604 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4605 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4606 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4607 *tl++ = txdr_unsigned(sequenceid);
4608 *tl++ = txdr_unsigned(nd->nd_slotid);
4609 *tl++ = txdr_unsigned(highest_slotid);
4610 *tl++ = txdr_unsigned(target_highest_slotid);
4611 *tl = txdr_unsigned(sflags);
4614 NFSEXITCODE2(error, nd);
4619 * nfsv4 reclaim complete service
4622 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4623 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4626 int error = 0, onefs;
4628 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4630 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4631 * to be used after a file system has been transferred to a different
4632 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4633 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4634 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4635 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4636 * NFS_OK without doing anything.
4639 if (*tl == newnfs_true)
4641 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4643 NFSEXITCODE2(error, nd);
4648 * nfsv4 destroy clientid service
4651 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4652 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4657 struct thread *p = curthread;
4659 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4661 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4662 clientid.lval[0] = *tl++;
4663 clientid.lval[1] = *tl;
4664 nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p);
4666 NFSEXITCODE2(error, nd);
4671 * nfsv4 bind connection to session service
4674 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4675 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4678 uint8_t sessid[NFSX_V4SESSIONID];
4679 int error = 0, foreaft;
4681 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4683 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4684 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4685 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4686 foreaft = fxdr_unsigned(int, *tl++);
4687 if (*tl == newnfs_true) {
4688 /* RDMA is not supported. */
4689 nd->nd_repstat = NFSERR_NOTSUPP;
4693 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4694 if (nd->nd_repstat == 0) {
4695 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4697 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4698 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4699 *tl++ = txdr_unsigned(foreaft);
4703 NFSEXITCODE2(error, nd);
4708 * nfsv4 destroy session service
4711 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4712 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4714 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4717 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4719 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4720 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4721 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4723 NFSEXITCODE2(error, nd);
4728 * nfsv4 free stateid service
4731 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4732 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4735 nfsv4stateid_t stateid;
4737 struct thread *p = curthread;
4739 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4740 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4741 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4744 * For the special stateid of other all 0s and seqid == 1, set the
4745 * stateid to the current stateid, if it is set.
4747 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4748 stateid.other[1] == 0 && stateid.other[2] == 0) {
4749 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4750 stateid = nd->nd_curstateid;
4753 nd->nd_repstat = NFSERR_BADSTATEID;
4758 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4760 /* If the current stateid has been free'd, unset it. */
4761 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4762 stateid.other[0] == nd->nd_curstateid.other[0] &&
4763 stateid.other[1] == nd->nd_curstateid.other[1] &&
4764 stateid.other[2] == nd->nd_curstateid.other[2])
4765 nd->nd_flag &= ~ND_CURSTATEID;
4767 NFSEXITCODE2(error, nd);
4772 * nfsv4 layoutget service
4775 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4776 vnode_t vp, struct nfsexstuff *exp)
4779 nfsv4stateid_t stateid;
4780 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4781 uint64_t offset, len, minlen;
4783 struct thread *p = curthread;
4785 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4787 tl++; /* Signal layout available. Ignore for now. */
4788 layouttype = fxdr_unsigned(int, *tl++);
4789 iomode = fxdr_unsigned(int, *tl++);
4790 offset = fxdr_hyper(tl); tl += 2;
4791 len = fxdr_hyper(tl); tl += 2;
4792 minlen = fxdr_hyper(tl); tl += 2;
4793 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4794 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4795 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4796 maxcnt = fxdr_unsigned(int, *tl);
4797 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4798 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4801 (minlen != UINT64_MAX && offset + minlen < offset) ||
4802 (len != UINT64_MAX && offset + len < offset)) {
4803 nd->nd_repstat = NFSERR_INVAL;
4808 * For the special stateid of other all 0s and seqid == 1, set the
4809 * stateid to the current stateid, if it is set.
4811 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4812 stateid.other[1] == 0 && stateid.other[2] == 0) {
4813 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4814 stateid = nd->nd_curstateid;
4817 nd->nd_repstat = NFSERR_BADSTATEID;
4823 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4824 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4825 else if (layouttype == NFSLAYOUT_FLEXFILE)
4826 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4829 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4831 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4832 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4833 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4834 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4836 if (nd->nd_repstat == 0) {
4837 /* For NFSv4.1, set the Current StateID. */
4838 if ((nd->nd_flag & ND_NFSV41) != 0) {
4839 nd->nd_curstateid = stateid;
4840 nd->nd_flag |= ND_CURSTATEID;
4842 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4844 *tl++ = txdr_unsigned(retonclose);
4845 *tl++ = txdr_unsigned(stateid.seqid);
4846 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4847 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4848 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4849 txdr_hyper(offset, tl); tl += 2;
4850 txdr_hyper(len, tl); tl += 2;
4851 *tl++ = txdr_unsigned(iomode);
4852 *tl = txdr_unsigned(layouttype);
4853 nfsm_strtom(nd, layp, layoutlen);
4854 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4855 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4861 NFSEXITCODE2(error, nd);
4866 * nfsv4 layoutcommit service
4869 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4870 vnode_t vp, struct nfsexstuff *exp)
4873 nfsv4stateid_t stateid;
4874 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4876 uint64_t offset, len, newoff = 0, newsize;
4877 struct timespec newmtime;
4879 struct thread *p = curthread;
4882 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4884 offset = fxdr_hyper(tl); tl += 2;
4885 len = fxdr_hyper(tl); tl += 2;
4886 reclaim = fxdr_unsigned(int, *tl++);
4887 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4888 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4889 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4891 * For the special stateid of other all 0s and seqid == 1, set the
4892 * stateid to the current stateid, if it is set.
4894 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4895 stateid.other[1] == 0 && stateid.other[2] == 0) {
4896 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4897 stateid = nd->nd_curstateid;
4900 nd->nd_repstat = NFSERR_BADSTATEID;
4905 hasnewoff = fxdr_unsigned(int, *tl);
4906 if (hasnewoff != 0) {
4907 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4908 newoff = fxdr_hyper(tl); tl += 2;
4910 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4911 hasnewmtime = fxdr_unsigned(int, *tl);
4912 if (hasnewmtime != 0) {
4913 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4914 fxdr_nfsv4time(tl, &newmtime);
4915 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4917 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4918 layouttype = fxdr_unsigned(int, *tl++);
4919 maxcnt = fxdr_unsigned(int, *tl);
4921 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4922 error = nfsrv_mtostr(nd, layp, maxcnt);
4926 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4927 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4928 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4929 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4930 if (nd->nd_repstat == 0) {
4931 if (hasnewsize != 0) {
4932 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4933 *tl++ = newnfs_true;
4934 txdr_hyper(newsize, tl);
4936 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4943 NFSEXITCODE2(error, nd);
4948 * nfsv4 layoutreturn service
4951 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4952 vnode_t vp, struct nfsexstuff *exp)
4954 uint32_t *tl, *layp;
4955 nfsv4stateid_t stateid;
4956 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4957 uint64_t offset, len;
4958 struct thread *p = curthread;
4961 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4963 layouttype = fxdr_unsigned(int, *tl++);
4964 iomode = fxdr_unsigned(int, *tl++);
4965 kind = fxdr_unsigned(int, *tl);
4966 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4967 layouttype, iomode, kind);
4968 if (kind == NFSV4LAYOUTRET_FILE) {
4969 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4971 offset = fxdr_hyper(tl); tl += 2;
4972 len = fxdr_hyper(tl); tl += 2;
4973 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4974 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4975 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4978 * For the special stateid of other all 0s and seqid == 1, set
4979 * the stateid to the current stateid, if it is set.
4981 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4982 stateid.other[1] == 0 && stateid.other[2] == 0) {
4983 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4984 stateid = nd->nd_curstateid;
4987 nd->nd_repstat = NFSERR_BADSTATEID;
4992 maxcnt = fxdr_unsigned(int, *tl);
4994 * There is no fixed upper bound defined in the RFCs,
4995 * but 128Kbytes should be more than sufficient.
4997 if (maxcnt < 0 || maxcnt > 131072)
5000 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5001 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
5006 if (reclaim == newnfs_true) {
5007 nd->nd_repstat = NFSERR_INVAL;
5013 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
5014 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
5016 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
5018 if (nd->nd_repstat == 0) {
5019 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5022 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
5023 *tl++ = txdr_unsigned(stateid.seqid);
5024 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5031 NFSEXITCODE2(error, nd);
5036 * nfsv4 layout error service
5039 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
5040 vnode_t vp, struct nfsexstuff *exp)
5043 nfsv4stateid_t stateid;
5044 int cnt, error = 0, i, stat;
5046 char devid[NFSX_V4DEVICEID];
5047 uint64_t offset, len;
5049 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5051 offset = fxdr_hyper(tl); tl += 2;
5052 len = fxdr_hyper(tl); tl += 2;
5053 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5054 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5055 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5056 cnt = fxdr_unsigned(int, *tl);
5057 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
5058 (uintmax_t)len, cnt);
5060 * For the special stateid of other all 0s and seqid == 1, set
5061 * the stateid to the current stateid, if it is set.
5063 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5064 stateid.other[1] == 0 && stateid.other[2] == 0) {
5065 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5066 stateid = nd->nd_curstateid;
5069 nd->nd_repstat = NFSERR_BADSTATEID;
5075 * Ignore offset, len and stateid for now.
5077 for (i = 0; i < cnt; i++) {
5078 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
5080 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5081 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5082 stat = fxdr_unsigned(int, *tl++);
5083 opnum = fxdr_unsigned(int, *tl);
5084 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
5086 * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
5087 * errors, disable the mirror.
5089 if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
5090 stat != NFSERR_NOSPC)
5091 nfsrv_delds(devid, curthread);
5093 /* For NFSERR_NOSPC, mark all deviceids and layouts. */
5094 if (stat == NFSERR_NOSPC)
5095 nfsrv_marknospc(devid, true);
5099 NFSEXITCODE2(error, nd);
5104 * nfsv4 layout stats service
5107 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
5108 vnode_t vp, struct nfsexstuff *exp)
5111 nfsv4stateid_t stateid;
5113 int layouttype __unused;
5114 char devid[NFSX_V4DEVICEID] __unused;
5115 uint64_t offset __unused, len __unused, readcount __unused;
5116 uint64_t readbytes __unused, writecount __unused, writebytes __unused;
5118 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
5119 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
5120 offset = fxdr_hyper(tl); tl += 2;
5121 len = fxdr_hyper(tl); tl += 2;
5122 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5123 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5124 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5125 readcount = fxdr_hyper(tl); tl += 2;
5126 readbytes = fxdr_hyper(tl); tl += 2;
5127 writecount = fxdr_hyper(tl); tl += 2;
5128 writebytes = fxdr_hyper(tl); tl += 2;
5129 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5130 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5131 layouttype = fxdr_unsigned(int, *tl++);
5132 cnt = fxdr_unsigned(int, *tl);
5133 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
5136 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
5138 * For the special stateid of other all 0s and seqid == 1, set
5139 * the stateid to the current stateid, if it is set.
5141 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5142 stateid.other[1] == 0 && stateid.other[2] == 0) {
5143 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5144 stateid = nd->nd_curstateid;
5147 nd->nd_repstat = NFSERR_BADSTATEID;
5153 * No use for the stats for now.
5157 NFSEXITCODE2(error, nd);
5162 * nfsv4 io_advise service
5165 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
5166 vnode_t vp, struct nfsexstuff *exp)
5169 nfsv4stateid_t stateid;
5174 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5175 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5176 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5177 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5178 offset = fxdr_hyper(tl); tl += 2;
5179 len = fxdr_hyper(tl);
5180 error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
5184 * For the special stateid of other all 0s and seqid == 1, set
5185 * the stateid to the current stateid, if it is set.
5187 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5188 stateid.other[1] == 0 && stateid.other[2] == 0) {
5189 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5190 stateid = nd->nd_curstateid;
5193 nd->nd_repstat = NFSERR_BADSTATEID;
5199 nd->nd_repstat = NFSERR_INVAL;
5204 if (vp->v_type != VREG) {
5205 if (vp->v_type == VDIR)
5206 nd->nd_repstat = NFSERR_ISDIR;
5208 nd->nd_repstat = NFSERR_WRONGTYPE;
5213 * For now, we can only handle WILLNEED and DONTNEED and don't use
5216 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5217 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5218 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5219 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5221 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5222 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5223 NFSZERO_ATTRBIT(&hints);
5225 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5227 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5229 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5230 NFSZERO_ATTRBIT(&hints);
5232 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5234 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5238 NFSZERO_ATTRBIT(&hints);
5239 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5242 nfsrv_putattrbit(nd, &hints);
5243 NFSEXITCODE2(error, nd);
5247 NFSEXITCODE2(error, nd);
5252 * nfsv4 getdeviceinfo service
5255 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5256 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5258 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5259 int cnt, devaddrlen, error = 0, i, layouttype;
5260 char devid[NFSX_V4DEVICEID], *devaddr;
5263 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5264 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5265 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5266 layouttype = fxdr_unsigned(int, *tl++);
5267 maxcnt = fxdr_unsigned(uint32_t, *tl++);
5268 cnt = fxdr_unsigned(int, *tl);
5269 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5271 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5272 nd->nd_repstat = NFSERR_INVAL;
5276 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5277 for (i = 0; i < cnt; i++)
5278 notify[i] = fxdr_unsigned(uint32_t, *tl++);
5280 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5284 * Check that the device id is not stale. Device ids are recreated
5285 * each time the nfsd threads are restarted.
5287 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5288 if (dev_time != nfsdev_time) {
5289 nd->nd_repstat = NFSERR_NOENT;
5293 /* Look for the device id. */
5294 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5295 notify, &devaddrlen, &devaddr);
5296 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5297 if (nd->nd_repstat == 0) {
5298 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5299 *tl = txdr_unsigned(layouttype);
5300 nfsm_strtom(nd, devaddr, devaddrlen);
5302 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5306 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5307 *tl++ = txdr_unsigned(cnt);
5308 for (i = 0; i < cnt; i++)
5309 *tl++ = txdr_unsigned(notify[i]);
5310 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5311 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5312 *tl = txdr_unsigned(maxcnt);
5315 NFSEXITCODE2(error, nd);
5320 * nfsv4 test stateid service
5323 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5324 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5327 nfsv4stateid_t *stateidp = NULL, *tstateidp;
5328 int cnt, error = 0, i, ret;
5329 struct thread *p = curthread;
5331 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5332 cnt = fxdr_unsigned(int, *tl);
5333 if (cnt <= 0 || cnt > 1024) {
5334 nd->nd_repstat = NFSERR_BADXDR;
5337 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5338 tstateidp = stateidp;
5339 for (i = 0; i < cnt; i++) {
5340 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5341 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5342 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5345 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5346 *tl = txdr_unsigned(cnt);
5347 tstateidp = stateidp;
5348 for (i = 0; i < cnt; i++) {
5349 ret = nfsrv_teststateid(nd, tstateidp, p);
5350 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5351 *tl = txdr_unsigned(ret);
5355 free(stateidp, M_TEMP);
5356 NFSEXITCODE2(error, nd);
5361 * nfs allocate service
5364 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5365 vnode_t vp, struct nfsexstuff *exp)
5368 struct nfsvattr forat;
5369 int error = 0, forat_ret = 1, gotproxystateid;
5371 struct nfsstate st, *stp = &st;
5372 struct nfslock lo, *lop = &lo;
5373 nfsv4stateid_t stateid;
5375 nfsattrbit_t attrbits;
5377 if (!nfsrv_doallocate) {
5379 * If any exported file system, such as a ZFS one, cannot
5380 * do VOP_ALLOCATE(), this operation cannot be supported
5381 * for NFSv4.2. This cannot be done 'per filesystem', but
5382 * must be for the entire nfsd NFSv4.2 service.
5384 nd->nd_repstat = NFSERR_NOTSUPP;
5387 gotproxystateid = 0;
5388 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5389 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5390 lop->lo_flags = NFSLCK_WRITE;
5391 stp->ls_ownerlen = 0;
5393 stp->ls_uid = nd->nd_cred->cr_uid;
5394 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5395 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5396 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5397 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5398 if ((nd->nd_flag & ND_NFSV41) != 0)
5399 clientid.qval = nd->nd_clientid.qval;
5400 else if (nd->nd_clientid.qval != clientid.qval)
5401 printf("EEK2 multiple clids\n");
5403 if ((nd->nd_flag & ND_NFSV41) != 0)
5404 printf("EEK! no clientid from session\n");
5405 nd->nd_flag |= ND_IMPLIEDCLID;
5406 nd->nd_clientid.qval = clientid.qval;
5408 stp->ls_stateid.other[2] = *tl++;
5410 * Don't allow this to be done for a DS.
5412 if ((nd->nd_flag & ND_DSSERVER) != 0)
5413 nd->nd_repstat = NFSERR_NOTSUPP;
5414 /* However, allow the proxy stateid. */
5415 if (stp->ls_stateid.seqid == 0xffffffff &&
5416 stp->ls_stateid.other[0] == 0x55555555 &&
5417 stp->ls_stateid.other[1] == 0x55555555 &&
5418 stp->ls_stateid.other[2] == 0x55555555)
5419 gotproxystateid = 1;
5420 off = fxdr_hyper(tl); tl += 2;
5421 lop->lo_first = off;
5422 len = fxdr_hyper(tl);
5423 lop->lo_end = lop->lo_first + len;
5425 * Sanity check the offset and length.
5426 * off and len are off_t (signed int64_t) whereas
5427 * lo_first and lo_end are uint64_t and, as such,
5428 * if off >= 0 && len > 0, lo_end cannot overflow
5429 * unless off_t is changed to something other than
5430 * int64_t. Check lo_end < lo_first in case that
5431 * is someday the case.
5433 if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end >
5434 OFF_MAX || lop->lo_end < lop->lo_first))
5435 nd->nd_repstat = NFSERR_INVAL;
5437 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5438 nd->nd_repstat = NFSERR_WRONGTYPE;
5439 NFSZERO_ATTRBIT(&attrbits);
5440 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5441 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5442 if (nd->nd_repstat == 0)
5443 nd->nd_repstat = forat_ret;
5444 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5445 NFSVNO_EXSTRICTACCESS(exp)))
5446 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5447 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5449 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5450 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5451 &stateid, exp, nd, curthread);
5453 NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n",
5454 (intmax_t)off, (intmax_t)len, nd->nd_repstat);
5455 if (nd->nd_repstat == 0)
5456 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5458 NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n",
5461 NFSEXITCODE2(0, nd);
5465 NFSEXITCODE2(error, nd);
5470 * nfs deallocate service
5473 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram,
5474 vnode_t vp, struct nfsexstuff *exp)
5477 struct nfsvattr forat;
5478 int error = 0, forat_ret = 1, gotproxystateid;
5480 struct nfsstate st, *stp = &st;
5481 struct nfslock lo, *lop = &lo;
5482 nfsv4stateid_t stateid;
5484 nfsattrbit_t attrbits;
5486 gotproxystateid = 0;
5487 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5488 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5489 lop->lo_flags = NFSLCK_WRITE;
5490 stp->ls_ownerlen = 0;
5492 stp->ls_uid = nd->nd_cred->cr_uid;
5493 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5494 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5495 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5496 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5497 if ((nd->nd_flag & ND_NFSV41) != 0)
5498 clientid.qval = nd->nd_clientid.qval;
5499 else if (nd->nd_clientid.qval != clientid.qval)
5500 printf("EEK2 multiple clids\n");
5502 if ((nd->nd_flag & ND_NFSV41) != 0)
5503 printf("EEK! no clientid from session\n");
5504 nd->nd_flag |= ND_IMPLIEDCLID;
5505 nd->nd_clientid.qval = clientid.qval;
5507 stp->ls_stateid.other[2] = *tl++;
5509 * Don't allow this to be done for a DS.
5511 if ((nd->nd_flag & ND_DSSERVER) != 0)
5512 nd->nd_repstat = NFSERR_NOTSUPP;
5513 /* However, allow the proxy stateid. */
5514 if (stp->ls_stateid.seqid == 0xffffffff &&
5515 stp->ls_stateid.other[0] == 0x55555555 &&
5516 stp->ls_stateid.other[1] == 0x55555555 &&
5517 stp->ls_stateid.other[2] == 0x55555555)
5518 gotproxystateid = 1;
5519 off = fxdr_hyper(tl); tl += 2;
5520 lop->lo_first = off;
5521 len = fxdr_hyper(tl);
5524 NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off,
5526 lop->lo_end = lop->lo_first + len;
5528 * Sanity check the offset and length.
5529 * off and len are off_t (signed int64_t) whereas
5530 * lo_first and lo_end are uint64_t and, as such,
5531 * if off >= 0 && len > 0, lo_end cannot overflow
5532 * unless off_t is changed to something other than
5533 * int64_t. Check lo_end < lo_first in case that
5534 * is someday the case.
5535 * The error to return is not specified by RFC 7862 so I
5536 * made this compatible with the Linux knfsd.
5538 if (nd->nd_repstat == 0) {
5539 if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE)
5540 nd->nd_repstat = NFSERR_FBIG;
5541 else if (len == 0 || lop->lo_end < lop->lo_first)
5542 nd->nd_repstat = NFSERR_INVAL;
5545 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5546 nd->nd_repstat = NFSERR_WRONGTYPE;
5547 NFSZERO_ATTRBIT(&attrbits);
5548 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5549 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5550 if (nd->nd_repstat == 0)
5551 nd->nd_repstat = forat_ret;
5552 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5553 NFSVNO_EXSTRICTACCESS(exp)))
5554 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5555 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5557 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5558 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5559 &stateid, exp, nd, curthread);
5561 if (nd->nd_repstat == 0)
5562 nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred,
5565 NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat);
5566 NFSEXITCODE2(0, nd);
5570 NFSEXITCODE2(error, nd);
5578 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5579 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5583 int cnt, error = 0, ret;
5584 off_t inoff, outoff;
5587 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5588 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5590 nfsv4stateid_t stateid;
5591 nfsattrbit_t attrbits;
5592 void *rl_rcookie, *rl_wcookie;
5594 rl_rcookie = rl_wcookie = NULL;
5595 if (nfsrv_devidcnt > 0) {
5597 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5598 * will do the copy via I/O on the DS(s).
5600 nd->nd_repstat = NFSERR_NOTSUPP;
5604 /* Copying a byte range within the same file is not allowed. */
5605 nd->nd_repstat = NFSERR_INVAL;
5608 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5610 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5611 inlop->lo_flags = NFSLCK_READ;
5612 instp->ls_ownerlen = 0;
5613 instp->ls_op = NULL;
5614 instp->ls_uid = nd->nd_cred->cr_uid;
5615 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5616 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5617 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5618 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5619 clientid.qval = nd->nd_clientid.qval;
5620 instp->ls_stateid.other[2] = *tl++;
5621 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5622 outlop->lo_flags = NFSLCK_WRITE;
5623 outstp->ls_ownerlen = 0;
5624 outstp->ls_op = NULL;
5625 outstp->ls_uid = nd->nd_cred->cr_uid;
5626 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5627 outstp->ls_stateid.other[0] = *tl++;
5628 outstp->ls_stateid.other[1] = *tl++;
5629 outstp->ls_stateid.other[2] = *tl++;
5630 inoff = fxdr_hyper(tl); tl += 2;
5631 inlop->lo_first = inoff;
5632 outoff = fxdr_hyper(tl); tl += 2;
5633 outlop->lo_first = outoff;
5634 len = fxdr_hyper(tl); tl += 2;
5636 /* len == 0 means to EOF. */
5637 inlop->lo_end = OFF_MAX;
5638 outlop->lo_end = OFF_MAX;
5640 inlop->lo_end = inlop->lo_first + len;
5641 outlop->lo_end = outlop->lo_first + len;
5645 * At this time only consecutive, synchronous copy is supported,
5646 * so ca_consecutive and ca_synchronous can be ignored.
5650 cnt = fxdr_unsigned(int, *tl);
5651 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5652 nd->nd_repstat = NFSERR_NOTSUPP;
5653 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5654 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5655 inlop->lo_end < inlop->lo_first || outlop->lo_end <
5657 nd->nd_repstat = NFSERR_INVAL;
5659 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5660 nd->nd_repstat = NFSERR_WRONGTYPE;
5662 /* Check permissions for the input file. */
5663 NFSZERO_ATTRBIT(&attrbits);
5664 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5665 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5666 if (nd->nd_repstat == 0)
5667 nd->nd_repstat = ret;
5668 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5669 NFSVNO_EXSTRICTACCESS(exp)))
5670 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5671 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5673 if (nd->nd_repstat == 0)
5674 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5675 clientid, &stateid, exp, nd, curthread);
5677 if (nd->nd_repstat != 0)
5680 error = NFSVOPLOCK(tovp, LK_SHARED);
5683 if (tovp->v_type != VREG)
5684 nd->nd_repstat = NFSERR_WRONGTYPE;
5686 /* For the output file, we only need the Owner attribute. */
5687 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5688 if (nd->nd_repstat == 0)
5689 nd->nd_repstat = ret;
5690 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5691 NFSVNO_EXSTRICTACCESS(exp)))
5692 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5693 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5695 if (nd->nd_repstat == 0)
5696 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5697 clientid, &stateid, toexp, nd, curthread);
5700 /* Range lock the byte ranges for both invp and outvp. */
5701 if (nd->nd_repstat == 0) {
5704 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5706 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5709 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5711 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5714 if (rl_rcookie != NULL)
5716 vn_rangelock_unlock(tovp, rl_wcookie);
5718 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5721 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5723 vn_rangelock_unlock(vp, rl_rcookie);
5726 error = NFSVOPLOCK(vp, LK_SHARED);
5728 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5731 * Since invp is range locked, na_size should
5734 if (len == 0 && at.na_size > inoff) {
5736 * If len == 0, set it based on invp's
5737 * size. If offset is past EOF, just
5740 len = at.na_size - inoff;
5741 } else if (nfsrv_linux42server == 0 &&
5742 inoff + len > at.na_size) {
5744 * RFC-7862 says that NFSERR_INVAL must
5745 * be returned when inoff + len exceeds
5746 * the file size, however the NFSv4.2
5747 * Linux client likes to do this, so
5748 * only check if nfsrv_linux42server
5751 nd->nd_repstat = NFSERR_INVAL;
5755 if (ret != 0 && nd->nd_repstat == 0)
5756 nd->nd_repstat = ret;
5757 } else if (nd->nd_repstat == 0)
5758 nd->nd_repstat = error;
5762 if (nd->nd_repstat == 0) {
5763 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5764 &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred,
5766 if (nd->nd_repstat == 0)
5770 /* Unlock the ranges. */
5771 if (rl_rcookie != NULL)
5772 vn_rangelock_unlock(vp, rl_rcookie);
5773 if (rl_wcookie != NULL)
5774 vn_rangelock_unlock(tovp, rl_wcookie);
5776 if (nd->nd_repstat == 0) {
5777 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5779 *tl++ = txdr_unsigned(0); /* No callback ids. */
5780 txdr_hyper(len, tl); tl += 2;
5781 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5782 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
5783 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
5784 *tl++ = newnfs_true;
5790 NFSEXITCODE2(error, nd);
5795 NFSEXITCODE2(error, nd);
5803 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5804 vnode_t vp, struct nfsexstuff *exp)
5808 int content, error = 0;
5811 nfsattrbit_t attrbits;
5814 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5815 /* Ignore the stateid for now. */
5816 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5817 off = fxdr_hyper(tl); tl += 2;
5818 content = fxdr_unsigned(int, *tl);
5819 if (content == NFSV4CONTENT_DATA)
5821 else if (content == NFSV4CONTENT_HOLE)
5824 nd->nd_repstat = NFSERR_BADXDR;
5825 if (nd->nd_repstat == 0 && vp->v_type == VDIR)
5826 nd->nd_repstat = NFSERR_ISDIR;
5827 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5828 nd->nd_repstat = NFSERR_WRONGTYPE;
5829 if (nd->nd_repstat == 0 && off < 0)
5830 nd->nd_repstat = NFSERR_NXIO;
5831 if (nd->nd_repstat == 0) {
5832 /* Check permissions for the input file. */
5833 NFSZERO_ATTRBIT(&attrbits);
5834 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5835 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5838 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5839 NFSVNO_EXSTRICTACCESS(exp)))
5840 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5841 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5843 if (nd->nd_repstat != 0)
5846 /* nfsvno_seek() unlocks and vrele()s the vp. */
5847 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5848 nd->nd_cred, curthread);
5849 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5850 nfsrv_linux42server != 0)
5851 nd->nd_repstat = NFSERR_NXIO;
5852 if (nd->nd_repstat == 0) {
5853 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5855 *tl++ = newnfs_true;
5857 *tl++ = newnfs_false;
5858 txdr_hyper(off, tl);
5860 NFSEXITCODE2(error, nd);
5864 NFSEXITCODE2(error, nd);
5869 * nfs get extended attribute service
5872 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5873 vnode_t vp, __unused struct nfsexstuff *exp)
5876 struct mbuf *mp = NULL, *mpend = NULL;
5879 struct thread *p = curthread;
5883 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5884 len = fxdr_unsigned(int, *tl);
5886 nd->nd_repstat = NFSERR_BADXDR;
5889 if (len > EXTATTR_MAXNAMELEN) {
5890 nd->nd_repstat = NFSERR_NOXATTR;
5893 name = malloc(len + 1, M_TEMP, M_WAITOK);
5894 nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5895 if (nd->nd_repstat == 0)
5896 nd->nd_repstat = nfsvno_getxattr(vp, name,
5897 nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
5898 nd->nd_maxextsiz, p, &mp, &mpend, &len);
5899 if (nd->nd_repstat == ENOATTR)
5900 nd->nd_repstat = NFSERR_NOXATTR;
5901 else if (nd->nd_repstat == EOPNOTSUPP)
5902 nd->nd_repstat = NFSERR_NOTSUPP;
5903 if (nd->nd_repstat == 0) {
5904 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5905 *tl = txdr_unsigned(len);
5907 nd->nd_mb->m_next = mp;
5909 if ((mpend->m_flags & M_EXTPG) != 0) {
5910 nd->nd_flag |= ND_EXTPG;
5911 nd->nd_bextpg = mpend->m_epg_npgs - 1;
5912 nd->nd_bpos = (char *)(void *)
5913 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
5914 off = (nd->nd_bextpg == 0) ?
5915 mpend->m_epg_1st_off : 0;
5916 nd->nd_bpos += off + mpend->m_epg_last_len;
5917 nd->nd_bextpgsiz = PAGE_SIZE -
5918 mpend->m_epg_last_len - off;
5920 nd->nd_bpos = mtod(mpend, char *) +
5927 if (nd->nd_repstat == 0)
5928 nd->nd_repstat = error;
5930 NFSEXITCODE2(0, nd);
5935 * nfs set extended attribute service
5938 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5939 vnode_t vp, __unused struct nfsexstuff *exp)
5942 struct nfsvattr ova, nva;
5943 nfsattrbit_t attrbits;
5944 int error, len, opt;
5947 struct thread *p = curthread;
5951 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5952 opt = fxdr_unsigned(int, *tl++);
5953 len = fxdr_unsigned(int, *tl);
5955 nd->nd_repstat = NFSERR_BADXDR;
5958 if (len > EXTATTR_MAXNAMELEN) {
5959 nd->nd_repstat = NFSERR_NOXATTR;
5962 name = malloc(len + 1, M_TEMP, M_WAITOK);
5963 error = nfsrv_mtostr(nd, name, len);
5966 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5967 len = fxdr_unsigned(int, *tl);
5968 if (len < 0 || len > IOSIZE_MAX) {
5969 nd->nd_repstat = NFSERR_XATTR2BIG;
5973 case NFSV4SXATTR_CREATE:
5974 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5975 &siz, nd->nd_cred, p);
5976 if (error != ENOATTR)
5977 nd->nd_repstat = NFSERR_EXIST;
5980 case NFSV4SXATTR_REPLACE:
5981 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5982 &siz, nd->nd_cred, p);
5984 nd->nd_repstat = NFSERR_NOXATTR;
5986 case NFSV4SXATTR_EITHER:
5989 nd->nd_repstat = NFSERR_BADXDR;
5991 if (nd->nd_repstat != 0)
5994 /* Now, do the Set Extended attribute, with Change before and after. */
5995 NFSZERO_ATTRBIT(&attrbits);
5996 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5997 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5998 if (nd->nd_repstat == 0) {
5999 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
6000 nd->nd_dpos, nd->nd_cred, p);
6001 if (nd->nd_repstat == ENXIO)
6002 nd->nd_repstat = NFSERR_XATTR2BIG;
6004 if (nd->nd_repstat == 0 && len > 0)
6005 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
6006 if (nd->nd_repstat == 0)
6007 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6008 if (nd->nd_repstat == 0) {
6009 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6010 *tl++ = newnfs_true;
6011 txdr_hyper(ova.na_filerev, tl); tl += 2;
6012 txdr_hyper(nva.na_filerev, tl);
6017 if (nd->nd_repstat == 0)
6018 nd->nd_repstat = error;
6020 NFSEXITCODE2(0, nd);
6025 * nfs remove extended attribute service
6028 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
6029 vnode_t vp, __unused struct nfsexstuff *exp)
6032 struct nfsvattr ova, nva;
6033 nfsattrbit_t attrbits;
6036 struct thread *p = curthread;
6040 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6041 len = fxdr_unsigned(int, *tl);
6043 nd->nd_repstat = NFSERR_BADXDR;
6046 if (len > EXTATTR_MAXNAMELEN) {
6047 nd->nd_repstat = NFSERR_NOXATTR;
6050 name = malloc(len + 1, M_TEMP, M_WAITOK);
6051 error = nfsrv_mtostr(nd, name, len);
6055 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
6056 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
6057 error = NFSERR_NOXATTR;
6061 * Now, do the Remove Extended attribute, with Change before and
6064 NFSZERO_ATTRBIT(&attrbits);
6065 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6066 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6067 if (nd->nd_repstat == 0) {
6068 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
6069 if (nd->nd_repstat == ENOATTR)
6070 nd->nd_repstat = NFSERR_NOXATTR;
6072 if (nd->nd_repstat == 0)
6073 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6074 if (nd->nd_repstat == 0) {
6075 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6076 *tl++ = newnfs_true;
6077 txdr_hyper(ova.na_filerev, tl); tl += 2;
6078 txdr_hyper(nva.na_filerev, tl);
6083 if (nd->nd_repstat == 0)
6084 nd->nd_repstat = error;
6086 NFSEXITCODE2(0, nd);
6091 * nfs list extended attribute service
6094 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
6095 vnode_t vp, __unused struct nfsexstuff *exp)
6097 uint32_t cnt, *tl, len, len2, i, pos, retlen;
6099 uint64_t cookie, cookie2;
6102 struct thread *p = curthread;
6106 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6108 * The cookie doesn't need to be in net byte order, but FreeBSD
6109 * does so to make it more readable in packet traces.
6111 cookie = fxdr_hyper(tl); tl += 2;
6112 len = fxdr_unsigned(uint32_t, *tl);
6113 if (len == 0 || cookie >= IOSIZE_MAX) {
6114 nd->nd_repstat = NFSERR_BADXDR;
6117 if (len > nd->nd_maxresp - NFS_MAXXDR)
6118 len = nd->nd_maxresp - NFS_MAXXDR;
6120 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
6122 if (nd->nd_repstat == EOPNOTSUPP)
6123 nd->nd_repstat = NFSERR_NOTSUPP;
6124 if (nd->nd_repstat == 0) {
6125 cookie2 = cookie + len;
6126 if (cookie2 < cookie)
6127 nd->nd_repstat = NFSERR_BADXDR;
6129 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
6130 if (nd->nd_repstat == 0 && len2 < retlen)
6131 nd->nd_repstat = NFSERR_TOOSMALL;
6132 if (nd->nd_repstat == 0) {
6133 /* Now copy the entries out. */
6135 /* The cookie was at eof. */
6136 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
6138 txdr_hyper(cookie2, tl); tl += 2;
6139 *tl++ = txdr_unsigned(0);
6144 /* Sanity check the cookie. */
6145 for (pos = 0; pos < len; pos += (i + 1)) {
6150 if (pos != cookie) {
6151 nd->nd_repstat = NFSERR_INVAL;
6155 /* Loop around copying the entrie(s) out. */
6159 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
6162 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
6164 txdr_hyper(cookie2, tl); tl += 2;
6166 retlen += nfsm_strtom(nd, &buf[pos + 1], i);
6173 * eof is set true/false by nfsvno_listxattr(), but if we
6174 * can't copy all entries returned by nfsvno_listxattr(),
6175 * we are not at eof.
6180 /* *tl is set above. */
6181 *tl = txdr_unsigned(cnt);
6182 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6188 nd->nd_repstat = NFSERR_TOOSMALL;
6193 if (nd->nd_repstat == 0)
6194 nd->nd_repstat = error;
6196 NFSEXITCODE2(0, nd);
6201 * nfsv4 service not supported
6204 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
6205 __unused vnode_t vp, __unused struct nfsexstuff *exp)
6208 nd->nd_repstat = NFSERR_NOTSUPP;
6209 NFSEXITCODE2(0, nd);