2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 #include "opt_inet6.h"
42 * nfs version 2, 3 and 4 server calls to vnode ops
43 * - these routines generally have 3 phases
44 * 1 - break down and validate rpc request in mbuf list
45 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
46 * function in nfsd_port.c
47 * 3 - build the rpc reply in an mbuf list
48 * For nfsv4, these functions are called for each Op within the Compound RPC.
52 #include <fs/nfs/nfsport.h>
55 extern u_int32_t newnfs_false, newnfs_true;
56 extern enum vtype nv34tov_type[8];
57 extern struct timeval nfsboottime;
58 extern int nfs_rootfhset;
59 extern int nfsrv_enable_crossmntpt;
60 extern int nfsrv_statehashsize;
61 extern int nfsrv_layouthashsize;
62 extern time_t nfsdev_time;
63 extern volatile int nfsrv_devidcnt;
64 extern int nfsd_debuglevel;
65 extern u_long sb_max_adj;
66 extern int nfsrv_pnfsatime;
67 extern int nfsrv_maxpnfsmirror;
68 #endif /* !APPLEKEXT */
70 static int nfs_async = 0;
71 SYSCTL_DECL(_vfs_nfsd);
72 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
73 "Tell client that writes were synced even though they were not");
74 extern int nfsrv_doflexfile;
75 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
76 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
79 * This list defines the GSS mechanisms supported.
80 * (Don't ask me how you get these strings from the RFC stuff like
81 * iso(1), org(3)... but someone did it, so I don't need to know.)
83 static struct nfsgss_mechlist nfsgss_mechlist[] = {
84 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
89 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
90 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
91 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
92 int *diraft_retp, nfsattrbit_t *attrbitp,
93 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
95 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
96 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
97 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
98 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
99 NFSPROC_T *p, struct nfsexstuff *exp);
102 * nfs access service (not a part of NFS V2)
105 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
106 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
109 int getret, error = 0;
111 u_int32_t testmode, nfsmode, supported = 0;
114 if (nd->nd_repstat) {
115 nfsrv_postopattr(nd, 1, &nva);
118 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
119 nfsmode = fxdr_unsigned(u_int32_t, *tl);
120 if ((nd->nd_flag & ND_NFSV4) &&
121 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
122 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
123 NFSACCESS_EXECUTE))) {
124 nd->nd_repstat = NFSERR_INVAL;
128 if (nfsmode & NFSACCESS_READ) {
129 supported |= NFSACCESS_READ;
130 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
131 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
132 nfsmode &= ~NFSACCESS_READ;
134 if (nfsmode & NFSACCESS_MODIFY) {
135 supported |= NFSACCESS_MODIFY;
136 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
137 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
138 nfsmode &= ~NFSACCESS_MODIFY;
140 if (nfsmode & NFSACCESS_EXTEND) {
141 supported |= NFSACCESS_EXTEND;
142 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
143 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
144 nfsmode &= ~NFSACCESS_EXTEND;
146 if (nfsmode & NFSACCESS_DELETE) {
147 supported |= NFSACCESS_DELETE;
148 if (vp->v_type == VDIR)
149 deletebit = VDELETE_CHILD;
152 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
153 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
154 nfsmode &= ~NFSACCESS_DELETE;
156 if (vnode_vtype(vp) == VDIR)
157 testmode = NFSACCESS_LOOKUP;
159 testmode = NFSACCESS_EXECUTE;
160 if (nfsmode & testmode) {
161 supported |= (nfsmode & testmode);
162 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
163 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
164 nfsmode &= ~testmode;
166 nfsmode &= supported;
167 if (nd->nd_flag & ND_NFSV3) {
168 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
169 nfsrv_postopattr(nd, getret, &nva);
172 if (nd->nd_flag & ND_NFSV4) {
173 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
174 *tl++ = txdr_unsigned(supported);
176 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
177 *tl = txdr_unsigned(nfsmode);
184 NFSEXITCODE2(error, nd);
189 * nfs getattr service
192 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
193 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
197 int at_root = 0, error = 0, supports_nfsv4acls;
198 struct nfsreferral *refp;
199 nfsattrbit_t attrbits, tmpbits;
201 struct vnode *tvp = NULL;
203 uint64_t mounted_on_fileno = 0;
208 if (nd->nd_flag & ND_NFSV4) {
209 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
216 * Check for a referral.
218 refp = nfsv4root_getreferral(vp, NULL, 0);
220 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
225 if (nd->nd_repstat == 0) {
227 NFSSET_ATTRBIT(&tmpbits, &attrbits);
230 * GETATTR with write-only attr time_access_set and time_modify_set
231 * should return NFS4ERR_INVAL.
233 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
234 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
235 error = NFSERR_INVAL;
239 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
240 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
241 accmode |= VREAD_ACL;
243 if (NFSNONZERO_ATTRBIT(&tmpbits))
244 accmode |= VREAD_ATTRIBUTES;
246 nd->nd_repstat = nfsvno_accchk(vp, accmode,
247 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
248 NFSACCCHK_VPISLOCKED, NULL);
252 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
253 if (!nd->nd_repstat) {
254 if (nd->nd_flag & ND_NFSV4) {
255 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
256 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
258 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
260 if (nd->nd_repstat == 0) {
261 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
263 if (nfsrv_enable_crossmntpt != 0 &&
264 vp->v_type == VDIR &&
265 (vp->v_vflag & VV_ROOT) != 0 &&
267 tvp = mp->mnt_vnodecovered;
275 if ((nd->nd_repstat =
276 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
277 nd->nd_repstat = VOP_GETATTR(
278 tvp, &va, nd->nd_cred);
282 if (nd->nd_repstat == 0)
283 mounted_on_fileno = (uint64_t)
288 if (nd->nd_repstat == 0)
289 nd->nd_repstat = vfs_busy(mp, 0);
291 if (nd->nd_repstat == 0) {
292 (void)nfsvno_fillattr(nd, mp, vp, &nva,
293 &fh, 0, &attrbits, nd->nd_cred, p,
294 isdgram, 1, supports_nfsv4acls,
295 at_root, mounted_on_fileno);
302 nfsrv_fillattr(nd, &nva);
310 NFSEXITCODE2(error, nd);
315 * nfs setattr service
318 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
319 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
321 struct nfsvattr nva, nva2;
323 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
325 struct timespec guard = { 0, 0 };
326 nfsattrbit_t attrbits, retbits;
327 nfsv4stateid_t stateid;
328 NFSACL_T *aclp = NULL;
330 if (nd->nd_repstat) {
331 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
334 #ifdef NFS4_ACL_EXTATTR_NAME
335 aclp = acl_alloc(M_WAITOK);
339 NFSVNO_ATTRINIT(&nva);
340 if (nd->nd_flag & ND_NFSV4) {
341 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
342 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
343 stateid.other[0] = *tl++;
344 stateid.other[1] = *tl++;
345 stateid.other[2] = *tl;
346 if (stateid.other[0] == 0x55555555 &&
347 stateid.other[1] == 0x55555555 &&
348 stateid.other[2] == 0x55555555 &&
349 stateid.seqid == 0xffffffff)
352 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
356 /* For NFSv4, only va_uid is used from nva2. */
357 NFSZERO_ATTRBIT(&retbits);
358 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
359 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
361 nd->nd_repstat = preat_ret;
363 NFSZERO_ATTRBIT(&retbits);
364 if (nd->nd_flag & ND_NFSV3) {
365 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
366 gcheck = fxdr_unsigned(int, *tl);
368 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
369 fxdr_nfsv3time(tl, &guard);
371 if (!nd->nd_repstat && gcheck &&
372 (nva2.na_ctime.tv_sec != guard.tv_sec ||
373 nva2.na_ctime.tv_nsec != guard.tv_nsec))
374 nd->nd_repstat = NFSERR_NOT_SYNC;
375 if (nd->nd_repstat) {
377 #ifdef NFS4_ACL_EXTATTR_NAME
380 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
383 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
384 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
387 * Now that we have all the fields, lets do it.
388 * If the size is being changed write access is required, otherwise
389 * just check for a read only file system.
391 if (!nd->nd_repstat) {
392 if (NFSVNO_NOTSETSIZE(&nva)) {
393 if (NFSVNO_EXRDONLY(exp) ||
394 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
395 nd->nd_repstat = EROFS;
397 if (vnode_vtype(vp) != VREG)
398 nd->nd_repstat = EINVAL;
399 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
400 NFSVNO_EXSTRICTACCESS(exp))
401 nd->nd_repstat = nfsvno_accchk(vp,
402 VWRITE, nd->nd_cred, exp, p,
403 NFSACCCHK_NOOVERRIDE,
404 NFSACCCHK_VPISLOCKED, NULL);
408 * Proxy operations from the MDS are allowed via the all 0s special
411 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
412 gotproxystateid == 0)
413 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
414 &nva, &attrbits, exp, p);
416 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
418 * For V4, try setting the attrbutes in sets, so that the
419 * reply bitmap will be correct for an error case.
421 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
422 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
423 NFSVNO_ATTRINIT(&nva2);
424 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
425 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
426 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
428 if (!nd->nd_repstat) {
429 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
430 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
431 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
432 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
435 if (!nd->nd_repstat &&
436 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
437 NFSVNO_ATTRINIT(&nva2);
438 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
439 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
442 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
444 if (!nd->nd_repstat &&
445 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
446 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
447 NFSVNO_ATTRINIT(&nva2);
448 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
449 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
450 if (nva.na_vaflags & VA_UTIMES_NULL) {
451 nva2.na_vaflags |= VA_UTIMES_NULL;
452 NFSVNO_SETACTIVE(&nva2, vaflags);
454 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
456 if (!nd->nd_repstat) {
457 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
458 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
459 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
460 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
463 if (!nd->nd_repstat &&
464 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
465 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
466 NFSVNO_ATTRINIT(&nva2);
467 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
468 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
470 if (!nd->nd_repstat) {
471 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
472 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
473 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
474 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
478 #ifdef NFS4_ACL_EXTATTR_NAME
479 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
480 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
481 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
483 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
486 } else if (!nd->nd_repstat) {
487 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
490 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
491 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
493 nd->nd_repstat = postat_ret;
496 #ifdef NFS4_ACL_EXTATTR_NAME
499 if (nd->nd_flag & ND_NFSV3)
500 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
501 else if (nd->nd_flag & ND_NFSV4)
502 (void) nfsrv_putattrbit(nd, &retbits);
503 else if (!nd->nd_repstat)
504 nfsrv_fillattr(nd, &nva);
511 #ifdef NFS4_ACL_EXTATTR_NAME
514 if (nd->nd_flag & ND_NFSV4) {
516 * For all nd_repstat, the V4 reply includes a bitmap,
517 * even NFSERR_BADXDR, which is what this will end up
520 (void) nfsrv_putattrbit(nd, &retbits);
522 NFSEXITCODE2(error, nd);
528 * (Also performs lookup parent for v4)
531 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
532 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
533 struct nfsexstuff *exp)
535 struct nameidata named;
536 vnode_t vp, dirp = NULL;
537 int error = 0, dattr_ret = 1;
538 struct nfsvattr nva, dattr;
542 if (nd->nd_repstat) {
543 nfsrv_postopattr(nd, dattr_ret, &dattr);
548 * For some reason, if dp is a symlink, the error
549 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
551 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
552 nd->nd_repstat = NFSERR_SYMLINK;
557 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
558 LOCKLEAF | SAVESTART);
559 nfsvno_setpathbuf(&named, &bufp, &hashp);
560 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
563 nfsvno_relpathbuf(&named);
566 if (!nd->nd_repstat) {
567 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
570 nfsvno_relpathbuf(&named);
572 if (nd->nd_repstat) {
574 if (nd->nd_flag & ND_NFSV3)
575 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
579 if (nd->nd_flag & ND_NFSV3)
580 nfsrv_postopattr(nd, dattr_ret, &dattr);
583 if (named.ni_startdir)
584 vrele(named.ni_startdir);
585 nfsvno_relpathbuf(&named);
587 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
588 vp->v_type != VDIR && vp->v_type != VLNK)
590 * Only allow lookup of VDIR and VLNK for traversal of
591 * non-exported volumes during NFSv4 mounting.
593 nd->nd_repstat = ENOENT;
594 if (nd->nd_repstat == 0)
595 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
596 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
597 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
598 if (vpp != NULL && nd->nd_repstat == 0)
603 if (nd->nd_flag & ND_NFSV3)
604 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
608 if (nd->nd_repstat) {
609 if (nd->nd_flag & ND_NFSV3)
610 nfsrv_postopattr(nd, dattr_ret, &dattr);
613 if (nd->nd_flag & ND_NFSV2) {
614 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
615 nfsrv_fillattr(nd, &nva);
616 } else if (nd->nd_flag & ND_NFSV3) {
617 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
618 nfsrv_postopattr(nd, 0, &nva);
619 nfsrv_postopattr(nd, dattr_ret, &dattr);
623 NFSEXITCODE2(error, nd);
628 * nfs readlink service
631 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
632 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
635 mbuf_t mp = NULL, mpend = NULL;
639 if (nd->nd_repstat) {
640 nfsrv_postopattr(nd, getret, &nva);
643 if (vnode_vtype(vp) != VLNK) {
644 if (nd->nd_flag & ND_NFSV2)
645 nd->nd_repstat = ENXIO;
647 nd->nd_repstat = EINVAL;
650 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
652 if (nd->nd_flag & ND_NFSV3)
653 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
655 if (nd->nd_flag & ND_NFSV3)
656 nfsrv_postopattr(nd, getret, &nva);
659 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
660 *tl = txdr_unsigned(len);
661 mbuf_setnext(nd->nd_mb, mp);
663 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
674 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
675 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
678 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
682 struct nfsstate st, *stp = &st;
683 struct nfslock lo, *lop = &lo;
684 nfsv4stateid_t stateid;
687 if (nd->nd_repstat) {
688 nfsrv_postopattr(nd, getret, &nva);
691 if (nd->nd_flag & ND_NFSV2) {
692 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
693 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
694 reqlen = fxdr_unsigned(int, *tl);
695 } else if (nd->nd_flag & ND_NFSV3) {
696 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
697 off = fxdr_hyper(tl);
699 reqlen = fxdr_unsigned(int, *tl);
701 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
702 reqlen = fxdr_unsigned(int, *(tl + 6));
704 if (reqlen > NFS_SRVMAXDATA(nd)) {
705 reqlen = NFS_SRVMAXDATA(nd);
706 } else if (reqlen < 0) {
711 if (nd->nd_flag & ND_NFSV4) {
712 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
713 lop->lo_flags = NFSLCK_READ;
714 stp->ls_ownerlen = 0;
716 stp->ls_uid = nd->nd_cred->cr_uid;
717 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
718 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
719 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
720 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
721 if ((nd->nd_flag & ND_NFSV41) != 0)
722 clientid.qval = nd->nd_clientid.qval;
723 else if (nd->nd_clientid.qval != clientid.qval)
724 printf("EEK1 multiple clids\n");
726 if ((nd->nd_flag & ND_NFSV41) != 0)
727 printf("EEK! no clientid from session\n");
728 nd->nd_flag |= ND_IMPLIEDCLID;
729 nd->nd_clientid.qval = clientid.qval;
731 stp->ls_stateid.other[2] = *tl++;
733 * Don't allow the client to use a special stateid for a DS op.
735 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
736 ((stp->ls_stateid.other[0] == 0x0 &&
737 stp->ls_stateid.other[1] == 0x0 &&
738 stp->ls_stateid.other[2] == 0x0) ||
739 (stp->ls_stateid.other[0] == 0xffffffff &&
740 stp->ls_stateid.other[1] == 0xffffffff &&
741 stp->ls_stateid.other[2] == 0xffffffff) ||
742 stp->ls_stateid.seqid != 0))
743 nd->nd_repstat = NFSERR_BADSTATEID;
744 /* However, allow the proxy stateid. */
745 if (stp->ls_stateid.seqid == 0xffffffff &&
746 stp->ls_stateid.other[0] == 0x55555555 &&
747 stp->ls_stateid.other[1] == 0x55555555 &&
748 stp->ls_stateid.other[2] == 0x55555555)
750 off = fxdr_hyper(tl);
753 lop->lo_end = off + reqlen;
755 * Paranoia, just in case it wraps around.
757 if (lop->lo_end < off)
758 lop->lo_end = NFS64BITSSET;
760 if (vnode_vtype(vp) != VREG) {
761 if (nd->nd_flag & ND_NFSV3)
762 nd->nd_repstat = EINVAL;
764 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
767 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
769 nd->nd_repstat = getret;
770 if (!nd->nd_repstat &&
771 (nva.na_uid != nd->nd_cred->cr_uid ||
772 NFSVNO_EXSTRICTACCESS(exp))) {
773 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
775 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
777 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
778 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
779 NFSACCCHK_VPISLOCKED, NULL);
782 * DS reads are marked by ND_DSSERVER or use the proxy special
785 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
786 ND_NFSV4 && gotproxystateid == 0)
787 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
788 &stateid, exp, nd, p);
789 if (nd->nd_repstat) {
791 if (nd->nd_flag & ND_NFSV3)
792 nfsrv_postopattr(nd, getret, &nva);
795 if (off >= nva.na_size) {
798 } else if (reqlen == 0)
800 else if ((off + reqlen) >= nva.na_size) {
801 cnt = nva.na_size - off;
807 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
809 if (!(nd->nd_flag & ND_NFSV4)) {
810 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
812 nd->nd_repstat = getret;
814 if (nd->nd_repstat) {
818 if (nd->nd_flag & ND_NFSV3)
819 nfsrv_postopattr(nd, getret, &nva);
824 if (nd->nd_flag & ND_NFSV2) {
825 nfsrv_fillattr(nd, &nva);
826 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
828 if (nd->nd_flag & ND_NFSV3) {
829 nfsrv_postopattr(nd, getret, &nva);
830 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
831 *tl++ = txdr_unsigned(cnt);
833 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
837 *tl++ = newnfs_false;
839 *tl = txdr_unsigned(cnt);
841 mbuf_setnext(nd->nd_mb, m3);
843 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
851 NFSEXITCODE2(error, nd);
859 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
860 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
865 struct nfsvattr nva, forat;
866 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
867 int gotproxystateid, stable = NFSWRITE_FILESYNC;
869 struct nfsstate st, *stp = &st;
870 struct nfslock lo, *lop = &lo;
871 nfsv4stateid_t stateid;
873 nfsattrbit_t attrbits;
875 if (nd->nd_repstat) {
876 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
880 if (nd->nd_flag & ND_NFSV2) {
881 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
882 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
884 retlen = len = fxdr_unsigned(int32_t, *tl);
885 } else if (nd->nd_flag & ND_NFSV3) {
886 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
887 off = fxdr_hyper(tl);
889 stable = fxdr_unsigned(int, *tl++);
890 retlen = len = fxdr_unsigned(int32_t, *tl);
892 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
893 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
894 lop->lo_flags = NFSLCK_WRITE;
895 stp->ls_ownerlen = 0;
897 stp->ls_uid = nd->nd_cred->cr_uid;
898 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
899 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
900 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
901 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
902 if ((nd->nd_flag & ND_NFSV41) != 0)
903 clientid.qval = nd->nd_clientid.qval;
904 else if (nd->nd_clientid.qval != clientid.qval)
905 printf("EEK2 multiple clids\n");
907 if ((nd->nd_flag & ND_NFSV41) != 0)
908 printf("EEK! no clientid from session\n");
909 nd->nd_flag |= ND_IMPLIEDCLID;
910 nd->nd_clientid.qval = clientid.qval;
912 stp->ls_stateid.other[2] = *tl++;
914 * Don't allow the client to use a special stateid for a DS op.
916 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
917 ((stp->ls_stateid.other[0] == 0x0 &&
918 stp->ls_stateid.other[1] == 0x0 &&
919 stp->ls_stateid.other[2] == 0x0) ||
920 (stp->ls_stateid.other[0] == 0xffffffff &&
921 stp->ls_stateid.other[1] == 0xffffffff &&
922 stp->ls_stateid.other[2] == 0xffffffff) ||
923 stp->ls_stateid.seqid != 0))
924 nd->nd_repstat = NFSERR_BADSTATEID;
925 /* However, allow the proxy stateid. */
926 if (stp->ls_stateid.seqid == 0xffffffff &&
927 stp->ls_stateid.other[0] == 0x55555555 &&
928 stp->ls_stateid.other[1] == 0x55555555 &&
929 stp->ls_stateid.other[2] == 0x55555555)
931 off = fxdr_hyper(tl);
934 stable = fxdr_unsigned(int, *tl++);
935 retlen = len = fxdr_unsigned(int32_t, *tl);
936 lop->lo_end = off + len;
938 * Paranoia, just in case it wraps around, which shouldn't
939 * ever happen anyhow.
941 if (lop->lo_end < lop->lo_first)
942 lop->lo_end = NFS64BITSSET;
946 * Loop through the mbuf chain, counting how many mbufs are a
947 * part of this write operation, so the iovec size is known.
951 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
967 if (retlen > NFS_SRVMAXIO || retlen < 0)
968 nd->nd_repstat = EIO;
969 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
970 if (nd->nd_flag & ND_NFSV3)
971 nd->nd_repstat = EINVAL;
973 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
976 NFSZERO_ATTRBIT(&attrbits);
977 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
978 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
980 nd->nd_repstat = forat_ret;
981 if (!nd->nd_repstat &&
982 (forat.na_uid != nd->nd_cred->cr_uid ||
983 NFSVNO_EXSTRICTACCESS(exp)))
984 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
986 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
988 * DS reads are marked by ND_DSSERVER or use the proxy special
991 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
992 ND_NFSV4 && gotproxystateid == 0)
993 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
994 &stateid, exp, nd, p);
995 if (nd->nd_repstat) {
997 if (nd->nd_flag & ND_NFSV3)
998 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1003 * For NFS Version 2, it is not obvious what a write of zero length
1004 * should do, but I might as well be consistent with Version 3,
1005 * which is to return ok so long as there are no permission problems.
1008 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, &stable,
1009 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1010 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1014 if (nd->nd_flag & ND_NFSV4)
1017 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1019 if (!nd->nd_repstat)
1020 nd->nd_repstat = aftat_ret;
1021 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1022 if (nd->nd_flag & ND_NFSV3)
1023 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1026 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1027 *tl++ = txdr_unsigned(retlen);
1029 * If nfs_async is set, then pretend the write was FILESYNC.
1030 * Warning: Doing this violates RFC1813 and runs a risk
1031 * of data written by a client being lost when the server
1034 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1035 *tl++ = txdr_unsigned(stable);
1037 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1039 * Actually, there is no need to txdr these fields,
1040 * but it may make the values more human readable,
1041 * for debugging purposes.
1043 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1044 *tl = txdr_unsigned(nfsboottime.tv_usec);
1045 } else if (!nd->nd_repstat)
1046 nfsrv_fillattr(nd, &nva);
1049 NFSEXITCODE2(0, nd);
1053 NFSEXITCODE2(error, nd);
1058 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1059 * now does a truncate to 0 length via. setattr if it already exists
1060 * The core creation routine has been extracted out into nfsrv_creatsub(),
1061 * so it can also be used by nfsrv_open() for V4.
1064 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1065 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1067 struct nfsvattr nva, dirfor, diraft;
1068 struct nfsv2_sattr *sp;
1069 struct nameidata named;
1071 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1072 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1074 vnode_t vp = NULL, dirp = NULL;
1079 int32_t cverf[2], tverf[2] = { 0, 0 };
1081 if (nd->nd_repstat) {
1082 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1085 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1086 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1087 nfsvno_setpathbuf(&named, &bufp, &hashp);
1088 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1091 if (!nd->nd_repstat) {
1092 NFSVNO_ATTRINIT(&nva);
1093 if (nd->nd_flag & ND_NFSV2) {
1094 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1095 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1098 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1099 NFSVNO_SETATTRVAL(&nva, mode,
1100 nfstov_mode(sp->sa_mode));
1101 switch (nva.na_type) {
1103 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1105 NFSVNO_SETATTRVAL(&nva, size,
1111 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1117 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1118 how = fxdr_unsigned(int, *tl);
1120 case NFSCREATE_GUARDED:
1121 case NFSCREATE_UNCHECKED:
1122 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1126 case NFSCREATE_EXCLUSIVE:
1127 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1133 NFSVNO_SETATTRVAL(&nva, type, VREG);
1136 if (nd->nd_repstat) {
1137 nfsvno_relpathbuf(&named);
1138 if (nd->nd_flag & ND_NFSV3) {
1139 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1141 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1148 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1150 if (nd->nd_flag & ND_NFSV2) {
1154 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1158 if (nd->nd_repstat) {
1159 if (nd->nd_flag & ND_NFSV3)
1160 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1167 if (!(nd->nd_flag & ND_NFSV2)) {
1169 case NFSCREATE_GUARDED:
1171 nd->nd_repstat = EEXIST;
1173 case NFSCREATE_UNCHECKED:
1175 case NFSCREATE_EXCLUSIVE:
1176 if (named.ni_vp == NULL)
1177 NFSVNO_SETATTRVAL(&nva, mode, 0);
1183 * Iff doesn't exist, create it
1184 * otherwise just truncate to 0 length
1185 * should I set the mode too ?
1187 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1188 &exclusive_flag, cverf, rdev, p, exp);
1190 if (!nd->nd_repstat) {
1191 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1192 if (!nd->nd_repstat)
1193 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1196 if (!nd->nd_repstat) {
1197 tverf[0] = nva.na_atime.tv_sec;
1198 tverf[1] = nva.na_atime.tv_nsec;
1201 if (nd->nd_flag & ND_NFSV2) {
1202 if (!nd->nd_repstat) {
1203 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1204 nfsrv_fillattr(nd, &nva);
1207 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1208 || cverf[1] != tverf[1]))
1209 nd->nd_repstat = EEXIST;
1210 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1212 if (!nd->nd_repstat) {
1213 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1214 nfsrv_postopattr(nd, 0, &nva);
1216 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1220 NFSEXITCODE2(0, nd);
1224 nfsvno_relpathbuf(&named);
1225 NFSEXITCODE2(error, nd);
1230 * nfs v3 mknod service (and v4 create)
1233 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1234 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1235 struct nfsexstuff *exp)
1237 struct nfsvattr nva, dirfor, diraft;
1239 struct nameidata named;
1240 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1241 u_int32_t major, minor;
1242 enum vtype vtyp = VNON;
1243 nfstype nfs4type = NFNON;
1244 vnode_t vp, dirp = NULL;
1245 nfsattrbit_t attrbits;
1246 char *bufp = NULL, *pathcp = NULL;
1247 u_long *hashp, cnflags;
1248 NFSACL_T *aclp = NULL;
1250 NFSVNO_ATTRINIT(&nva);
1251 cnflags = (LOCKPARENT | SAVESTART);
1252 if (nd->nd_repstat) {
1253 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1256 #ifdef NFS4_ACL_EXTATTR_NAME
1257 aclp = acl_alloc(M_WAITOK);
1262 * For V4, the creation stuff is here, Yuck!
1264 if (nd->nd_flag & ND_NFSV4) {
1265 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1266 vtyp = nfsv34tov_type(*tl);
1267 nfs4type = fxdr_unsigned(nfstype, *tl);
1270 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1277 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1278 major = fxdr_unsigned(u_int32_t, *tl++);
1279 minor = fxdr_unsigned(u_int32_t, *tl);
1280 nva.na_rdev = NFSMAKEDEV(major, minor);
1286 cnflags = (LOCKPARENT | SAVENAME);
1289 nd->nd_repstat = NFSERR_BADTYPE;
1291 #ifdef NFS4_ACL_EXTATTR_NAME
1297 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1298 nfsvno_setpathbuf(&named, &bufp, &hashp);
1299 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1302 if (!nd->nd_repstat) {
1303 if (nd->nd_flag & ND_NFSV3) {
1304 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1305 vtyp = nfsv34tov_type(*tl);
1307 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1311 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1312 (vtyp == VCHR || vtyp == VBLK)) {
1313 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1314 major = fxdr_unsigned(u_int32_t, *tl++);
1315 minor = fxdr_unsigned(u_int32_t, *tl);
1316 nva.na_rdev = NFSMAKEDEV(major, minor);
1320 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1321 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1322 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1323 dirfor.na_gid == nva.na_gid)
1324 NFSVNO_UNSET(&nva, gid);
1325 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1327 if (nd->nd_repstat) {
1329 #ifdef NFS4_ACL_EXTATTR_NAME
1332 nfsvno_relpathbuf(&named);
1334 free(pathcp, M_TEMP);
1335 if (nd->nd_flag & ND_NFSV3)
1336 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1342 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1343 * in va_mode, so we'll have to set a default here.
1345 if (NFSVNO_NOTSETMODE(&nva)) {
1353 named.ni_cnd.cn_flags |= WILLBEDIR;
1354 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1355 if (nd->nd_repstat) {
1357 if (nd->nd_flag & ND_NFSV3)
1358 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1362 #ifdef NFS4_ACL_EXTATTR_NAME
1365 if (nd->nd_flag & ND_NFSV3)
1366 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1371 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1373 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1375 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1376 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1378 #ifdef NFS4_ACL_EXTATTR_NAME
1382 } else if (vtyp == VLNK) {
1383 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1384 &dirfor, &diraft, &diraft_ret, &attrbits,
1385 aclp, p, exp, pathcp, pathlen);
1386 #ifdef NFS4_ACL_EXTATTR_NAME
1389 free(pathcp, M_TEMP);
1394 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1395 if (!nd->nd_repstat) {
1397 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1398 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1399 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1400 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1402 if (vpp != NULL && nd->nd_repstat == 0) {
1403 NFSVOPUNLOCK(vp, 0);
1409 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1411 if (!nd->nd_repstat) {
1412 if (nd->nd_flag & ND_NFSV3) {
1413 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1414 nfsrv_postopattr(nd, 0, &nva);
1416 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1417 *tl++ = newnfs_false;
1418 txdr_hyper(dirfor.na_filerev, tl);
1420 txdr_hyper(diraft.na_filerev, tl);
1421 (void) nfsrv_putattrbit(nd, &attrbits);
1424 if (nd->nd_flag & ND_NFSV3)
1425 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1426 #ifdef NFS4_ACL_EXTATTR_NAME
1431 NFSEXITCODE2(0, nd);
1435 #ifdef NFS4_ACL_EXTATTR_NAME
1439 nfsvno_relpathbuf(&named);
1441 free(pathcp, M_TEMP);
1443 NFSEXITCODE2(error, nd);
1448 * nfs remove service
1451 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1452 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1454 struct nameidata named;
1456 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1457 vnode_t dirp = NULL;
1458 struct nfsvattr dirfor, diraft;
1462 if (nd->nd_repstat) {
1463 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1466 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1467 LOCKPARENT | LOCKLEAF);
1468 nfsvno_setpathbuf(&named, &bufp, &hashp);
1469 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1472 nfsvno_relpathbuf(&named);
1475 if (!nd->nd_repstat) {
1476 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1479 nfsvno_relpathbuf(&named);
1482 if (!(nd->nd_flag & ND_NFSV2)) {
1483 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1490 if (!nd->nd_repstat) {
1491 if (nd->nd_flag & ND_NFSV4) {
1492 if (vnode_vtype(named.ni_vp) == VDIR)
1493 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1494 nd->nd_cred, p, exp);
1496 nd->nd_repstat = nfsvno_removesub(&named, 1,
1497 nd->nd_cred, p, exp);
1498 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1499 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1500 nd->nd_cred, p, exp);
1502 nd->nd_repstat = nfsvno_removesub(&named, 0,
1503 nd->nd_cred, p, exp);
1506 if (!(nd->nd_flag & ND_NFSV2)) {
1508 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1512 if (nd->nd_flag & ND_NFSV3) {
1513 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1515 } else if (!nd->nd_repstat) {
1516 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1517 *tl++ = newnfs_false;
1518 txdr_hyper(dirfor.na_filerev, tl);
1520 txdr_hyper(diraft.na_filerev, tl);
1525 NFSEXITCODE2(error, nd);
1530 * nfs rename service
1533 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1534 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1535 struct nfsexstuff *toexp)
1538 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1539 int tdirfor_ret = 1, tdiraft_ret = 1;
1540 struct nameidata fromnd, tond;
1541 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1542 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1543 struct nfsexstuff tnes;
1545 char *bufp, *tbufp = NULL;
1549 if (nd->nd_repstat) {
1550 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1551 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1554 if (!(nd->nd_flag & ND_NFSV2))
1555 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1556 tond.ni_cnd.cn_nameiop = 0;
1557 tond.ni_startdir = NULL;
1558 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1559 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1560 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1565 nfsvno_relpathbuf(&fromnd);
1569 * Unlock dp in this code section, so it is unlocked before
1570 * tdp gets locked. This avoids a potential LOR if tdp is the
1571 * parent directory of dp.
1573 if (nd->nd_flag & ND_NFSV4) {
1577 NFSVOPUNLOCK(dp, 0);
1578 /* Might lock tdp. */
1579 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1582 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1584 NFSVOPUNLOCK(dp, 0);
1587 tfh.nfsrvfh_len = 0;
1588 error = nfsrv_mtofh(nd, &tfh);
1590 error = nfsvno_getfh(dp, &fh, p);
1593 /* todp is always NULL except NFSv4 */
1594 nfsvno_relpathbuf(&fromnd);
1598 /* If this is the same file handle, just VREF() the vnode. */
1599 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1600 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1604 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1606 NFSVOPUNLOCK(dp, 0);
1608 NFSVOPUNLOCK(dp, 0);
1609 nd->nd_cred->cr_uid = nd->nd_saveduid;
1610 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1611 0, p); /* Locks tdp. */
1613 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1615 NFSVOPUNLOCK(tdp, 0);
1619 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1620 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1621 if (!nd->nd_repstat) {
1622 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1627 nfsvno_relpathbuf(&fromnd);
1628 nfsvno_relpathbuf(&tond);
1632 if (nd->nd_repstat) {
1633 if (nd->nd_flag & ND_NFSV3) {
1634 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1636 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1642 nfsvno_relpathbuf(&fromnd);
1643 nfsvno_relpathbuf(&tond);
1648 * Done parsing, now down to business.
1650 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1651 if (nd->nd_repstat) {
1652 if (nd->nd_flag & ND_NFSV3) {
1653 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1655 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1662 nfsvno_relpathbuf(&tond);
1665 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1666 tond.ni_cnd.cn_flags |= WILLBEDIR;
1667 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1668 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1669 nd->nd_flag, nd->nd_cred, p);
1671 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1673 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1678 if (nd->nd_flag & ND_NFSV3) {
1679 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1680 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1681 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1682 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1683 *tl++ = newnfs_false;
1684 txdr_hyper(fdirfor.na_filerev, tl);
1686 txdr_hyper(fdiraft.na_filerev, tl);
1688 *tl++ = newnfs_false;
1689 txdr_hyper(tdirfor.na_filerev, tl);
1691 txdr_hyper(tdiraft.na_filerev, tl);
1695 NFSEXITCODE2(error, nd);
1703 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1704 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1705 struct nfsexstuff *toexp)
1707 struct nameidata named;
1709 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1710 vnode_t dirp = NULL, dp = NULL;
1711 struct nfsvattr dirfor, diraft, at;
1712 struct nfsexstuff tnes;
1717 if (nd->nd_repstat) {
1718 nfsrv_postopattr(nd, getret, &at);
1719 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1722 NFSVOPUNLOCK(vp, 0);
1723 if (vnode_vtype(vp) == VDIR) {
1724 if (nd->nd_flag & ND_NFSV4)
1725 nd->nd_repstat = NFSERR_ISDIR;
1727 nd->nd_repstat = NFSERR_INVAL;
1731 if (!nd->nd_repstat) {
1732 if (nd->nd_flag & ND_NFSV4) {
1736 error = nfsrv_mtofh(nd, &dfh);
1739 /* tovp is always NULL unless NFSv4 */
1742 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1745 NFSVOPUNLOCK(dp, 0);
1748 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1749 LOCKPARENT | SAVENAME | NOCACHE);
1750 if (!nd->nd_repstat) {
1751 nfsvno_setpathbuf(&named, &bufp, &hashp);
1752 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1757 nfsvno_relpathbuf(&named);
1760 if (!nd->nd_repstat) {
1761 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1766 nfsvno_relpathbuf(&named);
1770 if (nd->nd_flag & ND_NFSV2) {
1774 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1778 if (!nd->nd_repstat)
1779 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1780 if (nd->nd_flag & ND_NFSV3)
1781 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1783 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1787 if (nd->nd_flag & ND_NFSV3) {
1788 nfsrv_postopattr(nd, getret, &at);
1789 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1790 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1791 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1792 *tl++ = newnfs_false;
1793 txdr_hyper(dirfor.na_filerev, tl);
1795 txdr_hyper(diraft.na_filerev, tl);
1799 NFSEXITCODE2(error, nd);
1804 * nfs symbolic link service
1807 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1808 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1809 struct nfsexstuff *exp)
1811 struct nfsvattr nva, dirfor, diraft;
1812 struct nameidata named;
1813 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1814 vnode_t dirp = NULL;
1815 char *bufp, *pathcp = NULL;
1818 if (nd->nd_repstat) {
1819 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1824 NFSVNO_ATTRINIT(&nva);
1825 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1826 LOCKPARENT | SAVESTART | NOCACHE);
1827 nfsvno_setpathbuf(&named, &bufp, &hashp);
1828 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1829 if (!error && !nd->nd_repstat)
1830 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1833 nfsvno_relpathbuf(&named);
1836 if (!nd->nd_repstat) {
1837 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1840 nfsvno_relpathbuf(&named);
1842 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1848 * And call nfsrvd_symlinksub() to do the common code. It will
1849 * return EBADRPC upon a parsing error, 0 otherwise.
1851 if (!nd->nd_repstat) {
1853 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1855 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1856 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1858 } else if (dirp != NULL) {
1859 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1863 free(pathcp, M_TEMP);
1865 if (nd->nd_flag & ND_NFSV3) {
1866 if (!nd->nd_repstat) {
1867 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1868 nfsrv_postopattr(nd, 0, &nva);
1870 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1874 NFSEXITCODE2(error, nd);
1879 * Common code for creating a symbolic link.
1882 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1883 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1884 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1885 int *diraft_retp, nfsattrbit_t *attrbitp,
1886 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1891 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1892 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1893 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1894 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1895 if (nd->nd_flag & ND_NFSV3) {
1896 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1897 if (!nd->nd_repstat)
1898 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1899 nvap, nd, p, 1, NULL);
1901 if (vpp != NULL && nd->nd_repstat == 0) {
1902 NFSVOPUNLOCK(ndp->ni_vp, 0);
1908 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1911 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1912 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1913 *tl++ = newnfs_false;
1914 txdr_hyper(dirforp->na_filerev, tl);
1916 txdr_hyper(diraftp->na_filerev, tl);
1917 (void) nfsrv_putattrbit(nd, attrbitp);
1920 NFSEXITCODE2(0, nd);
1927 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1928 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1929 struct nfsexstuff *exp)
1931 struct nfsvattr nva, dirfor, diraft;
1932 struct nameidata named;
1934 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1935 vnode_t dirp = NULL;
1939 if (nd->nd_repstat) {
1940 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1943 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1944 LOCKPARENT | SAVENAME | NOCACHE);
1945 nfsvno_setpathbuf(&named, &bufp, &hashp);
1946 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1949 if (!nd->nd_repstat) {
1950 NFSVNO_ATTRINIT(&nva);
1951 if (nd->nd_flag & ND_NFSV3) {
1952 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1956 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1957 nva.na_mode = nfstov_mode(*tl++);
1960 if (!nd->nd_repstat) {
1961 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1964 nfsvno_relpathbuf(&named);
1966 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1970 if (nd->nd_repstat) {
1972 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1976 if (nd->nd_flag & ND_NFSV3)
1977 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1982 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1985 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1987 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1988 &diraft_ret, NULL, NULL, p, exp);
1990 if (nd->nd_flag & ND_NFSV3) {
1991 if (!nd->nd_repstat) {
1992 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1993 nfsrv_postopattr(nd, 0, &nva);
1995 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1996 } else if (!nd->nd_repstat) {
1997 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1998 nfsrv_fillattr(nd, &nva);
2002 NFSEXITCODE2(0, nd);
2006 nfsvno_relpathbuf(&named);
2007 NFSEXITCODE2(error, nd);
2012 * Code common to mkdir for V2,3 and 4.
2015 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2016 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2017 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2018 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2019 NFSPROC_T *p, struct nfsexstuff *exp)
2024 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2025 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2026 nd->nd_cred, p, exp);
2027 if (!nd->nd_repstat) {
2029 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2030 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2031 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2032 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2034 if (vpp && !nd->nd_repstat) {
2035 NFSVOPUNLOCK(vp, 0);
2042 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2045 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2046 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2047 *tl++ = newnfs_false;
2048 txdr_hyper(dirforp->na_filerev, tl);
2050 txdr_hyper(diraftp->na_filerev, tl);
2051 (void) nfsrv_putattrbit(nd, attrbitp);
2054 NFSEXITCODE2(0, nd);
2058 * nfs commit service
2061 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2062 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2064 struct nfsvattr bfor, aft;
2066 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2069 if (nd->nd_repstat) {
2070 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2074 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2075 if (vp->v_type != VREG) {
2076 if (nd->nd_flag & ND_NFSV3)
2077 error = NFSERR_NOTSUPP;
2079 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2082 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2085 * XXX At this time VOP_FSYNC() does not accept offset and byte
2086 * count parameters, so these arguments are useless (someday maybe).
2088 off = fxdr_hyper(tl);
2090 cnt = fxdr_unsigned(int, *tl);
2091 if (nd->nd_flag & ND_NFSV3)
2092 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2093 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2094 if (nd->nd_flag & ND_NFSV3) {
2095 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2096 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2099 if (!nd->nd_repstat) {
2100 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2101 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2102 *tl = txdr_unsigned(nfsboottime.tv_usec);
2106 NFSEXITCODE2(0, nd);
2110 NFSEXITCODE2(error, nd);
2115 * nfs statfs service
2118 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2119 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2128 if (nd->nd_repstat) {
2129 nfsrv_postopattr(nd, getret, &at);
2132 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2133 nd->nd_repstat = nfsvno_statfs(vp, sf);
2134 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2136 if (nd->nd_flag & ND_NFSV3)
2137 nfsrv_postopattr(nd, getret, &at);
2140 if (nd->nd_flag & ND_NFSV2) {
2141 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2142 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2143 *tl++ = txdr_unsigned(sf->f_bsize);
2144 *tl++ = txdr_unsigned(sf->f_blocks);
2145 *tl++ = txdr_unsigned(sf->f_bfree);
2146 *tl = txdr_unsigned(sf->f_bavail);
2148 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2149 tval = (u_quad_t)sf->f_blocks;
2150 tval *= (u_quad_t)sf->f_bsize;
2151 txdr_hyper(tval, tl); tl += 2;
2152 tval = (u_quad_t)sf->f_bfree;
2153 tval *= (u_quad_t)sf->f_bsize;
2154 txdr_hyper(tval, tl); tl += 2;
2155 tval = (u_quad_t)sf->f_bavail;
2156 tval *= (u_quad_t)sf->f_bsize;
2157 txdr_hyper(tval, tl); tl += 2;
2158 tval = (u_quad_t)sf->f_files;
2159 txdr_hyper(tval, tl); tl += 2;
2160 tval = (u_quad_t)sf->f_ffree;
2161 txdr_hyper(tval, tl); tl += 2;
2162 tval = (u_quad_t)sf->f_ffree;
2163 txdr_hyper(tval, tl); tl += 2;
2169 NFSEXITCODE2(0, nd);
2174 * nfs fsinfo service
2177 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2178 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2181 struct nfsfsinfo fs;
2185 if (nd->nd_repstat) {
2186 nfsrv_postopattr(nd, getret, &at);
2189 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2190 nfsvno_getfs(&fs, isdgram);
2192 nfsrv_postopattr(nd, getret, &at);
2193 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2194 *tl++ = txdr_unsigned(fs.fs_rtmax);
2195 *tl++ = txdr_unsigned(fs.fs_rtpref);
2196 *tl++ = txdr_unsigned(fs.fs_rtmult);
2197 *tl++ = txdr_unsigned(fs.fs_wtmax);
2198 *tl++ = txdr_unsigned(fs.fs_wtpref);
2199 *tl++ = txdr_unsigned(fs.fs_wtmult);
2200 *tl++ = txdr_unsigned(fs.fs_dtpref);
2201 txdr_hyper(fs.fs_maxfilesize, tl);
2203 txdr_nfsv3time(&fs.fs_timedelta, tl);
2205 *tl = txdr_unsigned(fs.fs_properties);
2208 NFSEXITCODE2(0, nd);
2213 * nfs pathconf service
2216 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2217 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2219 struct nfsv3_pathconf *pc;
2221 long linkmax, namemax, chownres, notrunc;
2224 if (nd->nd_repstat) {
2225 nfsrv_postopattr(nd, getret, &at);
2228 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2230 if (!nd->nd_repstat)
2231 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2233 if (!nd->nd_repstat)
2234 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2235 &chownres, nd->nd_cred, p);
2236 if (!nd->nd_repstat)
2237 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2239 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2241 nfsrv_postopattr(nd, getret, &at);
2242 if (!nd->nd_repstat) {
2243 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2244 pc->pc_linkmax = txdr_unsigned(linkmax);
2245 pc->pc_namemax = txdr_unsigned(namemax);
2246 pc->pc_notrunc = txdr_unsigned(notrunc);
2247 pc->pc_chownrestricted = txdr_unsigned(chownres);
2250 * These should probably be supported by VOP_PATHCONF(), but
2251 * until msdosfs is exportable (why would you want to?), the
2252 * Unix defaults should be ok.
2254 pc->pc_caseinsensitive = newnfs_false;
2255 pc->pc_casepreserving = newnfs_true;
2259 NFSEXITCODE2(0, nd);
2264 * nfsv4 lock service
2267 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2268 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2272 struct nfsstate *stp = NULL;
2273 struct nfslock *lop;
2274 struct nfslockconflict cf;
2276 u_short flags = NFSLCK_LOCK, lflags;
2277 u_int64_t offset, len;
2278 nfsv4stateid_t stateid;
2281 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2282 i = fxdr_unsigned(int, *tl++);
2284 case NFSV4LOCKT_READW:
2285 flags |= NFSLCK_BLOCKING;
2286 case NFSV4LOCKT_READ:
2287 lflags = NFSLCK_READ;
2289 case NFSV4LOCKT_WRITEW:
2290 flags |= NFSLCK_BLOCKING;
2291 case NFSV4LOCKT_WRITE:
2292 lflags = NFSLCK_WRITE;
2295 nd->nd_repstat = NFSERR_BADXDR;
2298 if (*tl++ == newnfs_true)
2299 flags |= NFSLCK_RECLAIM;
2300 offset = fxdr_hyper(tl);
2302 len = fxdr_hyper(tl);
2304 if (*tl == newnfs_true)
2305 flags |= NFSLCK_OPENTOLOCK;
2306 if (flags & NFSLCK_OPENTOLOCK) {
2307 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2308 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2309 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2310 nd->nd_repstat = NFSERR_BADXDR;
2313 stp = malloc(sizeof (struct nfsstate) + i,
2314 M_NFSDSTATE, M_WAITOK);
2315 stp->ls_ownerlen = i;
2316 stp->ls_op = nd->nd_rp;
2317 stp->ls_seq = fxdr_unsigned(int, *tl++);
2318 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2319 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2321 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2324 * For the special stateid of other all 0s and seqid == 1, set
2325 * the stateid to the current stateid, if it is set.
2327 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2328 stp->ls_stateid.seqid == 1 &&
2329 stp->ls_stateid.other[0] == 0 &&
2330 stp->ls_stateid.other[1] == 0 &&
2331 stp->ls_stateid.other[2] == 0) {
2332 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2333 stp->ls_stateid = nd->nd_curstateid;
2334 stp->ls_stateid.seqid = 0;
2336 nd->nd_repstat = NFSERR_BADSTATEID;
2341 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2342 clientid.lval[0] = *tl++;
2343 clientid.lval[1] = *tl++;
2344 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2345 if ((nd->nd_flag & ND_NFSV41) != 0)
2346 clientid.qval = nd->nd_clientid.qval;
2347 else if (nd->nd_clientid.qval != clientid.qval)
2348 printf("EEK3 multiple clids\n");
2350 if ((nd->nd_flag & ND_NFSV41) != 0)
2351 printf("EEK! no clientid from session\n");
2352 nd->nd_flag |= ND_IMPLIEDCLID;
2353 nd->nd_clientid.qval = clientid.qval;
2355 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2359 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2360 stp = malloc(sizeof (struct nfsstate),
2361 M_NFSDSTATE, M_WAITOK);
2362 stp->ls_ownerlen = 0;
2363 stp->ls_op = nd->nd_rp;
2364 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2365 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2367 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2370 * For the special stateid of other all 0s and seqid == 1, set
2371 * the stateid to the current stateid, if it is set.
2373 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2374 stp->ls_stateid.seqid == 1 &&
2375 stp->ls_stateid.other[0] == 0 &&
2376 stp->ls_stateid.other[1] == 0 &&
2377 stp->ls_stateid.other[2] == 0) {
2378 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2379 stp->ls_stateid = nd->nd_curstateid;
2380 stp->ls_stateid.seqid = 0;
2382 nd->nd_repstat = NFSERR_BADSTATEID;
2387 stp->ls_seq = fxdr_unsigned(int, *tl);
2388 clientid.lval[0] = stp->ls_stateid.other[0];
2389 clientid.lval[1] = stp->ls_stateid.other[1];
2390 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2391 if ((nd->nd_flag & ND_NFSV41) != 0)
2392 clientid.qval = nd->nd_clientid.qval;
2393 else if (nd->nd_clientid.qval != clientid.qval)
2394 printf("EEK4 multiple clids\n");
2396 if ((nd->nd_flag & ND_NFSV41) != 0)
2397 printf("EEK! no clientid from session\n");
2398 nd->nd_flag |= ND_IMPLIEDCLID;
2399 nd->nd_clientid.qval = clientid.qval;
2402 lop = malloc(sizeof (struct nfslock),
2403 M_NFSDLOCK, M_WAITOK);
2404 lop->lo_first = offset;
2405 if (len == NFS64BITSSET) {
2406 lop->lo_end = NFS64BITSSET;
2408 lop->lo_end = offset + len;
2409 if (lop->lo_end <= lop->lo_first)
2410 nd->nd_repstat = NFSERR_INVAL;
2412 lop->lo_flags = lflags;
2413 stp->ls_flags = flags;
2414 stp->ls_uid = nd->nd_cred->cr_uid;
2417 * Do basic access checking.
2419 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2420 if (vnode_vtype(vp) == VDIR)
2421 nd->nd_repstat = NFSERR_ISDIR;
2423 nd->nd_repstat = NFSERR_INVAL;
2425 if (!nd->nd_repstat) {
2426 if (lflags & NFSLCK_WRITE) {
2427 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2428 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2429 NFSACCCHK_VPISLOCKED, NULL);
2431 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2432 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2433 NFSACCCHK_VPISLOCKED, NULL);
2435 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2436 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2437 NFSACCCHK_VPISLOCKED, NULL);
2442 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2443 * seqid# gets updated. nfsrv_lockctrl() will return the value
2444 * of nd_repstat, if it gets that far.
2446 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2447 &stateid, exp, nd, p);
2449 free(lop, M_NFSDLOCK);
2451 free(stp, M_NFSDSTATE);
2452 if (!nd->nd_repstat) {
2453 /* For NFSv4.1, set the Current StateID. */
2454 if ((nd->nd_flag & ND_NFSV41) != 0) {
2455 nd->nd_curstateid = stateid;
2456 nd->nd_flag |= ND_CURSTATEID;
2458 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2459 *tl++ = txdr_unsigned(stateid.seqid);
2460 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2461 } else if (nd->nd_repstat == NFSERR_DENIED) {
2462 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2463 txdr_hyper(cf.cl_first, tl);
2465 if (cf.cl_end == NFS64BITSSET)
2468 len = cf.cl_end - cf.cl_first;
2469 txdr_hyper(len, tl);
2471 if (cf.cl_flags == NFSLCK_WRITE)
2472 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2474 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2475 *tl++ = stateid.other[0];
2476 *tl = stateid.other[1];
2477 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2480 NFSEXITCODE2(0, nd);
2485 free(stp, M_NFSDSTATE);
2486 NFSEXITCODE2(error, nd);
2491 * nfsv4 lock test service
2494 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2495 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2499 struct nfsstate *stp = NULL;
2500 struct nfslock lo, *lop = &lo;
2501 struct nfslockconflict cf;
2503 nfsv4stateid_t stateid;
2507 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2508 i = fxdr_unsigned(int, *(tl + 7));
2509 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2510 nd->nd_repstat = NFSERR_BADXDR;
2513 stp = malloc(sizeof (struct nfsstate) + i,
2514 M_NFSDSTATE, M_WAITOK);
2515 stp->ls_ownerlen = i;
2517 stp->ls_flags = NFSLCK_TEST;
2518 stp->ls_uid = nd->nd_cred->cr_uid;
2519 i = fxdr_unsigned(int, *tl++);
2521 case NFSV4LOCKT_READW:
2522 stp->ls_flags |= NFSLCK_BLOCKING;
2523 case NFSV4LOCKT_READ:
2524 lo.lo_flags = NFSLCK_READ;
2526 case NFSV4LOCKT_WRITEW:
2527 stp->ls_flags |= NFSLCK_BLOCKING;
2528 case NFSV4LOCKT_WRITE:
2529 lo.lo_flags = NFSLCK_WRITE;
2532 nd->nd_repstat = NFSERR_BADXDR;
2535 lo.lo_first = fxdr_hyper(tl);
2537 len = fxdr_hyper(tl);
2538 if (len == NFS64BITSSET) {
2539 lo.lo_end = NFS64BITSSET;
2541 lo.lo_end = lo.lo_first + len;
2542 if (lo.lo_end <= lo.lo_first)
2543 nd->nd_repstat = NFSERR_INVAL;
2546 clientid.lval[0] = *tl++;
2547 clientid.lval[1] = *tl;
2548 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2549 if ((nd->nd_flag & ND_NFSV41) != 0)
2550 clientid.qval = nd->nd_clientid.qval;
2551 else if (nd->nd_clientid.qval != clientid.qval)
2552 printf("EEK5 multiple clids\n");
2554 if ((nd->nd_flag & ND_NFSV41) != 0)
2555 printf("EEK! no clientid from session\n");
2556 nd->nd_flag |= ND_IMPLIEDCLID;
2557 nd->nd_clientid.qval = clientid.qval;
2559 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2562 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2563 if (vnode_vtype(vp) == VDIR)
2564 nd->nd_repstat = NFSERR_ISDIR;
2566 nd->nd_repstat = NFSERR_INVAL;
2568 if (!nd->nd_repstat)
2569 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2570 &stateid, exp, nd, p);
2571 if (nd->nd_repstat) {
2572 if (nd->nd_repstat == NFSERR_DENIED) {
2573 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2574 txdr_hyper(cf.cl_first, tl);
2576 if (cf.cl_end == NFS64BITSSET)
2579 len = cf.cl_end - cf.cl_first;
2580 txdr_hyper(len, tl);
2582 if (cf.cl_flags == NFSLCK_WRITE)
2583 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2585 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2586 *tl++ = stp->ls_stateid.other[0];
2587 *tl = stp->ls_stateid.other[1];
2588 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2593 free(stp, M_NFSDSTATE);
2594 NFSEXITCODE2(0, nd);
2599 free(stp, M_NFSDSTATE);
2600 NFSEXITCODE2(error, nd);
2605 * nfsv4 unlock service
2608 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2609 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2613 struct nfsstate *stp;
2614 struct nfslock *lop;
2616 nfsv4stateid_t stateid;
2620 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2621 stp = malloc(sizeof (struct nfsstate),
2622 M_NFSDSTATE, M_WAITOK);
2623 lop = malloc(sizeof (struct nfslock),
2624 M_NFSDLOCK, M_WAITOK);
2625 stp->ls_flags = NFSLCK_UNLOCK;
2626 lop->lo_flags = NFSLCK_UNLOCK;
2627 stp->ls_op = nd->nd_rp;
2628 i = fxdr_unsigned(int, *tl++);
2630 case NFSV4LOCKT_READW:
2631 stp->ls_flags |= NFSLCK_BLOCKING;
2632 case NFSV4LOCKT_READ:
2634 case NFSV4LOCKT_WRITEW:
2635 stp->ls_flags |= NFSLCK_BLOCKING;
2636 case NFSV4LOCKT_WRITE:
2639 nd->nd_repstat = NFSERR_BADXDR;
2640 free(stp, M_NFSDSTATE);
2641 free(lop, M_NFSDLOCK);
2644 stp->ls_ownerlen = 0;
2645 stp->ls_uid = nd->nd_cred->cr_uid;
2646 stp->ls_seq = fxdr_unsigned(int, *tl++);
2647 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2648 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2650 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2653 * For the special stateid of other all 0s and seqid == 1, set the
2654 * stateid to the current stateid, if it is set.
2656 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2657 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2658 stp->ls_stateid.other[2] == 0) {
2659 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2660 stp->ls_stateid = nd->nd_curstateid;
2661 stp->ls_stateid.seqid = 0;
2663 nd->nd_repstat = NFSERR_BADSTATEID;
2668 lop->lo_first = fxdr_hyper(tl);
2670 len = fxdr_hyper(tl);
2671 if (len == NFS64BITSSET) {
2672 lop->lo_end = NFS64BITSSET;
2674 lop->lo_end = lop->lo_first + len;
2675 if (lop->lo_end <= lop->lo_first)
2676 nd->nd_repstat = NFSERR_INVAL;
2678 clientid.lval[0] = stp->ls_stateid.other[0];
2679 clientid.lval[1] = stp->ls_stateid.other[1];
2680 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2681 if ((nd->nd_flag & ND_NFSV41) != 0)
2682 clientid.qval = nd->nd_clientid.qval;
2683 else if (nd->nd_clientid.qval != clientid.qval)
2684 printf("EEK6 multiple clids\n");
2686 if ((nd->nd_flag & ND_NFSV41) != 0)
2687 printf("EEK! no clientid from session\n");
2688 nd->nd_flag |= ND_IMPLIEDCLID;
2689 nd->nd_clientid.qval = clientid.qval;
2691 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2692 if (vnode_vtype(vp) == VDIR)
2693 nd->nd_repstat = NFSERR_ISDIR;
2695 nd->nd_repstat = NFSERR_INVAL;
2698 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2699 * seqid# gets incremented. nfsrv_lockctrl() will return the
2700 * value of nd_repstat, if it gets that far.
2702 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2703 &stateid, exp, nd, p);
2705 free(stp, M_NFSDSTATE);
2707 free(lop, M_NFSDLOCK);
2708 if (!nd->nd_repstat) {
2709 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2710 *tl++ = txdr_unsigned(stateid.seqid);
2711 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2715 NFSEXITCODE2(error, nd);
2720 * nfsv4 open service
2723 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2724 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2725 struct nfsexstuff *exp)
2729 struct nfsstate *stp = NULL;
2730 int error = 0, create, claim, exclusive_flag = 0;
2731 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2732 int how = NFSCREATE_UNCHECKED;
2733 int32_t cverf[2], tverf[2] = { 0, 0 };
2734 vnode_t vp = NULL, dirp = NULL;
2735 struct nfsvattr nva, dirfor, diraft;
2736 struct nameidata named;
2737 nfsv4stateid_t stateid, delegstateid;
2738 nfsattrbit_t attrbits;
2742 NFSACL_T *aclp = NULL;
2744 #ifdef NFS4_ACL_EXTATTR_NAME
2745 aclp = acl_alloc(M_WAITOK);
2748 NFSZERO_ATTRBIT(&attrbits);
2749 named.ni_startdir = NULL;
2750 named.ni_cnd.cn_nameiop = 0;
2751 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2752 i = fxdr_unsigned(int, *(tl + 5));
2753 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2754 nd->nd_repstat = NFSERR_BADXDR;
2757 stp = malloc(sizeof (struct nfsstate) + i,
2758 M_NFSDSTATE, M_WAITOK);
2759 stp->ls_ownerlen = i;
2760 stp->ls_op = nd->nd_rp;
2761 stp->ls_flags = NFSLCK_OPEN;
2762 stp->ls_uid = nd->nd_cred->cr_uid;
2763 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2764 i = fxdr_unsigned(int, *tl++);
2766 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2767 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2769 /* For now, ignore these. */
2770 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2771 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2772 case NFSV4OPEN_WANTANYDELEG:
2773 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2775 i &= ~NFSV4OPEN_WANTDELEGMASK;
2777 case NFSV4OPEN_WANTREADDELEG:
2778 stp->ls_flags |= NFSLCK_WANTRDELEG;
2779 i &= ~NFSV4OPEN_WANTDELEGMASK;
2781 case NFSV4OPEN_WANTWRITEDELEG:
2782 stp->ls_flags |= NFSLCK_WANTWDELEG;
2783 i &= ~NFSV4OPEN_WANTDELEGMASK;
2785 case NFSV4OPEN_WANTNODELEG:
2786 stp->ls_flags |= NFSLCK_WANTNODELEG;
2787 i &= ~NFSV4OPEN_WANTDELEGMASK;
2789 case NFSV4OPEN_WANTCANCEL:
2790 printf("NFSv4: ignore Open WantCancel\n");
2791 i &= ~NFSV4OPEN_WANTDELEGMASK;
2794 /* nd_repstat will be set to NFSERR_INVAL below. */
2799 case NFSV4OPEN_ACCESSREAD:
2800 stp->ls_flags |= NFSLCK_READACCESS;
2802 case NFSV4OPEN_ACCESSWRITE:
2803 stp->ls_flags |= NFSLCK_WRITEACCESS;
2805 case NFSV4OPEN_ACCESSBOTH:
2806 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2809 nd->nd_repstat = NFSERR_INVAL;
2811 i = fxdr_unsigned(int, *tl++);
2813 case NFSV4OPEN_DENYNONE:
2815 case NFSV4OPEN_DENYREAD:
2816 stp->ls_flags |= NFSLCK_READDENY;
2818 case NFSV4OPEN_DENYWRITE:
2819 stp->ls_flags |= NFSLCK_WRITEDENY;
2821 case NFSV4OPEN_DENYBOTH:
2822 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2825 nd->nd_repstat = NFSERR_INVAL;
2827 clientid.lval[0] = *tl++;
2828 clientid.lval[1] = *tl;
2829 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2830 if ((nd->nd_flag & ND_NFSV41) != 0)
2831 clientid.qval = nd->nd_clientid.qval;
2832 else if (nd->nd_clientid.qval != clientid.qval)
2833 printf("EEK7 multiple clids\n");
2835 if ((nd->nd_flag & ND_NFSV41) != 0)
2836 printf("EEK! no clientid from session\n");
2837 nd->nd_flag |= ND_IMPLIEDCLID;
2838 nd->nd_clientid.qval = clientid.qval;
2840 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2843 NFSVNO_ATTRINIT(&nva);
2844 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2845 create = fxdr_unsigned(int, *tl);
2846 if (!nd->nd_repstat)
2847 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2848 if (create == NFSV4OPEN_CREATE) {
2851 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2852 how = fxdr_unsigned(int, *tl);
2854 case NFSCREATE_UNCHECKED:
2855 case NFSCREATE_GUARDED:
2856 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2860 * If the na_gid being set is the same as that of
2861 * the directory it is going in, clear it, since
2862 * that is what will be set by default. This allows
2863 * a user that isn't in that group to do the create.
2865 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2866 nva.na_gid == dirfor.na_gid)
2867 NFSVNO_UNSET(&nva, gid);
2868 if (!nd->nd_repstat)
2869 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2871 case NFSCREATE_EXCLUSIVE:
2872 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2876 case NFSCREATE_EXCLUSIVE41:
2877 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2880 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2883 if (NFSISSET_ATTRBIT(&attrbits,
2884 NFSATTRBIT_TIMEACCESSSET))
2885 nd->nd_repstat = NFSERR_INVAL;
2887 * If the na_gid being set is the same as that of
2888 * the directory it is going in, clear it, since
2889 * that is what will be set by default. This allows
2890 * a user that isn't in that group to do the create.
2892 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2893 nva.na_gid == dirfor.na_gid)
2894 NFSVNO_UNSET(&nva, gid);
2895 if (nd->nd_repstat == 0)
2896 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2899 nd->nd_repstat = NFSERR_BADXDR;
2902 } else if (create != NFSV4OPEN_NOCREATE) {
2903 nd->nd_repstat = NFSERR_BADXDR;
2908 * Now, handle the claim, which usually includes looking up a
2909 * name in the directory referenced by dp. The exception is
2910 * NFSV4OPEN_CLAIMPREVIOUS.
2912 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2913 claim = fxdr_unsigned(int, *tl);
2914 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2915 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2916 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2917 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2918 stp->ls_flags |= NFSLCK_DELEGCUR;
2919 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2920 stp->ls_flags |= NFSLCK_DELEGPREV;
2922 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2923 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2924 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2925 claim != NFSV4OPEN_CLAIMNULL)
2926 nd->nd_repstat = NFSERR_INVAL;
2927 if (nd->nd_repstat) {
2928 nd->nd_repstat = nfsrv_opencheck(clientid,
2929 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2932 if (create == NFSV4OPEN_CREATE)
2933 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2934 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2936 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2937 LOCKLEAF | SAVESTART);
2938 nfsvno_setpathbuf(&named, &bufp, &hashp);
2939 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2942 #ifdef NFS4_ACL_EXTATTR_NAME
2945 free(stp, M_NFSDSTATE);
2946 nfsvno_relpathbuf(&named);
2947 NFSEXITCODE2(error, nd);
2950 if (!nd->nd_repstat) {
2951 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2955 nfsvno_relpathbuf(&named);
2957 if (create == NFSV4OPEN_CREATE) {
2959 case NFSCREATE_UNCHECKED:
2962 * Clear the setable attribute bits, except
2963 * for Size, if it is being truncated.
2965 NFSZERO_ATTRBIT(&attrbits);
2966 if (NFSVNO_ISSETSIZE(&nva))
2967 NFSSETBIT_ATTRBIT(&attrbits,
2971 case NFSCREATE_GUARDED:
2972 if (named.ni_vp && !nd->nd_repstat)
2973 nd->nd_repstat = EEXIST;
2975 case NFSCREATE_EXCLUSIVE:
2980 case NFSCREATE_EXCLUSIVE41:
2985 nfsvno_open(nd, &named, clientid, &stateid, stp,
2986 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2987 nd->nd_cred, p, exp, &vp);
2988 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2989 NFSV4OPEN_CLAIMFH) {
2990 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2991 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2992 i = fxdr_unsigned(int, *tl);
2994 case NFSV4OPEN_DELEGATEREAD:
2995 stp->ls_flags |= NFSLCK_DELEGREAD;
2997 case NFSV4OPEN_DELEGATEWRITE:
2998 stp->ls_flags |= NFSLCK_DELEGWRITE;
2999 case NFSV4OPEN_DELEGATENONE:
3002 nd->nd_repstat = NFSERR_BADXDR;
3005 stp->ls_flags |= NFSLCK_RECLAIM;
3008 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3009 nd->nd_repstat = NFSERR_INVAL;
3012 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3013 if ((vp->v_iflag & VI_DOOMED) == 0)
3014 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3015 stp, vp, nd, p, nd->nd_repstat);
3017 nd->nd_repstat = NFSERR_PERM;
3019 nd->nd_repstat = NFSERR_BADXDR;
3024 * Do basic access checking.
3026 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3028 * The IETF working group decided that this is the correct
3029 * error return for all non-regular files.
3031 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3033 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3034 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3035 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3036 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3037 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3038 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3040 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3041 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
3042 NFSACCCHK_VPISLOCKED, NULL);
3045 if (!nd->nd_repstat) {
3046 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3047 if (!nd->nd_repstat) {
3048 tverf[0] = nva.na_atime.tv_sec;
3049 tverf[1] = nva.na_atime.tv_nsec;
3052 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3053 cverf[1] != tverf[1]))
3054 nd->nd_repstat = EEXIST;
3056 * Do the open locking/delegation stuff.
3058 if (!nd->nd_repstat)
3059 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3060 &delegstateid, &rflags, exp, p, nva.na_filerev);
3063 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3064 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3065 * (ie: Leave the NFSVOPUNLOCK() about here.)
3068 NFSVOPUNLOCK(vp, 0);
3070 free(stp, M_NFSDSTATE);
3071 if (!nd->nd_repstat && dirp)
3072 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3073 if (!nd->nd_repstat) {
3074 /* For NFSv4.1, set the Current StateID. */
3075 if ((nd->nd_flag & ND_NFSV41) != 0) {
3076 nd->nd_curstateid = stateid;
3077 nd->nd_flag |= ND_CURSTATEID;
3079 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3080 *tl++ = txdr_unsigned(stateid.seqid);
3081 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3082 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3083 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3084 *tl++ = newnfs_true;
3090 *tl++ = newnfs_false; /* Since dirp is not locked */
3091 txdr_hyper(dirfor.na_filerev, tl);
3093 txdr_hyper(diraft.na_filerev, tl);
3096 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3097 (void) nfsrv_putattrbit(nd, &attrbits);
3098 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3099 if (rflags & NFSV4OPEN_READDELEGATE)
3100 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3101 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3102 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3103 else if (retext != 0) {
3104 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3105 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3106 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3107 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3108 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3109 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3110 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3111 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3112 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3113 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3115 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3116 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3117 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3121 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3124 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3125 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3126 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3127 *tl++ = txdr_unsigned(delegstateid.seqid);
3128 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3130 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3131 if (rflags & NFSV4OPEN_RECALL)
3135 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3136 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3137 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3138 txdr_hyper(nva.na_size, tl);
3140 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3141 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3142 *tl++ = txdr_unsigned(0x0);
3143 acemask = NFSV4ACE_ALLFILESMASK;
3144 if (nva.na_mode & S_IRUSR)
3145 acemask |= NFSV4ACE_READMASK;
3146 if (nva.na_mode & S_IWUSR)
3147 acemask |= NFSV4ACE_WRITEMASK;
3148 if (nva.na_mode & S_IXUSR)
3149 acemask |= NFSV4ACE_EXECUTEMASK;
3150 *tl = txdr_unsigned(acemask);
3151 (void) nfsm_strtom(nd, "OWNER@", 6);
3159 #ifdef NFS4_ACL_EXTATTR_NAME
3162 NFSEXITCODE2(0, nd);
3166 #ifdef NFS4_ACL_EXTATTR_NAME
3170 free(stp, M_NFSDSTATE);
3171 NFSEXITCODE2(error, nd);
3176 * nfsv4 close service
3179 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3180 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3183 struct nfsstate st, *stp = &st;
3184 int error = 0, writeacc;
3185 nfsv4stateid_t stateid;
3189 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3190 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3191 stp->ls_ownerlen = 0;
3192 stp->ls_op = nd->nd_rp;
3193 stp->ls_uid = nd->nd_cred->cr_uid;
3194 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3195 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3199 * For the special stateid of other all 0s and seqid == 1, set the
3200 * stateid to the current stateid, if it is set.
3202 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3203 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3204 stp->ls_stateid.other[2] == 0) {
3205 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3206 stp->ls_stateid = nd->nd_curstateid;
3208 nd->nd_repstat = NFSERR_BADSTATEID;
3213 stp->ls_flags = NFSLCK_CLOSE;
3214 clientid.lval[0] = stp->ls_stateid.other[0];
3215 clientid.lval[1] = stp->ls_stateid.other[1];
3216 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3217 if ((nd->nd_flag & ND_NFSV41) != 0)
3218 clientid.qval = nd->nd_clientid.qval;
3219 else if (nd->nd_clientid.qval != clientid.qval)
3220 printf("EEK8 multiple clids\n");
3222 if ((nd->nd_flag & ND_NFSV41) != 0)
3223 printf("EEK! no clientid from session\n");
3224 nd->nd_flag |= ND_IMPLIEDCLID;
3225 nd->nd_clientid.qval = clientid.qval;
3227 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3229 /* For pNFS, update the attributes. */
3230 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3231 nfsrv_updatemdsattr(vp, &na, p);
3233 if (!nd->nd_repstat) {
3235 * If the stateid that has been closed is the current stateid,
3238 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3239 stateid.other[0] == nd->nd_curstateid.other[0] &&
3240 stateid.other[1] == nd->nd_curstateid.other[1] &&
3241 stateid.other[2] == nd->nd_curstateid.other[2])
3242 nd->nd_flag &= ~ND_CURSTATEID;
3243 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3244 *tl++ = txdr_unsigned(stateid.seqid);
3245 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3247 NFSEXITCODE2(0, nd);
3251 NFSEXITCODE2(error, nd);
3256 * nfsv4 delegpurge service
3259 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3260 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3266 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3267 nd->nd_repstat = NFSERR_WRONGSEC;
3270 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3271 clientid.lval[0] = *tl++;
3272 clientid.lval[1] = *tl;
3273 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3274 if ((nd->nd_flag & ND_NFSV41) != 0)
3275 clientid.qval = nd->nd_clientid.qval;
3276 else if (nd->nd_clientid.qval != clientid.qval)
3277 printf("EEK9 multiple clids\n");
3279 if ((nd->nd_flag & ND_NFSV41) != 0)
3280 printf("EEK! no clientid from session\n");
3281 nd->nd_flag |= ND_IMPLIEDCLID;
3282 nd->nd_clientid.qval = clientid.qval;
3284 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3285 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3287 NFSEXITCODE2(error, nd);
3292 * nfsv4 delegreturn service
3295 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3296 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3299 int error = 0, writeacc;
3300 nfsv4stateid_t stateid;
3304 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3305 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3306 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3307 clientid.lval[0] = stateid.other[0];
3308 clientid.lval[1] = stateid.other[1];
3309 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3310 if ((nd->nd_flag & ND_NFSV41) != 0)
3311 clientid.qval = nd->nd_clientid.qval;
3312 else if (nd->nd_clientid.qval != clientid.qval)
3313 printf("EEK10 multiple clids\n");
3315 if ((nd->nd_flag & ND_NFSV41) != 0)
3316 printf("EEK! no clientid from session\n");
3317 nd->nd_flag |= ND_IMPLIEDCLID;
3318 nd->nd_clientid.qval = clientid.qval;
3320 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3321 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3322 /* For pNFS, update the attributes. */
3323 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3324 nfsrv_updatemdsattr(vp, &na, p);
3327 NFSEXITCODE2(error, nd);
3332 * nfsv4 get file handle service
3335 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3336 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3340 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3342 if (!nd->nd_repstat)
3343 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3344 NFSEXITCODE2(0, nd);
3349 * nfsv4 open confirm service
3352 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3353 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3356 struct nfsstate st, *stp = &st;
3358 nfsv4stateid_t stateid;
3361 if ((nd->nd_flag & ND_NFSV41) != 0) {
3362 nd->nd_repstat = NFSERR_NOTSUPP;
3365 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3366 stp->ls_ownerlen = 0;
3367 stp->ls_op = nd->nd_rp;
3368 stp->ls_uid = nd->nd_cred->cr_uid;
3369 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3370 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3372 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3373 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3374 stp->ls_flags = NFSLCK_CONFIRM;
3375 clientid.lval[0] = stp->ls_stateid.other[0];
3376 clientid.lval[1] = stp->ls_stateid.other[1];
3377 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3378 if ((nd->nd_flag & ND_NFSV41) != 0)
3379 clientid.qval = nd->nd_clientid.qval;
3380 else if (nd->nd_clientid.qval != clientid.qval)
3381 printf("EEK11 multiple clids\n");
3383 if ((nd->nd_flag & ND_NFSV41) != 0)
3384 printf("EEK! no clientid from session\n");
3385 nd->nd_flag |= ND_IMPLIEDCLID;
3386 nd->nd_clientid.qval = clientid.qval;
3388 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3390 if (!nd->nd_repstat) {
3391 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3392 *tl++ = txdr_unsigned(stateid.seqid);
3393 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3397 NFSEXITCODE2(error, nd);
3402 * nfsv4 open downgrade service
3405 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3406 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3410 struct nfsstate st, *stp = &st;
3412 nfsv4stateid_t stateid;
3415 /* opendowngrade can only work on a file object.*/
3416 if (vp->v_type != VREG) {
3417 error = NFSERR_INVAL;
3420 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3421 stp->ls_ownerlen = 0;
3422 stp->ls_op = nd->nd_rp;
3423 stp->ls_uid = nd->nd_cred->cr_uid;
3424 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3425 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3427 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3430 * For the special stateid of other all 0s and seqid == 1, set the
3431 * stateid to the current stateid, if it is set.
3433 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3434 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3435 stp->ls_stateid.other[2] == 0) {
3436 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3437 stp->ls_stateid = nd->nd_curstateid;
3439 nd->nd_repstat = NFSERR_BADSTATEID;
3444 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3445 i = fxdr_unsigned(int, *tl++);
3446 if ((nd->nd_flag & ND_NFSV41) != 0)
3447 i &= ~NFSV4OPEN_WANTDELEGMASK;
3449 case NFSV4OPEN_ACCESSREAD:
3450 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3452 case NFSV4OPEN_ACCESSWRITE:
3453 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3455 case NFSV4OPEN_ACCESSBOTH:
3456 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3460 nd->nd_repstat = NFSERR_INVAL;
3462 i = fxdr_unsigned(int, *tl);
3464 case NFSV4OPEN_DENYNONE:
3466 case NFSV4OPEN_DENYREAD:
3467 stp->ls_flags |= NFSLCK_READDENY;
3469 case NFSV4OPEN_DENYWRITE:
3470 stp->ls_flags |= NFSLCK_WRITEDENY;
3472 case NFSV4OPEN_DENYBOTH:
3473 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3476 nd->nd_repstat = NFSERR_INVAL;
3479 clientid.lval[0] = stp->ls_stateid.other[0];
3480 clientid.lval[1] = stp->ls_stateid.other[1];
3481 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3482 if ((nd->nd_flag & ND_NFSV41) != 0)
3483 clientid.qval = nd->nd_clientid.qval;
3484 else if (nd->nd_clientid.qval != clientid.qval)
3485 printf("EEK12 multiple clids\n");
3487 if ((nd->nd_flag & ND_NFSV41) != 0)
3488 printf("EEK! no clientid from session\n");
3489 nd->nd_flag |= ND_IMPLIEDCLID;
3490 nd->nd_clientid.qval = clientid.qval;
3492 if (!nd->nd_repstat)
3493 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3495 if (!nd->nd_repstat) {
3496 /* For NFSv4.1, set the Current StateID. */
3497 if ((nd->nd_flag & ND_NFSV41) != 0) {
3498 nd->nd_curstateid = stateid;
3499 nd->nd_flag |= ND_CURSTATEID;
3501 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3502 *tl++ = txdr_unsigned(stateid.seqid);
3503 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3507 NFSEXITCODE2(error, nd);
3512 * nfsv4 renew lease service
3515 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3516 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3522 if ((nd->nd_flag & ND_NFSV41) != 0) {
3523 nd->nd_repstat = NFSERR_NOTSUPP;
3526 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3527 nd->nd_repstat = NFSERR_WRONGSEC;
3530 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3531 clientid.lval[0] = *tl++;
3532 clientid.lval[1] = *tl;
3533 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3534 if ((nd->nd_flag & ND_NFSV41) != 0)
3535 clientid.qval = nd->nd_clientid.qval;
3536 else if (nd->nd_clientid.qval != clientid.qval)
3537 printf("EEK13 multiple clids\n");
3539 if ((nd->nd_flag & ND_NFSV41) != 0)
3540 printf("EEK! no clientid from session\n");
3541 nd->nd_flag |= ND_IMPLIEDCLID;
3542 nd->nd_clientid.qval = clientid.qval;
3544 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3545 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3547 NFSEXITCODE2(error, nd);
3552 * nfsv4 security info service
3555 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3556 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3560 struct nameidata named;
3561 vnode_t dirp = NULL, vp;
3563 struct nfsexstuff retnes;
3565 int error = 0, savflag, i;
3570 * All this just to get the export flags for the name.
3572 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3573 LOCKLEAF | SAVESTART);
3574 nfsvno_setpathbuf(&named, &bufp, &hashp);
3575 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3578 nfsvno_relpathbuf(&named);
3581 if (!nd->nd_repstat) {
3582 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3585 nfsvno_relpathbuf(&named);
3591 vrele(named.ni_startdir);
3592 nfsvno_relpathbuf(&named);
3593 fh.nfsrvfh_len = NFSX_MYFH;
3595 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3597 savflag = nd->nd_flag;
3598 if (!nd->nd_repstat) {
3599 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3603 nd->nd_flag = savflag;
3608 * Finally have the export flags for name, so we can create
3609 * the security info.
3612 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3613 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3614 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3615 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3616 *tl = txdr_unsigned(RPCAUTH_UNIX);
3618 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3619 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3620 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3621 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3622 nfsgss_mechlist[KERBV_MECH].len);
3623 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3624 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3625 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3627 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3628 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3629 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3630 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3631 nfsgss_mechlist[KERBV_MECH].len);
3632 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3633 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3634 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3636 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3637 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3638 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3639 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3640 nfsgss_mechlist[KERBV_MECH].len);
3641 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3642 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3643 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3647 *sizp = txdr_unsigned(len);
3650 NFSEXITCODE2(error, nd);
3655 * nfsv4 set client id service
3658 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3659 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3663 int error = 0, idlen;
3664 struct nfsclient *clp = NULL;
3666 struct sockaddr_in *rin;
3669 struct sockaddr_in6 *rin6;
3671 #if defined(INET) || defined(INET6)
3674 u_char *verf, *addrbuf;
3675 nfsquad_t clientid, confirm;
3677 if ((nd->nd_flag & ND_NFSV41) != 0) {
3678 nd->nd_repstat = NFSERR_NOTSUPP;
3681 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3682 nd->nd_repstat = NFSERR_WRONGSEC;
3685 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3686 verf = (u_char *)tl;
3687 tl += (NFSX_VERF / NFSX_UNSIGNED);
3688 i = fxdr_unsigned(int, *tl);
3689 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3690 nd->nd_repstat = NFSERR_BADXDR;
3694 if (nd->nd_flag & ND_GSS)
3695 i += nd->nd_princlen;
3696 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3698 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3699 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3700 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3701 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3702 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3704 clp->lc_req.nr_cred = NULL;
3705 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3706 clp->lc_idlen = idlen;
3707 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3710 if (nd->nd_flag & ND_GSS) {
3711 clp->lc_flags = LCL_GSS;
3712 if (nd->nd_flag & ND_GSSINTEGRITY)
3713 clp->lc_flags |= LCL_GSSINTEGRITY;
3714 else if (nd->nd_flag & ND_GSSPRIVACY)
3715 clp->lc_flags |= LCL_GSSPRIVACY;
3719 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3720 clp->lc_flags |= LCL_NAME;
3721 clp->lc_namelen = nd->nd_princlen;
3722 clp->lc_name = &clp->lc_id[idlen];
3723 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3725 clp->lc_uid = nd->nd_cred->cr_uid;
3726 clp->lc_gid = nd->nd_cred->cr_gid;
3728 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3729 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3730 error = nfsrv_getclientipaddr(nd, clp);
3733 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3734 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3737 * nfsrv_setclient() does the actual work of adding it to the
3738 * client list. If there is no error, the structure has been
3739 * linked into the client list and clp should no longer be used
3740 * here. When an error is returned, it has not been linked in,
3741 * so it should be free'd.
3743 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3744 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3746 * 8 is the maximum length of the port# string.
3748 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3749 switch (clp->lc_req.nr_nam->sa_family) {
3752 if (clp->lc_flags & LCL_TCPCALLBACK)
3753 (void) nfsm_strtom(nd, "tcp", 3);
3755 (void) nfsm_strtom(nd, "udp", 3);
3756 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3757 ucp = (u_char *)&rin->sin_addr.s_addr;
3758 ucp2 = (u_char *)&rin->sin_port;
3759 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3760 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3761 ucp2[0] & 0xff, ucp2[1] & 0xff);
3766 if (clp->lc_flags & LCL_TCPCALLBACK)
3767 (void) nfsm_strtom(nd, "tcp6", 4);
3769 (void) nfsm_strtom(nd, "udp6", 4);
3770 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3771 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3777 ucp2 = (u_char *)&rin6->sin6_port;
3778 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3783 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3784 free(addrbuf, M_TEMP);
3787 free(clp->lc_req.nr_nam, M_SONAME);
3788 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3789 free(clp->lc_stateid, M_NFSDCLIENT);
3790 free(clp, M_NFSDCLIENT);
3792 if (!nd->nd_repstat) {
3793 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3794 *tl++ = clientid.lval[0];
3795 *tl++ = clientid.lval[1];
3796 *tl++ = confirm.lval[0];
3797 *tl = confirm.lval[1];
3801 NFSEXITCODE2(0, nd);
3805 free(clp->lc_req.nr_nam, M_SONAME);
3806 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3807 free(clp->lc_stateid, M_NFSDCLIENT);
3808 free(clp, M_NFSDCLIENT);
3810 NFSEXITCODE2(error, nd);
3815 * nfsv4 set client id confirm service
3818 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3819 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3820 __unused struct nfsexstuff *exp)
3824 nfsquad_t clientid, confirm;
3826 if ((nd->nd_flag & ND_NFSV41) != 0) {
3827 nd->nd_repstat = NFSERR_NOTSUPP;
3830 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3831 nd->nd_repstat = NFSERR_WRONGSEC;
3834 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3835 clientid.lval[0] = *tl++;
3836 clientid.lval[1] = *tl++;
3837 confirm.lval[0] = *tl++;
3838 confirm.lval[1] = *tl;
3841 * nfsrv_getclient() searches the client list for a match and
3842 * returns the appropriate NFSERR status.
3844 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3845 NULL, NULL, confirm, 0, nd, p);
3847 NFSEXITCODE2(error, nd);
3852 * nfsv4 verify service
3855 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3856 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3858 int error = 0, ret, fhsize = NFSX_MYFH;
3859 struct nfsvattr nva;
3861 struct nfsfsinfo fs;
3864 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3865 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3866 if (!nd->nd_repstat)
3867 nd->nd_repstat = nfsvno_statfs(vp, sf);
3868 if (!nd->nd_repstat)
3869 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3870 if (!nd->nd_repstat) {
3871 nfsvno_getfs(&fs, isdgram);
3872 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3873 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3875 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3877 nd->nd_repstat = NFSERR_SAME;
3878 else if (ret != NFSERR_NOTSAME)
3879 nd->nd_repstat = ret;
3881 nd->nd_repstat = ret;
3886 NFSEXITCODE2(error, nd);
3894 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3895 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3896 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3899 int error = 0, createdir __unused;
3901 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3902 createdir = fxdr_unsigned(int, *tl);
3903 nd->nd_repstat = NFSERR_NOTSUPP;
3906 NFSEXITCODE2(error, nd);
3911 * nfsv4 release lock owner service
3914 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3915 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3918 struct nfsstate *stp = NULL;
3922 if ((nd->nd_flag & ND_NFSV41) != 0) {
3923 nd->nd_repstat = NFSERR_NOTSUPP;
3926 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3927 nd->nd_repstat = NFSERR_WRONGSEC;
3930 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3931 len = fxdr_unsigned(int, *(tl + 2));
3932 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3933 nd->nd_repstat = NFSERR_BADXDR;
3936 stp = malloc(sizeof (struct nfsstate) + len,
3937 M_NFSDSTATE, M_WAITOK);
3938 stp->ls_ownerlen = len;
3940 stp->ls_flags = NFSLCK_RELEASE;
3941 stp->ls_uid = nd->nd_cred->cr_uid;
3942 clientid.lval[0] = *tl++;
3943 clientid.lval[1] = *tl;
3944 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3945 if ((nd->nd_flag & ND_NFSV41) != 0)
3946 clientid.qval = nd->nd_clientid.qval;
3947 else if (nd->nd_clientid.qval != clientid.qval)
3948 printf("EEK14 multiple clids\n");
3950 if ((nd->nd_flag & ND_NFSV41) != 0)
3951 printf("EEK! no clientid from session\n");
3952 nd->nd_flag |= ND_IMPLIEDCLID;
3953 nd->nd_clientid.qval = clientid.qval;
3955 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3958 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3959 free(stp, M_NFSDSTATE);
3961 NFSEXITCODE2(0, nd);
3965 free(stp, M_NFSDSTATE);
3966 NFSEXITCODE2(error, nd);
3971 * nfsv4 exchange_id service
3974 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3975 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3978 int error = 0, i, idlen;
3979 struct nfsclient *clp = NULL;
3980 nfsquad_t clientid, confirm;
3982 uint32_t sp4type, v41flags;
3983 uint64_t owner_minor;
3984 struct timespec verstime;
3986 struct sockaddr_in *sin, *rin;
3989 struct sockaddr_in6 *sin6, *rin6;
3992 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3993 nd->nd_repstat = NFSERR_WRONGSEC;
3996 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3997 verf = (uint8_t *)tl;
3998 tl += (NFSX_VERF / NFSX_UNSIGNED);
3999 i = fxdr_unsigned(int, *tl);
4000 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4001 nd->nd_repstat = NFSERR_BADXDR;
4005 if (nd->nd_flag & ND_GSS)
4006 i += nd->nd_princlen;
4007 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4009 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4010 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4011 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4012 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4013 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4015 switch (nd->nd_nam->sa_family) {
4018 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4019 sin = (struct sockaddr_in *)nd->nd_nam;
4020 rin->sin_family = AF_INET;
4021 rin->sin_len = sizeof(struct sockaddr_in);
4023 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4028 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4029 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4030 rin6->sin6_family = AF_INET6;
4031 rin6->sin6_len = sizeof(struct sockaddr_in6);
4032 rin6->sin6_port = 0;
4033 rin6->sin6_addr = sin6->sin6_addr;
4037 clp->lc_req.nr_cred = NULL;
4038 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4039 clp->lc_idlen = idlen;
4040 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4043 if ((nd->nd_flag & ND_GSS) != 0) {
4044 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4045 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4046 clp->lc_flags |= LCL_GSSINTEGRITY;
4047 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4048 clp->lc_flags |= LCL_GSSPRIVACY;
4050 clp->lc_flags = LCL_NFSV41;
4051 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4052 clp->lc_flags |= LCL_NAME;
4053 clp->lc_namelen = nd->nd_princlen;
4054 clp->lc_name = &clp->lc_id[idlen];
4055 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4057 clp->lc_uid = nd->nd_cred->cr_uid;
4058 clp->lc_gid = nd->nd_cred->cr_gid;
4060 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4061 v41flags = fxdr_unsigned(uint32_t, *tl++);
4062 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4063 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4064 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4065 nd->nd_repstat = NFSERR_INVAL;
4068 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4069 confirm.lval[1] = 1;
4071 confirm.lval[1] = 0;
4072 if (nfsrv_devidcnt == 0)
4073 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4075 v41flags = NFSV4EXCH_USEPNFSMDS;
4076 sp4type = fxdr_unsigned(uint32_t, *tl);
4077 if (sp4type != NFSV4EXCH_SP4NONE) {
4078 nd->nd_repstat = NFSERR_NOTSUPP;
4083 * nfsrv_setclient() does the actual work of adding it to the
4084 * client list. If there is no error, the structure has been
4085 * linked into the client list and clp should no longer be used
4086 * here. When an error is returned, it has not been linked in,
4087 * so it should be free'd.
4089 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4091 free(clp->lc_req.nr_nam, M_SONAME);
4092 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4093 free(clp->lc_stateid, M_NFSDCLIENT);
4094 free(clp, M_NFSDCLIENT);
4096 if (nd->nd_repstat == 0) {
4097 if (confirm.lval[1] != 0)
4098 v41flags |= NFSV4EXCH_CONFIRMEDR;
4099 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4100 *tl++ = clientid.lval[0]; /* ClientID */
4101 *tl++ = clientid.lval[1];
4102 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4103 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4104 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
4105 owner_minor = 0; /* Owner */
4106 txdr_hyper(owner_minor, tl); /* Minor */
4107 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4108 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4109 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4110 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4111 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4112 *tl = txdr_unsigned(1);
4113 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4114 (void)nfsm_strtom(nd, version, strlen(version));
4115 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4116 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4117 verstime.tv_nsec = 0;
4118 txdr_nfsv4time(&verstime, tl);
4120 NFSEXITCODE2(0, nd);
4124 free(clp->lc_req.nr_nam, M_SONAME);
4125 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4126 free(clp->lc_stateid, M_NFSDCLIENT);
4127 free(clp, M_NFSDCLIENT);
4129 NFSEXITCODE2(error, nd);
4134 * nfsv4 create session service
4137 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4138 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4142 nfsquad_t clientid, confirm;
4143 struct nfsdsession *sep = NULL;
4146 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4147 nd->nd_repstat = NFSERR_WRONGSEC;
4150 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4151 M_NFSDSESSION, M_WAITOK | M_ZERO);
4152 sep->sess_refcnt = 1;
4153 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4154 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4155 clientid.lval[0] = *tl++;
4156 clientid.lval[1] = *tl++;
4157 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4158 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4159 /* Persistent sessions and RDMA are not supported. */
4160 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4162 /* Fore channel attributes. */
4163 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4164 tl++; /* Header pad always 0. */
4165 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4166 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4167 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4168 printf("Consider increasing kern.ipc.maxsockbuf\n");
4170 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4171 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4172 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4173 printf("Consider increasing kern.ipc.maxsockbuf\n");
4175 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4176 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4177 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4178 if (sep->sess_maxslots > NFSV4_SLOTS)
4179 sep->sess_maxslots = NFSV4_SLOTS;
4180 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4182 nd->nd_repstat = NFSERR_BADXDR;
4184 } else if (rdmacnt == 1)
4185 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4187 /* Back channel attributes. */
4188 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4189 tl++; /* Header pad always 0. */
4190 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4191 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4192 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4193 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4194 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4195 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4197 nd->nd_repstat = NFSERR_BADXDR;
4199 } else if (rdmacnt == 1)
4200 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4202 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4203 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4206 * nfsrv_getclient() searches the client list for a match and
4207 * returns the appropriate NFSERR status.
4209 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4210 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4211 if (nd->nd_repstat == 0) {
4212 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4213 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4214 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4215 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4216 *tl++ = txdr_unsigned(sep->sess_crflags);
4218 /* Fore channel attributes. */
4220 *tl++ = txdr_unsigned(sep->sess_maxreq);
4221 *tl++ = txdr_unsigned(sep->sess_maxresp);
4222 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4223 *tl++ = txdr_unsigned(sep->sess_maxops);
4224 *tl++ = txdr_unsigned(sep->sess_maxslots);
4225 *tl++ = txdr_unsigned(1);
4226 *tl++ = txdr_unsigned(0); /* No RDMA. */
4228 /* Back channel attributes. */
4230 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4231 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4232 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4233 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4234 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4235 *tl++ = txdr_unsigned(1);
4236 *tl = txdr_unsigned(0); /* No RDMA. */
4239 if (nd->nd_repstat != 0 && sep != NULL)
4240 free(sep, M_NFSDSESSION);
4241 NFSEXITCODE2(error, nd);
4246 * nfsv4 sequence service
4249 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4250 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4253 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4254 int cache_this, error = 0;
4256 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4257 nd->nd_repstat = NFSERR_WRONGSEC;
4260 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4261 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4262 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4263 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4264 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4265 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4266 if (*tl == newnfs_true)
4270 nd->nd_flag |= ND_HASSEQUENCE;
4271 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4272 &target_highest_slotid, cache_this, &sflags, p);
4273 if (nd->nd_repstat == 0) {
4274 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4275 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4276 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4277 *tl++ = txdr_unsigned(sequenceid);
4278 *tl++ = txdr_unsigned(nd->nd_slotid);
4279 *tl++ = txdr_unsigned(highest_slotid);
4280 *tl++ = txdr_unsigned(target_highest_slotid);
4281 *tl = txdr_unsigned(sflags);
4284 NFSEXITCODE2(error, nd);
4289 * nfsv4 reclaim complete service
4292 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4293 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4296 int error = 0, onefs;
4298 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4299 nd->nd_repstat = NFSERR_WRONGSEC;
4302 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4304 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4305 * to be used after a file system has been transferred to a different
4306 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4307 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4308 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4309 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4310 * NFS_OK without doing anything.
4313 if (*tl == newnfs_true)
4315 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4317 NFSEXITCODE2(error, nd);
4322 * nfsv4 destroy clientid service
4325 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4326 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4332 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4333 nd->nd_repstat = NFSERR_WRONGSEC;
4336 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4337 clientid.lval[0] = *tl++;
4338 clientid.lval[1] = *tl;
4339 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4341 NFSEXITCODE2(error, nd);
4346 * nfsv4 bind connection to session service
4349 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4350 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4353 uint8_t sessid[NFSX_V4SESSIONID];
4354 int error = 0, foreaft;
4356 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4357 nd->nd_repstat = NFSERR_WRONGSEC;
4360 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4361 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4362 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4363 foreaft = fxdr_unsigned(int, *tl++);
4364 if (*tl == newnfs_true) {
4365 /* RDMA is not supported. */
4366 nd->nd_repstat = NFSERR_NOTSUPP;
4370 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4371 if (nd->nd_repstat == 0) {
4372 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4374 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4375 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4376 *tl++ = txdr_unsigned(foreaft);
4380 NFSEXITCODE2(error, nd);
4385 * nfsv4 destroy session service
4388 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4389 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4391 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4394 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4395 nd->nd_repstat = NFSERR_WRONGSEC;
4398 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4399 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4400 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4402 NFSEXITCODE2(error, nd);
4407 * nfsv4 free stateid service
4410 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4411 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4414 nfsv4stateid_t stateid;
4417 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4418 nd->nd_repstat = NFSERR_WRONGSEC;
4421 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4422 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4423 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4426 * For the special stateid of other all 0s and seqid == 1, set the
4427 * stateid to the current stateid, if it is set.
4429 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4430 stateid.other[1] == 0 && stateid.other[2] == 0) {
4431 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4432 stateid = nd->nd_curstateid;
4435 nd->nd_repstat = NFSERR_BADSTATEID;
4440 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4442 /* If the current stateid has been free'd, unset it. */
4443 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4444 stateid.other[0] == nd->nd_curstateid.other[0] &&
4445 stateid.other[1] == nd->nd_curstateid.other[1] &&
4446 stateid.other[2] == nd->nd_curstateid.other[2])
4447 nd->nd_flag &= ~ND_CURSTATEID;
4449 NFSEXITCODE2(error, nd);
4454 * nfsv4 layoutget service
4457 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4458 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
4461 nfsv4stateid_t stateid;
4462 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4463 uint64_t offset, len, minlen;
4466 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4467 nd->nd_repstat = NFSERR_WRONGSEC;
4470 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4472 tl++; /* Signal layout available. Ignore for now. */
4473 layouttype = fxdr_unsigned(int, *tl++);
4474 iomode = fxdr_unsigned(int, *tl++);
4475 offset = fxdr_hyper(tl); tl += 2;
4476 len = fxdr_hyper(tl); tl += 2;
4477 minlen = fxdr_hyper(tl); tl += 2;
4478 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4479 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4480 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4481 maxcnt = fxdr_unsigned(int, *tl);
4482 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4483 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4486 (minlen != UINT64_MAX && offset + minlen < offset) ||
4487 (len != UINT64_MAX && offset + len < offset)) {
4488 nd->nd_repstat = NFSERR_INVAL;
4493 * For the special stateid of other all 0s and seqid == 1, set the
4494 * stateid to the current stateid, if it is set.
4496 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4497 stateid.other[1] == 0 && stateid.other[2] == 0) {
4498 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4499 stateid = nd->nd_curstateid;
4502 nd->nd_repstat = NFSERR_BADSTATEID;
4508 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4509 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4510 else if (layouttype == NFSLAYOUT_FLEXFILE)
4511 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4514 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4516 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4517 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4518 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4519 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4521 if (nd->nd_repstat == 0) {
4522 /* For NFSv4.1, set the Current StateID. */
4523 if ((nd->nd_flag & ND_NFSV41) != 0) {
4524 nd->nd_curstateid = stateid;
4525 nd->nd_flag |= ND_CURSTATEID;
4527 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4529 *tl++ = txdr_unsigned(retonclose);
4530 *tl++ = txdr_unsigned(stateid.seqid);
4531 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4532 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4533 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4534 txdr_hyper(offset, tl); tl += 2;
4535 txdr_hyper(len, tl); tl += 2;
4536 *tl++ = txdr_unsigned(iomode);
4537 *tl = txdr_unsigned(layouttype);
4538 nfsm_strtom(nd, layp, layoutlen);
4539 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4540 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4546 NFSEXITCODE2(error, nd);
4551 * nfsv4 layoutcommit service
4554 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4555 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
4558 nfsv4stateid_t stateid;
4559 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4561 uint64_t offset, len, newoff, newsize;
4562 struct timespec newmtime;
4566 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4567 nd->nd_repstat = NFSERR_WRONGSEC;
4570 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4572 offset = fxdr_hyper(tl); tl += 2;
4573 len = fxdr_hyper(tl); tl += 2;
4574 reclaim = fxdr_unsigned(int, *tl++);
4575 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4576 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4577 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4579 * For the special stateid of other all 0s and seqid == 1, set the
4580 * stateid to the current stateid, if it is set.
4582 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4583 stateid.other[1] == 0 && stateid.other[2] == 0) {
4584 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4585 stateid = nd->nd_curstateid;
4588 nd->nd_repstat = NFSERR_BADSTATEID;
4593 hasnewoff = fxdr_unsigned(int, *tl);
4594 if (hasnewoff != 0) {
4595 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4596 newoff = fxdr_hyper(tl); tl += 2;
4598 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4599 hasnewmtime = fxdr_unsigned(int, *tl);
4600 if (hasnewmtime != 0) {
4601 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4602 fxdr_nfsv4time(tl, &newmtime);
4603 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4605 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4606 layouttype = fxdr_unsigned(int, *tl++);
4607 maxcnt = fxdr_unsigned(int, *tl);
4609 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4610 error = nfsrv_mtostr(nd, layp, maxcnt);
4614 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4615 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4616 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4617 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4618 if (nd->nd_repstat == 0) {
4619 if (hasnewsize != 0) {
4620 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4621 *tl++ = newnfs_true;
4622 txdr_hyper(newsize, tl);
4624 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4631 NFSEXITCODE2(error, nd);
4636 * nfsv4 layoutreturn service
4639 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4640 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
4642 uint32_t *tl, *layp;
4643 nfsv4stateid_t stateid;
4644 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4645 uint64_t offset, len;
4648 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4649 nd->nd_repstat = NFSERR_WRONGSEC;
4652 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4654 layouttype = fxdr_unsigned(int, *tl++);
4655 iomode = fxdr_unsigned(int, *tl++);
4656 kind = fxdr_unsigned(int, *tl);
4657 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4658 layouttype, iomode, kind);
4659 if (kind == NFSV4LAYOUTRET_FILE) {
4660 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4662 offset = fxdr_hyper(tl); tl += 2;
4663 len = fxdr_hyper(tl); tl += 2;
4664 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4665 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4666 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4669 * For the special stateid of other all 0s and seqid == 1, set
4670 * the stateid to the current stateid, if it is set.
4672 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4673 stateid.other[1] == 0 && stateid.other[2] == 0) {
4674 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4675 stateid = nd->nd_curstateid;
4678 nd->nd_repstat = NFSERR_BADSTATEID;
4683 maxcnt = fxdr_unsigned(int, *tl);
4685 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4686 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4691 if (reclaim == newnfs_true) {
4692 nd->nd_repstat = NFSERR_INVAL;
4698 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4699 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4701 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4703 if (nd->nd_repstat == 0) {
4704 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4707 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4708 *tl++ = txdr_unsigned(stateid.seqid);
4709 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4716 NFSEXITCODE2(error, nd);
4721 * nfsv4 getdeviceinfo service
4724 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
4725 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4727 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
4728 int cnt, devaddrlen, error = 0, i, layouttype;
4729 char devid[NFSX_V4DEVICEID], *devaddr;
4732 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4733 nd->nd_repstat = NFSERR_WRONGSEC;
4736 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4737 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4738 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4739 layouttype = fxdr_unsigned(int, *tl++);
4740 maxcnt = fxdr_unsigned(uint32_t, *tl++);
4741 cnt = fxdr_unsigned(int, *tl);
4742 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
4744 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
4745 nd->nd_repstat = NFSERR_INVAL;
4749 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
4750 for (i = 0; i < cnt; i++)
4751 notify[i] = fxdr_unsigned(uint32_t, *tl++);
4753 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
4757 * Check that the device id is not stale. Device ids are recreated
4758 * each time the nfsd threads are restarted.
4760 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
4761 if (dev_time != nfsdev_time) {
4762 nd->nd_repstat = NFSERR_NOENT;
4766 /* Look for the device id. */
4767 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
4768 notify, &devaddrlen, &devaddr);
4769 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
4770 if (nd->nd_repstat == 0) {
4771 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4772 *tl = txdr_unsigned(layouttype);
4773 nfsm_strtom(nd, devaddr, devaddrlen);
4775 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
4779 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
4780 *tl++ = txdr_unsigned(cnt);
4781 for (i = 0; i < cnt; i++)
4782 *tl++ = txdr_unsigned(notify[i]);
4783 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
4784 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4785 *tl = txdr_unsigned(maxcnt);
4788 NFSEXITCODE2(error, nd);
4793 * nfsv4 test stateid service
4796 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
4797 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4800 nfsv4stateid_t *stateidp = NULL, *tstateidp;
4801 int cnt, error = 0, i, ret;
4803 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4804 nd->nd_repstat = NFSERR_WRONGSEC;
4807 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4808 cnt = fxdr_unsigned(int, *tl);
4809 if (cnt <= 0 || cnt > 1024) {
4810 nd->nd_repstat = NFSERR_BADXDR;
4813 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
4814 tstateidp = stateidp;
4815 for (i = 0; i < cnt; i++) {
4816 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4817 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
4818 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
4821 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4822 *tl = txdr_unsigned(cnt);
4823 tstateidp = stateidp;
4824 for (i = 0; i < cnt; i++) {
4825 ret = nfsrv_teststateid(nd, tstateidp, p);
4826 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4827 *tl = txdr_unsigned(ret);
4831 free(stateidp, M_TEMP);
4832 NFSEXITCODE2(error, nd);
4837 * nfsv4 service not supported
4840 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4841 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4844 nd->nd_repstat = NFSERR_NOTSUPP;
4845 NFSEXITCODE2(0, nd);